Читать строку из файла, не зная длины строки - PullRequest
27 голосов
/ 28 марта 2010

Я хочу читать в файл построчно, не зная длины строки раньше. Вот что я получил до сих пор:

int ch = getc(file);
int length = 0;
char buffer[4095];

while (ch != '\n' && ch != EOF) {
    ch = getc(file);
    buffer[length] = ch;
    length++;
}

printf("Line length: %d characters.", length);

char newbuffer[length + 1];

for (int i = 0; i < length; i++)
    newbuffer[i] = buffer[i];

newbuffer[length] = '\0';    // newbuffer now contains the line.

Теперь я могу определить длину строки, но только для строк, длина которых не превышает 4095 символов, плюс два массива символов кажутся неудобным способом выполнения задачи. Есть ли лучший способ сделать это (я уже использовал fgets (), но мне сказали, что это не лучший способ)?

- Ry

Ответы [ 4 ]

15 голосов
/ 28 марта 2010

Вы можете начать с подходящего размера по вашему выбору, а затем использовать realloc на полпути, если вам нужно больше места как:

int CUR_MAX = 4095;
char *buffer = (char*) malloc(sizeof(char) * CUR_MAX); // allocate buffer.
int length = 0;

while ( (ch != '\n') && (ch != EOF) ) {
    if(length ==CUR_MAX) { // time to expand ?
      CUR_MAX *= 2; // expand to double the current size of anything similar.
      buffer = realloc(buffer, CUR_MAX); // re allocate memory.
    }
    ch = getc(file); // read from stream.
    buffer[length] = ch; // stuff in buffer.
    length++;
}
.
.
free(buffer);

Вам придется проверять ошибки распределения после звонков на malloc и realloc.

5 голосов
/ 28 марта 2010

Возможно, вы захотите заглянуть в публичное достояние Чака Б. Фальконера ggets библиотека . Если вы работаете в системе с glibc, вам, вероятно, доступна (нестандартная) функция getline.

1 голос
/ 10 марта 2015

Вот как я это сделал для стандартного ввода, если вы вызываете его как readLine(NULL, 0), функция выделяет для вас буфер размером 1024 и позволяет ему увеличиваться с шагом 1024. Если вы вызываете функцию с readLine(NULL, 10) вы получаете буфер с шагом 10. Если у вас есть буфер, вы можете указать его размер.

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

char *readLine(char **line, size_t *length)
{
    assert(line != NULL);
    assert(length != NULL);

    size_t count = 0;

    *length = *length > 0 ? *length : 1024;

    if (!*line)
    {
        *line = calloc(*length, sizeof(**line));
        if (!*line)
        {
            return NULL;
        }
    }
    else
    {
        memset(*line, 0, *length);
    }

    for (int ch = getc(stdin); ch != '\n' && ch != EOF; ch = getc(stdin))
    {
        if (count == *length)
        {
            *length += 2;
            *line = realloc(*line, *length);
            if (!*line)
            {
                return NULL;
            }
        }

        (*line)[count] = (char)ch;

        ++count;
    }

    return *line;
}
1 голос
/ 28 марта 2010

Ты рядом. В основном вы хотите прочитать куски данных и проверить их на наличие \n символов. Если вы найдете один, хорошо, у вас есть конец строки. Если вы этого не сделаете, вы должны увеличить свой буфер (т.е. выделить новый буфер в два раза больше первого и скопировать данные из первого в новый, затем удалить старый буфер и переименовать новый буфер как старый - или просто realloc, если вы находитесь в C), тогда читайте еще немного, пока не найдете окончание.

Если у вас есть конец, текст от начала буфера до символа \n будет вашей строкой. Скопируйте его в буфер или поработайте над ним на ваше усмотрение.

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...