2014 dxdy logo

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

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




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3
 
 
Сообщение17.12.2005, 03:30 
Заслуженный участник
Аватара пользователя


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

 Профиль  
                  
 
 
Сообщение25.12.2005, 22:12 


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

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 


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

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

Кроме того добавлен контроль на пустоту введенного имени файла
(см. функцию 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

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group