C читать файл построчно

Я написал эту функцию для чтения строки из файла:

const char *readLine(FILE *file) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    const char *constLine = line;
    return constLine;
}

Функция правильно читает файл, и, используя printf, я вижу, что строка constLine также была прочитана правильно.

Однако, если я использую функцию, например, нравится:

while (!feof(myFile)) {
    const char *line = readLine(myFile);
    printf("%s\n", line);
}

printf выводит тарабарщину. Почему?


person lron    schedule 17.08.2010    source источник
comment
Используйте fgets вместо fgetc. Вы читаете посимвольно, а не построчно.   -  person Shiv    schedule 17.03.2017
comment
Обратите внимание, что getline() является частью POSIX 2008. Может быть POSIX -подобные платформы без него, особенно если они не поддерживают остальную часть POSIX 2008, но в мире систем POSIX getline() в наши дни довольно портативен.   -  person Jonathan Leffler    schedule 09.05.2017


Ответы (17)


Если ваша задача - не изобрести функцию построчного чтения, а просто построчно прочитать файл, вы можете использовать типичный фрагмент кода, включающий функцию getline() (см. Страницу руководства здесь):

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

int main(void)
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("/etc/motd", "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        printf("Retrieved line of length %zu:\n", read);
        printf("%s", line);
    }

    fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}
person mbaitoff    schedule 17.08.2010
comment
Точнее, это getline специфично для GNU libc, то есть для Linux. Однако, если цель состоит в том, чтобы иметь функцию чтения строк (в отличие от изучения C), в Интернете доступно несколько общедоступных функций чтения строк. - person Gilles 'SO- stop being evil'; 17.08.2010
comment
также я думаю, вы хотите free(line) до конца этого цикла while - person ; 30.11.2012
comment
Почему я должен делать это? Прочтите мануал, буфер перераспределяется при каждом вызове, затем его нужно освобождать в конце. - person mbaitoff; 30.11.2012
comment
Проверка if(line) лишняя. Вызов free(NULL), по сути, бесполезен. - person aroth; 28.01.2014
comment
@aroth Я согласен, но это отрывок со страницы man. Они сказали, что лучше перестраховаться, чем сожалеть. )) - person mbaitoff; 28.01.2014
comment
Я скажу, что это довольно гладко, и направление, в котором я буду двигаться ... Редактировать: @mbaitoff Спасибо! - person kzorro; 16.03.2014
comment
@ gg.kaspersky Я не специалист по поиску божественных посланий в священных книгах. Дело в том, что в реальной жизни ресурсы освобождаются. Я думаю, что фрагменты короткого кода предоставляют только концепцию и не должны включать в себя все бремя инициализации / деинициализации. - person mbaitoff; 02.04.2014
comment
@PhilipAdler - Тогда тот, кто написал спецификацию, сделал глупый / небрежный поступок. Хотя справочная страница говорит, что если ptr является NULL, никакие операции не выполняются. Для меня это достаточно хорошее определение. - person aroth; 25.05.2014
comment
@PhilipAdler Если вы действительно хотите бороться из-за того, что free(NULL) не указан (хотя я почти уверен, что это нигде так не написано), то вы должны знать, что даже ls вызывает free(NULL). После проверки на странице руководства указано, что free(ptr); free(ptr); не определено и что free(NULL) ничего не делает. @mbaitoff Тогда зачем тебе тогда освобождать line? Тем не менее, этот веб-сайт предназначен для обучения или помощи с лучшим возможным решением, и освобождение каждой выделенной памяти, которая больше не используется, на самом деле является хорошей практикой. - person Jerska; 13.06.2014
comment
@Jerksa; С этим не поспоришь! - person Philip Adler; 14.06.2014
comment
Для тех, кто сказал, что эта getline специфична для GNU libc, и getline (), и getdelim () изначально были расширениями GNU. Они были стандартизированы в POSIX.1-2008. - person willkill07; 22.04.2015
comment
Честно говоря, выделение ресурсов и оставление ответственности за освобождение от ответственности за пользователя само по себе не очень разумная идея. - person Overdrivr; 29.02.2016
comment
Если быть полностью честным, этот ответ взят прямо со страницы руководства. Если необходимо обсудить правильное выделение / освобождение памяти, это следует поставить как отдельный вопрос, и, конечно же, это уже так. ОП явно задавал вопрос только о функции и ее цели - читать файл построчно. Следовательно, этот вопрос не должен иметь ничего общего с надлежащим управлением памятью или передовыми практиками. Это не имеет отношения к исходному вопросу. - person Chisx; 03.09.2017
comment
@PhilipAdler - free(NULL) - это не определенная операция ...: из стандарта C11, §7.22.3.3 / 2, Если ptr - пустой указатель, никаких действий не происходит. Стандарты C89 и C99 говорят то же самое. Итак, free(NULL) - это определенная не операция. - person ad absurdum; 28.01.2018
comment
У меня больше нет доступа к стандартам, которые я использовал четыре года, чтобы проверить, откуда исходит мое утверждение, так что @DavidBowling вполне может быть прав. - person Philip Adler; 29.01.2018
comment
@PhilipAdler - ссылка в моем комментарии относится к проекту стандарта C11. Но вы также можете прочитать это и это. По-видимому, до C89 некоторые реализации вылетали из-за нулевого указателя. - person ad absurdum; 29.01.2018
comment
Интересный. Интересно, какую версию стандарта C младше меня читал в университетской библиотеке. Может, стоит посетить мою альма-матер! - person Philip Adler; 29.01.2018
comment
Даже C90 §7.10.3.2 Функция free сказала Если ptr является нулевым указателем. никаких действий не происходит. Только стандартные библиотеки C могли ошибаться free(NULL). После выпуска стандарта C90 некоторые библиотеки, вероятно, не обновлялись в течение нескольких лет, но к середине 90-х было в целом безопасно использовать free(NULL) - или, что более вероятно, free(ptr), где ptr оказался нулевым указателем. - person Jonathan Leffler; 16.10.2019
comment
Если вам известна максимальная длина строки, использование fgets - более простой подход, который также не требует кучи. - person theicfire; 17.10.2019
comment
@Nark это уже обсуждалось восемь лет назад и исключено, проверьте документацию и комментарии выше. - person mbaitoff; 24.05.2020

В своей функции readLine вы возвращаете указатель на массив line (строго говоря, указатель на его первый символ, но здесь разница не имеет значения). Поскольку это автоматическая переменная (т.е. она находится «в стеке»), память освобождается при возврате функции. Вы видите тарабарщину, потому что printf положил в стек свой собственный материал.

Вам необходимо вернуть из функции динамически выделенный буфер. Он у вас уже есть, это lineBuffer; все, что вам нужно сделать, это обрезать его до желаемой длины.

    lineBuffer[count] = '\0';
    realloc(lineBuffer, count + 1);
    return lineBuffer;
}

ДОБАВЛЕНО (ответ на последующий вопрос в комментарии): readLine возвращает указатель на символы, составляющие строку. Этот указатель - то, что вам нужно для работы с содержимым строки. Это также то, что вы должны передать free, когда закончите использовать память, занятую этими символами. Вот как можно использовать функцию readLine:

char *line = readLine(file);
printf("LOG: read a line: %s\n", line);
if (strchr(line, 'a')) { puts("The line contains an a"); }
/* etc. */
free(line);
/* After this point, the memory allocated for the line has been reclaimed.
   You can't use the value of `line` again (though you can assign a new value
   to the `line` variable if you want). */
person Gilles 'SO- stop being evil'    schedule 17.08.2010
comment
@Iron: Я кое-что добавил к своему ответу, но я не уверен, в чем ваша сложность, так что это может быть неправильно. - person Gilles 'SO- stop being evil'; 17.08.2010
comment
@Iron: ответ в том, что вы не освобождаете его. Вы документируете (в документации API) тот факт, что возвращаемый буфер является malloc'd, и вызывающий должен освободить его. Затем люди, которые используют вашу функцию readLine, будут (надеюсь!) Писать код, аналогичный фрагменту, который Жиль добавил к своему ответу. - person JeremyP; 17.08.2010

readLine() возвращает указатель на локальную переменную, что вызывает неопределенное поведение.

Чтобы передвигаться, вы можете:

  1. Создайте переменную в вызывающей функции и передайте ее адрес readLine()
  2. Выделите память для line с помощью malloc() - в этом случае line будет постоянным
  3. Используйте глобальную переменную, хотя, как правило, это плохая практика.
person qrdl    schedule 17.08.2010

Используйте fgets(), чтобы прочитать строку из дескриптора файла.

person Raku Escape    schedule 11.05.2016

Полное решение fgets():

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

#define MAX_LEN 256

int main(void)
{
    FILE* fp;
    fp = fopen("file.txt", "r");
    if (fp == NULL) {
      perror("Failed: ");
      return 1;
    }

    char buffer[MAX_LEN];
    // -1 to allow room for NULL terminator for really long string
    while (fgets(buffer, MAX_LEN - 1, fp))
    {
        // Remove trailing newline
        buffer[strcspn(buffer, "\n")] = 0;
        printf("%s\n", buffer);
    }

    fclose(fp);
    return 0;
}

Вывод:

First line of file
Second line of file
Third (and also last) line of file

Помните, что если вы хотите читать из стандартного ввода (а не из файла, как в этом случае), все, что вам нужно сделать, это передать stdin в качестве третьего параметра метода fgets(), например:

while(fgets(buffer, MAX_LEN - 1, stdin))

Приложение

Удаление завершающего символа новой строки из ввода fgets ()

как определить, открыт файл или нет в c

person gsamaras    schedule 17.10.2020
comment
Привет, @gsamaras, я думаю, мы можем напрямую передать MAX_LEN в fgets. Я нашел это описание в: linux.die.net/man/3/fgets `` `` ` - person juan cortez; 17.11.2020
comment
Привет, @juancortez, я действительно передаю MAX_LEN - 1 во втором аргументе метода! - person gsamaras; 17.11.2020

Некоторые ошибки в примере:

  • вы забыли добавить \ n в свой printfs. Также сообщения об ошибках должны отправляться в stderr, т.е. fprintf(stderr, ....
  • (не очень важно, но) подумайте об использовании fgetc(), а не getc(). getc() - макрос, fgetc() - правильная функция
  • getc() возвращает int, поэтому ch следует объявить как int. Это важно, поскольку сравнение с EOF будет выполнено правильно. Некоторые 8-битные наборы символов используют 0xFF в качестве допустимого символа (примером может служить ISO-LATIN-1), а EOF, который равен -1, будет 0xFF, если он назначен char.
  • Возможное переполнение буфера в строке

    lineBuffer[count] = '\0';
    

    Если длина строки ровно 128 символов, count будет 128 в момент выполнения.

  • Как указывали другие, line - это локально объявленный массив. Вы не можете вернуть на него указатель.

  • strncpy(count + 1) скопирует не более count + 1 символов, но завершится, если попадет в '\0'. Поскольку вы установили lineBuffer[count] на '\0', вы знаете, что он никогда не дойдет до count + 1. Однако, если бы это было так, это не привело бы к включению завершающего '\0', поэтому вам нужно это сделать. Часто можно увидеть что-то вроде следующего:

    char buffer [BUFFER_SIZE];
    strncpy(buffer, sourceString, BUFFER_SIZE - 1);
    buffer[BUFFER_SIZE - 1] = '\0';
    
  • если вы malloc() строку, которую нужно вернуть (вместо вашего локального char массива), ваш тип возврата должен быть char* - отбросьте const.

person JeremyP    schedule 17.08.2010

const char *readLine(FILE *file, char* line) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    char *lineBuffer = (char *)malloc(sizeof(char) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    char ch = getc(file);
    int count = 0;

    while ((ch != '\n') && (ch != EOF)) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }
        lineBuffer[count] = ch;
        count++;

        ch = getc(file);
    }

    lineBuffer[count] = '\0';
    char line[count + 1];
    strncpy(line, lineBuffer, (count + 1));
    free(lineBuffer);
    return line;

}


char linebuffer[256];
while (!feof(myFile)) {
    const char *line = readLine(myFile, linebuffer);
    printf("%s\n", line);
}

обратите внимание, что переменная line объявляется в вызывающей функции и затем передается, поэтому ваша функция readLine заполняет предопределенный буфер и просто возвращает его. Так работает большинство библиотек C.

Есть и другие способы, о которых я знаю:

  • определение char line[] как статического (static char line[MAX_LINE_LENGTH] -> он будет удерживать свое значение ПОСЛЕ возврата из функции). -> плохо, функция не является реентерабельной, и может возникнуть состояние гонки -> если вы вызовете ее дважды из двух потоков, она перезапишет ее результаты
  • malloc() освобождение строки char [] и ее освобождение при вызове функций -> слишком много дорогостоящих malloc и делегирование ответственности за освобождение буфера другой функции (наиболее элегантным решением является вызов malloc и free для любых буферов в той же функции)

кстати, «явное» приведение от char* к const char* является избыточным.

btw2, нет необходимости malloc() lineBuffer, просто определите его char lineBuffer[128], поэтому вам не нужно его освобождать

btw3 не использует «массивы стека динамического размера» (определяя массив как char arrayName[some_nonconstant_variable]), если вы точно не знаете, что делаете, это работает только в C99.

person nothrow    schedule 17.08.2010
comment
обратите внимание, что переменная 'line' объявляется в вызывающей функции, а затем передается, - тогда вам, вероятно, следовало удалить локальное объявление строки в функции. Кроме того, вам необходимо сообщить функции, какой длины буфер, который вы передаете, и подумать о стратегии обработки строк, которые слишком длинные для буфера, который вы передаете. - person JeremyP; 17.08.2010

void readLine(FILE* file, char* line, int limit)
{
    int i;
    int read;

    read = fread(line, sizeof(char), limit, file);
    line[read] = '\0';

    for(i = 0; i <= read;i++)
    {
        if('\0' == line[i] || '\n' == line[i] || '\r' == line[i])
        {
            line[i] = '\0';
            break;
        }
    }

    if(i != read)
    {
        fseek(file, i - read + 1, SEEK_CUR);
    }
}

что насчет этого?

person Taner Mansur    schedule 12.08.2015

Реализовать метод для чтения и получения содержимого из файла (input1.txt)

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

void testGetFile() {
    // open file
    FILE *fp = fopen("input1.txt", "r");
    size_t len = 255;
    // need malloc memory for line, if not, segmentation fault error will occurred.
    char *line = malloc(sizeof(char) * len);
    // check if file exist (and you can open it) or not
    if (fp == NULL) {
        printf("can open file input1.txt!");
        return;
    }
    while(fgets(line, len, fp) != NULL) {
        printf("%s\n", line);
    }
    free(line);
}

Надеюсь на эту помощь. Удачного кодирования!

person Nhat Dinh    schedule 16.11.2017

Вот мои несколько часов ... Чтение всего файла построчно.

char * readline(FILE *fp, char *buffer)
{
    int ch;
    int i = 0;
    size_t buff_len = 0;

    buffer = malloc(buff_len + 1);
    if (!buffer) return NULL;  // Out of memory

    while ((ch = fgetc(fp)) != '\n' && ch != EOF)
    {
        buff_len++;
        void *tmp = realloc(buffer, buff_len + 1);
        if (tmp == NULL)
        {
            free(buffer);
            return NULL; // Out of memory
        }
        buffer = tmp;

        buffer[i] = (char) ch;
        i++;
    }
    buffer[i] = '\0';

    // Detect end
    if (ch == EOF && (i == 0 || ferror(fp)))
    {
        free(buffer);
        return NULL;
    }
    return buffer;
}

void lineByline(FILE * file){
char *s;
while ((s = readline(file, 0)) != NULL)
{
    puts(s);
    free(s);
    printf("\n");
}
}

int main()
{
    char *fileName = "input-1.txt";
    FILE* file = fopen(fileName, "r");
    lineByline(file);
    return 0;
}
person Sam    schedule 28.11.2017
comment
Почему вы используете fgetc вместо fgets? - person theicfire; 17.10.2019

Вы должны использовать функции ANSI для чтения строки, например. fgets. После вызова вам понадобится free () в контексте вызова, например:

...
const char *entirecontent=readLine(myFile);
puts(entirecontent);
free(entirecontent);
...

const char *readLine(FILE *file)
{
  char *lineBuffer=calloc(1,1), line[128];

  if ( !file || !lineBuffer )
  {
    fprintf(stderr,"an ErrorNo 1: ...");
    exit(1);
  }

  for(; fgets(line,sizeof line,file) ; strcat(lineBuffer,line) )
  {
    if( strchr(line,'\n') ) *strchr(line,'\n')=0;
    lineBuffer=realloc(lineBuffer,strlen(lineBuffer)+strlen(line)+1);
    if( !lineBuffer )
    {
      fprintf(stderr,"an ErrorNo 2: ...");
      exit(2);
    }
  }
  return lineBuffer;
}
person user411313    schedule 17.08.2010

Моя реализация с нуля:

FILE *pFile = fopen(your_file_path, "r");
int nbytes = 1024;
char *line = (char *) malloc(nbytes);
char *buf = (char *) malloc(nbytes);

size_t bytes_read;
int linesize = 0;
while (fgets(buf, nbytes, pFile) != NULL) {
    bytes_read = strlen(buf);
    // if line length larger than size of line buffer
    if (linesize + bytes_read > nbytes) {
        char *tmp = line;
        nbytes += nbytes / 2;
        line = (char *) malloc(nbytes);
        memcpy(line, tmp, linesize);
        free(tmp);
    }
    memcpy(line + linesize, buf, bytes_read);
    linesize += bytes_read;

    if (feof(pFile) || buf[bytes_read-1] == '\n') {
        handle_line(line);
        linesize = 0;
        memset(line, '\0', nbytes);
    }
}

free(buf);
free(line);
person tjeubaoit    schedule 08.08.2018
comment
Почему вы используете кучу (malloc) вместо стека? Кажется, есть более простое решение на основе стека с fgets, которое можно было бы использовать. - person theicfire; 17.10.2019

Предоставьте переносимую универсальную функцию getdelim, тест пройден через msvc, clang, gcc.

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

ssize_t
portabl_getdelim(char ** restrict linep,
                 size_t * restrict linecapp,
                 int delimiter,
                 FILE * restrict stream) {
    if (0 == *linep) {
        *linecapp = 8;
        *linep = malloc(*linecapp);
        if (0 == *linep) {
            return EOF;
        }
    }

    ssize_t linelen = 0;
    int c = 0;
    char *p = *linep;

    while (EOF != (c = fgetc(stream))) {
        if (linelen == (ssize_t) *linecapp - 1) {
            *linecapp <<= 1;
            char *p1 = realloc(*linep, *linecapp);
            if (0 == *p1) {
                return EOF;
            }
            p = p1 + linelen;
        }
        *p++ = c;
        linelen++;

        if (delimiter == c) {
            *p = 0;
            return linelen;
        }
    }
    return EOF == c ? EOF : linelen;
}


int
main(int argc, char **argv) {
    const char *filename = "/a/b/c.c";
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror(filename);
        return 1;
    }

    char *line = 0;
    size_t linecap = 0;
    ssize_t linelen;

    while (0 < (linelen = portabl_getdelim(&line, &linecap, '\n', file))) {
        fwrite(line, linelen, 1, stdout);
    }
    if (line) {
        free(line);
    }
    fclose(file);   

    return 0;
}
person 南山竹    schedule 25.08.2019
comment
Почему это происходит, когда fgets существует? - person theicfire; 17.10.2019
comment
Может ли fgets настраивать разделители строк или настраивать действия с текущими строками? - person 南山竹; 17.10.2019
comment
getdelim позволяет настраивать разделители. Также я заметил, что нет ограничения на длину строки - в этом случае вы можете использовать стек с getline. (Оба описаны здесь: man7.org/linux/man-pages/man3 /getline.3.html) - person theicfire; 17.10.2019
comment
вы говорите только о Linux, вопрос в том, как читать строчки на C, не так ли? - person 南山竹; 17.10.2019
comment
Это работает для любой стандартной реализации c (getdelim и getline были стандартизированы в POSIX.1-2008, кто-то упоминает на этой странице). fgets также является стандартным c, а не специфичным для Linux - person theicfire; 17.10.2019
comment
POSIX C! = Стандарт C, почему вы говорите о POSIX? POSIX - другая тема. - person 南山竹; 18.10.2019
comment
Верно, но я считаю, что getline, fgets и getdelim работают на Mac, Linux и Windows. - person theicfire; 18.10.2019
comment
В Windows нет getdelim. - person 南山竹; 21.10.2019
comment
Ах ты прав. Это обсуждение помогает мне понять, когда будет полезен ваш код. - person theicfire; 22.10.2019

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

const char* func x(){
    char line[100];
    return (const char*) line; //illegal
}

Чтобы избежать этого, вы либо возвращаете указатель на память, которая находится в куче, например. lineBuffer, и пользователь должен будет вызвать free (), когда он закончит с ним. В качестве альтернативы вы можете попросить пользователя передать вам в качестве аргумента адрес памяти, в который будет записано содержимое строки.

person Lefteris E    schedule 25.03.2013
comment
Есть разница между незаконным и неопределенным поведением ^^. - person Phong; 27.06.2013

Мне нужен код с нуля, поэтому я сделал это, чтобы прочитать содержимое словаря построчно.

char temp_str [20]; // вы можете изменить размер буфера в соответствии с вашими требованиями. И длина одной строки в файле.

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

#include<stdio.h>

int main()
{
int i;
char temp_ch;
FILE *fp=fopen("data.txt","r");
while(temp_ch!=EOF)
{
 i=0;
  char temp_str[20]={'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'};
while(temp_ch!='\n')
{
  temp_ch=fgetc(fp);
  temp_str[i]=temp_ch;
  i++;
}
if(temp_ch=='\n')
{
temp_ch=fgetc(fp);
temp_str[i]=temp_ch;
}
printf("%s",temp_str);
}
return 0;
}
person Mohit Dabas    schedule 25.09.2014
comment
ваша программа будет работать, если ваши скобки будут в нужных местах;) например int main() { - person dylnmc; 08.08.2015
comment
Кстати, указывать все 20 '\ 0' необязательно. Вы можете просто написать: code char temp_str [20] = {'\ 0'}; code c будет автоматически заполнять каждый слот нулевым ограничителем, поскольку способ объявления массивов заключается в том, что если массив инициализируется меньшим количеством элементов, чем содержит массив, последний элемент будет заполнять оставшиеся элементы. - person alaniane; 20.01.2018
comment
Я считаю, что char temp_str[20] = {0} также заполняет весь массив символов нулевыми ограничителями. - person thuyein; 26.11.2018

person    schedule
comment
Для меня это приводит к перезаписи каждой строки следующей. См. Этот вопрос, основанный на приведенном выше ответе. . - person Cezar Cobuz; 08.01.2019
comment
Почему бросок (FILE*) fp? Разве fp не является уже FILE *, а также fopen() возвращает FILE *? - person Accountant م; 05.04.2019
comment
Если вас устраивает ограничение длины строк до определенной длины, это лучший ответ. В противном случае хорошей альтернативой будет использование getline. Я согласен, что FILE * бросок не нужен. - person theicfire; 17.10.2019
comment
Я удалил ненужное приведение, добавил переменную для длины буфера и изменил fp на filePointer для большей ясности. - person Rob; 06.01.2020

person    schedule
comment
С этим кодом возникают некоторые проблемы: fopen_s делает код непереносимым. printf будет искать спецификаторы формата и не печатать знаки процента и следующий символ (символы) как есть. Нулевые байты приведут к исчезновению всех символов в остальной части строки. (Не говорите мне, что нулевых байтов быть не может!) - person hagello; 17.03.2016
comment
И, кстати, проблему не вы решаете. OP описывает, что возвращаемое значение его функции исчезает. Я не думаю, что вы решаете эту проблему. - person hagello; 18.03.2016
comment
@Hartley Я знаю, что это старый комментарий, но я добавляю его, чтобы кто-то не прочитал его комментарий и не попытался освободить (строку) в цикле. Память для строки выделяется только один раз перед началом цикла, поэтому она должна быть освобождена только один раз после завершения цикла. Если вы попытаетесь освободить строку внутри цикла, вы получите неожиданный результат. В зависимости от того, как free () обрабатывает указатель. Если он просто освобождает память и оставляет указатель, указывающий на старое место, код может работать. Если он присвоит указателю другое значение, вы перезапишете другой раздел памяти. - person alaniane; 20.01.2018
comment
printf (строка) неверна! Не делай это. Это открывает ваш код для уязвимости строкового формата, где вы можете свободно читать / писать прямо в память через печатаемый материал. Если бы я поместил% n /% p в файл и снова указал указателем на адрес в памяти (в строке из файла), который я контролировал, я мог бы выполнить этот код. - person oxagast; 07.08.2018