2010-01-10 5 views
2
#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 

Я знаю, что я неправильно в концепции. Помощь Pls.

+1

Ваше название и вопрос полностью противоречат друг другу. На какой вопрос вы спрашиваете? –

+0

В дополнение к проблеме 'realloc' вы не должны вызывать' feof' как условие цикла. Вместо этого ваша структура цикла должна быть: 'int c;/* Обратите внимание, что это int, а не char */while ((c = fgetc (inFile))! = EOF) {/ * ... */' См. Http://c-faq.com/~scs /cclass/int/sx2h.html для объяснения. Кроме того, вместо того, чтобы изобретать колесо, рассмотрите возможность использования 'fgets', или если вы хотите, чтобы версия динамически распределяла буфер достаточно долго, чтобы удерживать всю строку, используйте функцию« ggets »общественного достояния Чака Фальконера: http: // cbfalconer.home.att.net/download/ggets.zip – jamesdlin

+0

Хорошо. Я понимаю. Я прочитал c-faq .. thanx –

ответ

4

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

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

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

Другой способ подумать об этом заключается в том, что фактическим объектом, представляющим файл, является FILE. Чтобы получить семантику pass-by-reference, вы передаете указатель на объект. Поскольку вы проходите по ссылке, каждая строка поднимается туда, где последний остановился.

+0

Да .. Я получил то, что я действительно хотел .. Большое спасибо .. Thanx другим людям, чтобы рассказать еще несколько важных моментов ... –

6

Неверное использование 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. Вы перераспределяете память на каждый символ, что потенциально является дорогостоящей операцией.
+1

bad bad bad |! он должен быть недействительным * tmp = realloc (строка, i + 1); if (tmp) {line = tmp; } else {/ * handle error * /} – asveikau

+3

Я бы добавил к этому +1 ответ, что вы не должны быть 'realloc'ing для каждого символа. Это относительно дорогостоящий процесс. Существует два распространенных подхода к изменению размера буферов. 1) имеют начальное распределение (например, 1024 байта) и размер дельта (512 байт), который вы добавляете каждый раз, когда вам нужно расширить буфер. И 2) имеют размер по умолчанию (например, 64 байта) и удваивают размер каждый раз, когда вы повторно используете. О, а также вы должны поместить '\ n' в конец ваших строк, если вы хотите их увидеть; printf обычно использует буферизованный вывод. – gavinb

+0

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

4

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

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

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

+0

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

+0

Вы смешиваете термины. Указатель на файл - это не то же самое, что «указатель файла», также известный как «указатель позиции файла». Вы передаете указатель на тот же файл снова и снова, но индикатор позиции файла продвигается при каждом вызове функции fgetc(). Как говорит aib, вам придется сбросить его с помощью fseek(), если вы хотите начать все заново. – wadesworld

Смежные вопросы