Есть ли завершающий символ (НЕ EOF) в конце файла, который будет читаться как последний символ? - PullRequest
1 голос
/ 28 апреля 2020

Я пытался прочитать файл в строку со следующим кодом. Я назначил 5 байтов для char *a и фактически прочитал файл с более чем 5 символами. Тем не менее, выходные данные по-прежнему печатают правильное содержимое файла без какого-либо мусорного значения или пропущенного значения.

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

#define INPUT_SIZE 5

int main() {

        char *a = malloc(INPUT_SIZE);
        FILE *fp = fopen("text", "r");
        if (fp == NULL) {
                perror("Unable to open the file");
        }

        char *b = a;
        char c;
        int i = 0;
        while ((c = fgetc(fp)) != EOF) {
                *b++ = c;
        }

        printf("%s", a);
        free(a);
        fclose(fp);
        return 0;
}

Входной файл

abc
def
g

И выходные данные в точности совпадают с входными file.
Так как обычно в конце char * должен стоять '\ 0', чтобы показать, где конец строки. Но в этом случае нет явного '\ 0' в char *a. Поэтому мне интересно, есть ли в конце файла '\ 0', который был прочитан как последний символ?

1 Ответ

2 голосов
/ 28 апреля 2020

Это ситуация, когда результаты могут выглядеть правильно, но вам просто «везет» с выходом вашей программы.

Во-первых, когда вы вызываете malloc(INPUT_SIZE), ваша реализация lib c обычно не выделяет только 5 байтов, но фактически несколько кратных 8 байтов (например, 16 или 32, зависит от платформы [см. неожиданный вывод размера, выделенного mallo c в C). Эти дополнительные данные содержат возможные байты заполнения после ваших данных и метаданные до и после запрошенного вами блока. Это сделано в целях выравнивания и учета, но выгода в том, что вы получаете больше, чем просите, когда звоните malloc.

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

Во-вторых, поведение нулевого терминатора, которое вы видите, - это просто удача и получение обнуленной части память от malloc. Это не всегда гарантируется, и в следующий раз, когда вы запустите программу, ваш буфер может вернуться из malloc, заполненного случайными значениями, вместо 0. Если вы хотите предварительно обнуленную память, используйте calloc.

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

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