Как упростить эту функцию readLine ()? - PullRequest
1 голос
/ 24 мая 2019

У меня есть эта функция, и она читает первую строку некоторого файла .txt и возвращает строку для работы с ней.Я НЕ знаю, какова будет длина строки, поэтому я не могу иметь постоянный размер буфера.Моя проблема в том, что я не могу использовать эту функцию, потому что она будет рассматриваться как мошенничество (у меня есть экзамены), потому что это не мой код.

Я думал о переменной длине массива, но это злокак мне сказали, и я мог бы просто отсканировать всю строку где-то, я думаю, но я не уверен, как мне это сделать в этом случае (мне нужно вернуть строку)

char* readLine(FILE *line) { 
    char individualChar;
    int pos = 0;
    int size = 16;
    char *buffer = (char *)malloc(size);

    while ((individualChar = fgetc(line)) != EOF && individualChar != '\n'){
        if (pos + 1 == size){
            size *= 2;
            char *tmp = (char *)realloc(buffer, size);
            if (!tmp){
                free(buffer);
                fprintf(stderr, "Realloc failed");
                return 0;
            }
            buffer = tmp;
        }
        buffer[pos] = individualChar;
        pos++;
    }

    buffer[pos] = '\0';
    return buffer;
}

Ответы [ 2 ]

2 голосов
/ 24 мая 2019

Размещение большого количества кода здесь не годится, так как у OP

считается обманом (у меня есть экзамены), потому что это не мой код.

Итак, несколько советов


Я НЕ знаю, какова будет длина строки, поэтому я не могу иметь постоянный размер буфера.

Защитное программирование предполагает разумную верхнюю границу для предотвращения хакерских атак. IAC, при чтении текстовых файлов экологические ограничения .

Экологические ограничения
Реализация должна поддерживать текстовые файлы со строками, содержащими не менее 254 символов, включая завершающий символ новой строки. Значение макроса BUFSIZ должно быть не менее 256. C11 §7.21.2 7

При таком подходе:

#include <stdio.h>
#define SANE_BOUND (BUFSIZ+1)

char* readLine(FILE *line) { 
  char buffer[SANE_BOUND];
  if (fgets(buffer, sizeof buffer, line) == NULL) {
    return NULL;
  }
  return strdup(buffer);
}

Как упростить эту readLine() функцию?

Для ясности, код, который вы не хотите копировать, имеет проблем .

Исправления

// char is insufficient to distinguish the 257 different results from fgetc()
// char individualChar;
int individualChar;

// Use size_t for sizing, `int` may be too small
size_t pos = 0;
size_t size = 16;

Если первый fgetc() возврат вызова EOF или более поздний возврат вызова EOF из-за редкой ошибки ввода, функция должна вернуть NULL.

Бросьте броски, не нужно.

//char *buffer = (char *)malloc(size);
//char *tmp = (char *)realloc(buffer, size);
char *buffer = malloc(size);
char *tmp = realloc(buffer, size);

Почему неполный чек?

Код имеет if (!tmp){, но нет предварительной проверки для if (!buffer){

Minor

// Use \n and stay case correct
// fprintf(stderr, "Realloc failed");
fprintf(stderr, "realloc() failed\n");

Pedantic

size *= 2; может переполниться. Насколько безопасным ты хочешь быть?

Дизайн

Я бы правильный размер с окончательным realloc().

Я бы перепроектировал, чтобы передать вызывающей стороне как считанный размер, так и выделенную память. Текстовый файл lines необычно может содержать нулевой символ , и возвращение только указателя string не означает, что некоторые из них были прочитаны. Относится и к этому кейсу .


A хорошо выделение readLine() будет менее простым, чем опубликованный код OP.

0 голосов
/ 24 мая 2019

Вы могли бы предложить более простой подход:

  1. считать размер первой строки
  2. выделить необходимую память за один шаг
  3. чтение строки в выделенную память

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

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

char *readline(FILE *f)
{
    size_t size = 0;
    char *ret = NULL;
    long pos = ftell(f);

    /* find line size */
    int c = fgetc(f);
    while (c != EOF && c != '\n')
    {
        c = fgetc(f);
        ++size;
    }

    if (size)
    {
        /* allocate mem */
        ret = malloc(size + 1);

        /* rewind file */
        fseek(f, SEEK_SET, pos);

        /* read data */
        fread(ret, 1, size, f);

        /* add string limiter */
        ret[size] = 0;
    }
    return ret;
}

Внимание

Этот код неполон, так как он не проверяет:

  • для f не для NULL
  • возвращаемые значения malloc и fread
...