2015-04-07 2 views
2
#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    FILE *input_f; 

    input_f = fopen("Input.txt", "r"); //Opens the file in read mode. 
    if (input_f != NULL) 
    { 
     char line[2048]; 

     while(fgets(line, sizeof line, input_f) != NULL) 
     { 
      //do something 
     } 
     fclose(input_f); //Close the input file. 
    } 
    else 
    { 
     perror("File couldn't opened"); //Will print that file couldn't opened and why. 
    } 
    return 0; 
} 

Hi. Я знаю, что могу читать строки за строкой с этим кодом на C, но я не хочу ограничивать размер строки, например, в этом коде с 2048.Чтение строки из файла в C, динамически

Я думал об использовании malloc, но я не знаю, размер строки до того, как я ее прочитаю, поэтому ИМО это не может быть сделано.

Есть ли способ не ограничивать размер линии?

Этот вопрос только для моего любопытства, спасибо.

+4

Вы всегда можете использовать 'getchar()' + 'realloc()', и есть также 'getline()'. –

+2

http://stackoverflow.com/questions/2532425/read-line-from-file-without-knowing-the-line-length –

+0

Мой ответ на аналогичный вопрос: http://stackoverflow.com/questions/28254245/ c-reading-a-text-file-separated-by-spaces-with-unbounded-word-size/28255082 # 28255082 –

ответ

1

При выделении памяти динамически, вы хотите изменить:

char line[2048]; 

в

#define MAXL 2048   /* the use of a define will become apparent when you */ 
size_t maxl = MAXL;   /* need to check to determine if a realloc is needed */ 
char *line = malloc (maxl * sizeof *line); 
if (!line)     /* always check to insure allocation succeeded */ 
    ...error.. memory allocation failed 

Вы читать дочитать до (maxl -1) символов или newline (при использовании fgetc и т.д. ..) или прочитайте строку, а затем проверьте, line [strlen (line) - 1] == '\n', чтобы определить, читаете ли вы всю строку (если используете fgets). (POSIX требует, чтобы все линии заканчивались newline). Если вы читаете maxl символов (fgetc) или не читали новую строку (fgets), то это короткое сообщение и больше символов осталось. Ваш выбор - realloc (обычно удваивает размер) и повторите попытку. Для того, чтобы перераспределить:

char *tmp = realloc (line, 2 * maxl) 
if (tmp) { 
    line = tmp; 
    maxl *= 2; 
} 

. Примечание: никогда перераспределить, используя исходный указатель (например line = realloc (line, 2 * maxl), потому что если realloc терпит неудачу, память освобождается и указатель установлен на NULL, и вы потеряете все данные, которые существовали в line также обратите внимание, что maxl обычно удваивается каждый раз при realloc. Однако вы можете выбрать любую схему увеличения размера, которая вам нравится. (Если вас беспокоит обнуление всей выделенной выделенной памяти, вы можете использовать memset для инициализации вновь выделенного пространства до нуля/null. Полезно в некоторых ситуациях, когда вы хотите застраховать свой line, всегда null-terminated)

Это основная схема динамического распределения/перераспределения. Заметьте, что вы читаете, пока не прочитаете полную строку, поэтому вам нужно будет перестроить свой цикл теста. И, наконец, поскольку вы выделили память, вы несете ответственность за освобождение памяти, когда вы закончите с ней. Инструментом, с которым вы не можете жить, является valgrind (или аналогичная программа проверки памяти), чтобы подтвердить, что вы не пропускаете память.

Совет, если вы читаете и хотите застраховать свою строку всегда null-terminated, то после выделения своего блока памяти, ноль (0) все символы. Как упоминалось ранее, есть memset, но если вы выберете calloc вместо malloc, он будет нулевать для вас память. Однако в realloc новое пространство НЕ равно нулю, так что вызов memset требуется независимо от того, какая функция изначально назначила блок.

Tip2 Посмотрите на POSIX getline. getline будет обрабатывать распределение/перераспределение, если line инициализирован до NULL.getline также возвращает количество фактически прочитанных символов, выдающих с необходимостью позвонить strlen после fgets, чтобы определить то же самое.

Дайте мне знать, если у вас есть дополнительные вопросы.

+0

Не соглашайтесь с тем, что использование «обнуления всей выделенной памяти» «полезно, если вы хотите, чтобы ваша линия всегда была завершена нулем». Лучше всего проверять возвращаемое значение из 'fgets()'. Если возвращаемое значение не 'NULL' (и' size> 0'), тогда буфер всегда будет иметь нулевой символ. – chux

+0

Я думал об этом. Это не один размер, который подходит для всех ситуаций, но как представить новый распределитель концепции? Я подумаю об этом и передумаю. Есть ли у вас какие-либо предложения? –

+0

@chux Как это для квалификации? Не стесняйтесь брать креативную лицензию. Дело в том, чтобы помочь OP учиться. –

0

Рассмотрим 2 мысли:

  1. Верхняя граница выделенной памяти является разумным. Характер задачи должен иметь приблизительно Идея максимальной длины линии, будь то 80, 1024 или 1 Мбайт.

  2. С умной ОС фактическое использование выделенной памяти может не произойти до тех пор, пока это не понадобится. См Why is malloc not "using up" the memory on my computer?

Итак код выделить 1 большой буфер, чтобы ограничить патологические случаи, и пусть основное управление памятью (повторно) выделить реальную память по мере необходимости.

#define N (1000000) 
char *buf = malloc(N); 
... 
while (fgets(buf, N, stdin) != NULL)) { 
    size_t len = strlen(buf); 
    if (len == N-1) { 
    perror("Excessive Long Line"); 
    exit(EXIT_FAILURE); 
    } 
} 
free(buf); 
Смежные вопросы