Подтвердить что ты не робот

Чтение строки из файла без знания длины строки

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

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 символов, плюс два массива char кажутся неудобным способом выполнения задачи. Есть ли лучший способ сделать это (я уже использовал fgets(), но мне сказали, что это не лучший способ)?

- Ry

4b9b3361

Ответ 1

Вы можете начать с подходящего размера по вашему выбору, а затем использовать 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.

Ответ 3

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

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

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

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

Ответ 4

Вот как я это сделал для stdin, если вы называете это как 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;
}