Чтение файла символ за символом в C - PullRequest
27 голосов
/ 28 января 2011

Привет всем, я пишу BF-интерпретатор на C и столкнулся с проблемой чтения файлов.Раньше я использовал scanf для чтения первой строки, но тогда у вас не могло быть пробелов или комментариев в вашем коде BF.

Прямо сейчас вот что у меня есть.

char *readFile(char *fileName)
{
  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  {
    *code++ = (char)fgetc(file);

  } while(*code != EOF);
  return code;
}

Я знаю, что проблема возникает в том, как я назначаю следующий символ в файле указателю кода, но я просто не уверен, что это такое.
Мне не хватает знаний об указателях, что является целью этого упражнения.Интерпретатор работает нормально, все используют указатели, у меня просто проблема с чтением файлов в него.

(я собираюсь реализовать только чтение "+ -> <[].", В файлпозже, хотя, если у кого-то есть хороший способ сделать это, было бы здорово, если бы вы дали мне знать!) </p>

Заранее спасибо

Ответы [ 7 ]

35 голосов
/ 28 января 2011

В вашем коде есть ряд проблем:

char *readFile(char *fileName)
{
    FILE *file;
    char *code = malloc(1000 * sizeof(char));
    file = fopen(fileName, "r");
    do 
    {
      *code++ = (char)fgetc(file);

    } while(*code != EOF);
    return code;
}
  1. Что если размер файла превышает 1000 байт?
  2. Вы увеличиваете code каждый разВы читаете символ и возвращаете code обратно вызывающей стороне (даже если он больше не указывает на первый байт блока памяти, как он был возвращен malloc).
  3. Вы ведете кастрезультат от fgetc(file) до char.Вам нужно проверить EOF перед приведением результата к char.

Важно сохранить исходный указатель, возвращаемый malloc, чтобы вы могли его позже освободить.Если мы пренебрегаем размером файла, мы можем достичь этого, используя следующее:

char *readFile(char *fileName)
{
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL)
        return NULL; //could not open file

    code = malloc(1000);

    while ((c = fgetc(file)) != EOF)
    {
        code[n++] = (char) c;
    }

    // don't forget to terminate with the null character
    code[n] = '\0';        

    return code;
}

Существуют различные системные вызовы, которые сообщают вам размер файла;общий stat.

8 голосов
/ 30 марта 2013

Расширение на приведенный выше код из @ dreamlax

char *readFile(char *fileName) {
    FILE *file = fopen(fileName, "r");
    char *code;
    size_t n = 0;
    int c;

    if (file == NULL) return NULL; //could not open file
    fseek(file, 0, SEEK_END);
    long f_size = ftell(file);
    fseek(file, 0, SEEK_SET);
    code = malloc(f_size);

    while ((c = fgetc(file)) != EOF) {
        code[n++] = (char)c;
    }

    code[n] = '\0';        

    return code;
}

Это дает вам длину файла, а затем приступает к чтению его символ за символом.

2 голосов
/ 31 января 2011

файл открывается и не закрывается для каждого вызова функции также

2 голосов
/ 28 января 2011

Вот один простой способ игнорировать все, кроме действительных персонажей-мозговитцев:

#define BF_VALID "+-><[].,"

if (strchr(BF_VALID, c))
    code[n++] = c;
2 голосов
/ 28 января 2011

Я думаю, что наиболее существенной проблемой является то, что вы увеличиваете code, когда читаете материал, а затем возвращаете конечное значение code, т.е. вы будете возвращать указатель на end строки. Возможно, вы захотите сделать копию code перед циклом и вернуть ее вместо этого.

Кроме того, строки C должны заканчиваться нулем. Вам нужно убедиться, что вы ставите '\0' сразу после последнего прочитанного вами символа.

Примечание: Вы можете просто использовать fgets(), чтобы получить всю строку одним ударом.

1 голос
/ 28 января 2011

Проблема здесь двоякая: а) вы увеличиваете указатель, прежде чем проверяете прочитанное значение, и б) вы игнорируете тот факт, что fgetc () возвращает int вместо char.

Первый легко исправить:

char *orig = code; // the beginning of the array
// ...
do {
  *code = fgetc(file);
} while(*code++ != EOF);
*code = '\0'; // nul-terminate the string
return orig; // don't return a pointer to the end

Вторая проблема более тонкая - fgetc возвращает int, что значение EOF можно отличить от любого возможного значения chsr. Для исправления используется временный int для проверки EOF и, вероятно, обычный цикл while вместо do / while.

1 голос
/ 28 января 2011

Любой из двух должен делать свое дело -

char *readFile(char *fileName)
{
  FILE *file;
  char *code = malloc(1000 * sizeof(char));
  char *p = code;
  file = fopen(fileName, "r");
  do 
  {
    *p++ = (char)fgetc(file);
  } while(*p != EOF);
  *p = '\0';
  return code;
}

char *readFile(char *fileName)
{
  FILE *file;
  int i = 0;
  char *code = malloc(1000 * sizeof(char));
  file = fopen(fileName, "r");
  do 
  {
    code[i++] = (char)fgetc(file);
  } while(code[i-1] != EOF);
  code[i] = '\0'
  return code;
}

Как указали другие авторы, вам нужно убедиться, что размер файла не превышает 1000 символов.Кроме того, не забудьте освободить память, когда закончите с ней.

...