2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3
 
 
Сообщение17.12.2005, 03:30 
Аватара пользователя
:evil:
Я все-таки не понимаю - у Вас массивы ограничены (100, 200, причем даже не 100L, 200L). Неужели 16 битных индексов не хватит? А коль уж так о переносимости заботиться, так надо вместо long использовать ptrdiff_t. Он гарантирован по стандарту быть переносимым - в отличии от int, long, или short. Подход MS гарантирует правильность программы путем конфигурации (некоторые еще и проверку правильности конфигурации в программу вставляют - что все типы имеют ожидаемый размер). Ваш подход ничего гарантировать не может. Но может привести к неожиданным ошибкам. И к неоправданному расходу памяти.

 
 
 
 
Сообщение25.12.2005, 22:12 
В ходе тестирования этой программы был обнаружен ещё один глюк:
при наличии файла с формулами взаимодействия веществ:

1 2 3
4 5 6
a b v
3 6 x

и файла с веществами:

1 2 4 5 7 a b

в процессе выполнении данной программы, создаётся файл с результатом взаимодействия
веществ:

3 6 7 v

т.е. программа не заменяет вещества 3 и 6 (которые были получены в результате взаимодействия веществ 1 и 2, 4 и 5 соответственно) на х (хотя взаимодействие этих веществ указано в формуле)!

Подскажите как исправить данный глюк.

 
 
 
 
Сообщение25.12.2005, 23:42 
Код:
Молодой человек! Сколько еще раз мы с вами будем "пулять по Луне"?
Вы же в условии не сказали, что результат взаимодействия последнего
вещества пробирки и очередного опытного вещества СНОВА должен
проверяться по формуле взаимодействия!

Эта ситуация учтена в тексте программы, обрамленная комментариями
//((((( и //)))))

Кроме того добавлен контроль на пустоту введенного имени файла
(см. функцию IsEmpty)

И если программирование будет хотя бы отчасти вашей будущей профессией,
запомните: в программировании четко поставленная задача есть 70 процентов
решения задачи...

#include <stdio.h>
#include <malloc.h>
#include <string.h>

struct formula
{
  char *n1;  // Первое вещество из пары взаимодействующих веществ
  char *n2;  // Второе вещество из пары взаимодействующих веществ
  char *n3;  // Результат их взаимодействия
};

#define MAX_FORMULA 200 // Максимальное число формул
#define MAX_PRIOR   100 // Максимальное число опытных веществ
#define MAX_LEN 512

// Список формул
struct formula prior_formula[MAX_FORMULA];

// Число формул
long  cnt_formula;

// Число опытных веществ
long  cnt_prior;

// Исходные вещества для опыта
char *prior[MAX_PRIOR];

// Вещества в результате опыта
char *result[MAX_PRIOR];

void stack_func
(
  struct formula  *para,    // Список формул взаимодействий веществ
  long            len_para, // Размер списка формул
  char            **src,    // Список веществ для опыта
  long            len_src,  // Размер списка веществ для опыта
  char            **out,    // Адрес результирующего списка веществ
                            //  после окончания опыта
  long            *len_out  // Размер списка веществ в результате опыта
)
{
  long  i, j, d1, d2;
  char  *n1, *n2;

  // Поместить в массив результата первое вещество
  out[0] = src[0];
  d1 = d2 = 0;

  // Просмотр всех остальных веществ
  for(i = 1; i < len_src; ++i)
  {
    n1 = out[d1];    // Последнее вещество из пробирки
    n2 = src[++d2];  // Очередное вещество для опыта

    // Поиск формулы взаимодействия этих веществ
    for(j = 0; j < len_para; ++j)
    {
      if(strcmp(n1, para[j].n1) == 0 && strcmp(n2, para[j].n2) == 0 ||
         strcmp(n2, para[j].n1) == 0 && strcmp(n1, para[j].n2) == 0)
        break;
    }

    // Если формулу взаимодействия нашли, заменить
    // последнее вещество из пробирки на результат взаимодействия
    if(j != len_para)
    {
      out[d1] = para[j].n3;

//(((((

      // Кроме того, результат взаимодействия может спровоцировать новое
      // взаимодействие, поэтому повторяем поиск формулы взаимодействия
      // для последних двух веществ

      while(d1)
      {
        n1 = out[d1 - 1]; // Предпоследнее вещество в пробирке
        n2 = out[d1];     // Последнее вещество в пробирке

        for(j = 0; j < len_para; ++j)
        {
          if(strcmp(n1, para[j].n1) == 0 && strcmp(n2, para[j].n2) == 0 ||
             strcmp(n2, para[j].n1) == 0 && strcmp(n1, para[j].n2) == 0)
            break;
        }
        if(j == len_para)
          break;
        out[--d1] = para[j].n3;
      }
//)))))
      continue;
    }

    // Формулу не нашли, последним веществом в пробирке будет
    // очередное выбранное вещество
    out[++d1] = n2;
  }

  *len_out = d1 + 1;
}

// Проверить на пустоту введенные имена файлов
int IsEmpty(char *s)
{
  char c, *s1, tmp[MAX_LEN];

  for(s1 = s; (c = *s) == ' ' || c == '\n' || c == '\t'; ++s)
    ;
  if(c == 0)
  {
    printf("Empty Name File\n");
    return(1);
  }

  // Переписать имя файла без начальных пробелов
  // Это можно было сделать проще (через memmove),
  // но я не хочу еще одной дискуссии по этому поводу
  strcpy(tmp, s);
  strcpy(s1, tmp);
  return(0);
}

int main(int argc, char **argv)
{
  long len, i, len1, len2, len3;
  FILE *f;
  char  feld[MAX_LEN + 1];
  char  c, *s, *s1, *s2, *s3;
  char  name_formula[MAX_LEN], name_prior[MAX_LEN], name_out[MAX_LEN];

  // Программа стартуется без параметров,
  // а имена файлов вводятся с консоли
  //
  // 1) имя файла с формулами взаимодействия
  // 2) имя файла с опытными веществами
  // 3) имя файла результата

  // Ввод данных о формулах взаимодействия веществ из файла,
  // структура которого предполагается следующей:
  //
  // Каждая строка файла представляет собой одну формулу взаимодействия
  // и состоит из трех слов, разделенных пробелами, например:
  //
  // свинец соляная_кислота супер_вещество
  //
  // Обратите внимание на то, что в названии веществ не должно быть
  // пробела, при необходимост последнего следует использовать символ
  // подчеркивания
  //
  // В приведенном выше примере предполагается, что если в пробирке
  // последнее вещество есть свинец, то при добавлении в пробирку
  // соляная_кислота с этим свинцом превращается в супер_вещество
  //
  // Конец файла означает конец формул взаимодействия

  // Запрос имен трех файлов с консоли
  // Не предполагается никаких проверок (переполнение и так далее)
  printf("Formula File? ");
  gets(name_formula);
  if(IsEmpty(name_formula))
    return(0);

  printf("Prior File?   ");
  gets(name_prior);
  if(IsEmpty(name_prior))
    return(0);

  printf("Result File?  ");
  gets(name_out);
  if(IsEmpty(name_out))
    return(0);

  // А есть ли файл с формулами?
  if((f = fopen(name_formula, "r")) == NULL)
  {
    printf("Not File (%s) Found\n", name_formula);
    return(0);
  }

  // Номер строки файла для выдачи ошибок
  i = 0;

  // Счетчик формул
  cnt_formula = 0;
 
  // Счетчик опытных веществ
  cnt_prior = 0;

  // Читаем символьный файл по записям до его конца
  while(fgets(feld, MAX_LEN, f))
  {
    ++i;

    // Сбрасываем пустые символы перед первым веществом
    for(s = feld; *s == ' ' || *s == '\t' || *s == '\n'; ++s)
      ;

    // Считаем, что если формула начинается с символа ';'
    // то это комментарийная строка
    // Комментарием будет также полностью пустая строка
    if(*s == ';' || *s == 0)
      continue;

    // Не слишком ли много формул задано?
    if(cnt_formula == MAX_FORMULA)
    {
      printf("Error Big Formula\n");
      goto error1;
    }

    // Отмечаем начало первого слова во введенной записи
    s1 = s;

    // Ищем конец первого слова
    while((c = *++s) != ' ' && c != '\t' && c != '\n' && c)
      ;

    // Записываем в конец первого слова символ конца строки
    *s = 0;

    // А есть ли еще слова после первого слова?
    if(c == 0)
    {

error:

      printf("Error Formula Line %d\n", i);

error1:

      fclose(f);

error2:

      // Освобождаем память
      for(i = 0; i < cnt_formula; ++i)
        free(prior_formula[i].n1);

      return(0);
    }

    // Сбрасываем пустые символы перед вторым веществом
    while((c = *++s) == ' ' || c == '\t' || c == '\n')
      ;

    // А есть ли второе вещество?
    if(c == 0)
      goto error;       

    // Отмечаем начало второго слова во введенной записи
    s2 = s;

    // Ищем конец второго слова
    while((c = *++s) != ' ' && c != '\t' && c != '\n' && c)
      ;

    // Записываем в конец второго слова символ конца строки
    *s = 0;

    // А есть ли еще слова после второго слова?
    if(c == 0)
      goto error;       

    // Сбрасываем пустые символы перед третьим веществом
    while((c = *++s) == ' ' || c == '\t' || c == '\n')
      ;

    // Отмечаем начало третьего слова во введенной записи
    s3 = s;

    // Ищем конец третьего слова
    while((c = *++s) != ' ' && c != '\t' && c != '\n' && c)
      ;

    // Записываем в конец третьего слова символ конца строки
    *s = 0;

    // После третьего слова до конца записи могут идти только
    // пустые символы
    if(c)
    {
      while((c = *++s) == ' ' || c == '\t' || c == '\n')
        ;
      if(c)
        goto error;
    }

    // Теперь можно выделить память под три слова и запомнить их там
    // Считаем, что память есть всегда, поэтому не применяем контроль
    len1 = strlen(s1) + 1;
    len2 = strlen(s2) + 1;
    len3 = strlen(s3) + 1;
    s = (char *)malloc(len1 + len2 + len3);
    prior_formula[cnt_formula].n1 = s;
    prior_formula[cnt_formula].n2 = s + len1;
    prior_formula[cnt_formula].n3 = s + len1 + len2;
    strcpy(prior_formula[cnt_formula].n1, s1);
    strcpy(prior_formula[cnt_formula].n2, s2);
    strcpy(prior_formula[cnt_formula].n3, s3);

    // Увеличиваем счетчик формул
    ++cnt_formula;
  }

  // А есть ли хотя бы одна формула?
  if(cnt_formula == 0)
  {
    printf("Error No Formula\n");
    goto error1;
  }

  // С формулами покончено, закрываем их файл
  fclose(f);

  // Ввод данных о веществах, участвующих в опыте
  // Считается, что они тоже заданы словами, разделенными пробелами,
  // но для упрощения программы будем их вводить при помощи fscanf,
  // а не заниматься разбором, как для формул

  // А есть ли файл с опытными веществами?
  if((f = fopen(name_prior, "r")) == NULL)
  {
    printf("Not File (%s) Found\n", name_prior);
    goto error2;
  }

  while(fscanf(f, "%s", feld) == 1)
  {
    if(cnt_prior == MAX_PRIOR)
    {
      printf("Error Big Prior\n");

      // Освобождаем память
      for(i = 0; i < cnt_prior; ++i)
        free(prior[i]);
      goto error1;
    }
    prior[cnt_prior] = (char *)malloc(strlen(feld) + 1);
    strcpy(prior[cnt_prior], feld);
    ++cnt_prior;
  }

  // А есть ли опытные вещества?
  if(cnt_prior == 0)
  {
    printf("Error No Prior\n");
    goto error1;
  }

  // А не слишком ли мало опытных веществ?
  if(cnt_prior < 2)
  {
    printf("Error 2 Prior\n");
    goto error1;
  }

  // С опытными веществами покончено, закрываем их файл
  fclose(f);

  stack_func(prior_formula, cnt_formula, prior, cnt_prior, result, &len);

  // Открыть файл печати результата
  f = fopen(name_out, "w");

  // Печать результата опыта
  for(i = 0; i < len; ++i)
  {
    fprintf(f, "%s ", result[i]);
    if(i + 1 % 5 == 0)
      fprintf(f, "\n");
  }
  fprintf(f, "\n");

  fclose(f);

  // Освободить память

  for(i = 0; i < cnt_formula; ++i)
    free(prior_formula[i].n1);

  for(i = 0; i < cnt_prior; ++i)
    free(prior[i]);

  return(0);
}


 
 
 [ Сообщений: 33 ]  На страницу Пред.  1, 2, 3


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group