Почему эта программа не показывает первую строку снова и снова? - PullRequest
2 голосов
/ 10 января 2010
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *readLine(FILE *inFile)  //Simply reads line in a text file till "\n"
{
    char *line = realloc(NULL, 1);
    char c;
    int i=0;
    while (!feof(inFile))
    {
        c = fgetc(inFile);
        if (ferror(inFile)) printf("Error reading");
        if (c == 10)
            {
                realloc(line,i+1);
                line[i]= 10;
                break;
            }
        realloc(line, i+1);
        line[i++] = c;
    }
    return line;
}

int main(int argc,char **argv)
{
    FILE *inFile;
    inFile = fopen("testFile","r");
    printf("%s",readLine(inFile));
    printf("%s",readLine(inFile));
    printf("%s",readLine(inFile));
    return 0;
}

Если содержимое testFile: -

abc
def
ghi

Три оператора printf должны показывать «abc» три раза .. Но результат будет таким:

abc
def
ghi

Я знаю, что где-то ошибаюсь в концепции. Просьба помочь.

Ответы [ 3 ]

6 голосов
/ 10 января 2010

Использование realloc() неверно.

realloc(line,i+1); // wrong

// OK
void *new_line = realloc(line,i+1);
if (!new_line)
{
    free(line);
    return NULL;
}
line = new_line;

Поскольку line передается по значению, оно не изменяется. Фактически перераспределенная память находится в возвращаемом значении. Поэтому line остается одним и тем же снова и снова, и вы видите одну и ту же строку снова и снова. Редактировать: только что понял, что это даже если это ошибка, это не то, что вызовет повторяющиеся строки. Другие пункты остаются в силе.

Что хуже:

  1. У вас есть утечка памяти, каждый раз теряя заново перераспределенный указатель.
  2. Вы потенциально получаете доступ к освобожденной памяти, поскольку старое значение line может стать недействительным после перераспределения, если оно было перераспределено в другой части кучи.
  3. Вы перераспределяете память каждому символу, что потенциально является дорогостоящей операцией.
4 голосов
/ 10 января 2010

Но я передаю указатель файла по значению. Поэтому я должен снова и снова получать вывод "abc"

Ах, я понимаю ваше замешательство.

Указатель файла указывает только на фактическую структуру файла. Такие состояния, как текущее смещение, не являются частью указателя, но являются частью внутренней структуры.

Еще один способ думать об этом - фактический объект, представляющий файл, - ФАЙЛ. Чтобы получить семантику передачи по ссылке, вы передаете указатель на объект. Поскольку вы передаете по ссылке, каждая строка выбирается там, где остановилась последняя.

4 голосов
/ 10 января 2010

fgetc() увеличивает указатель файла (то есть «где находится следующий символ для чтения»). Вот как вы можете вызвать его в цикле и прочитать целую строку символов.

После того, как он прошел за символ новой строки, он естественным образом переходит к следующему символу, который является началом следующей строки.

Вы можете изменить указатель файла с помощью функции fseek(). Например, вызов fseek(inFile, 0, SEEK_SET) сбрасывает его в начало файла, в результате чего следующий вызов fgetc() начинается заново с первого символа файла.

...