Системный вызов read не обнаруживает конец файла

Я пытаюсь создать функцию, которая читает весь файл, используя определенный размер чтения, который может измениться в любое время, но системный вызов read не сохраняет символы в буфере должным образом, пока я пытаюсь печатать только до конец файла, как это:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

# define READ_SIZE (42)

int main(int argc, char **argv)
 {
   int fd;
   int rd;
   char *buffer;

   buffer = malloc(READ_SIZE);
   fd = open(argv[1], O_RDONLY);
   while ((rd = read(fd, buffer, READ_SIZE)) > 0)
    {
       printf("%s", buffer);
    }
    return (0);
 }

Это файл, который я пытаюсь прочитать:

test1234
test123
test1
test2
test3
test4
test

Это вывод моей программы:

test123
test12
test1
test2
test3
test4
testest123
test12
test1
test2
test3
test4
tes

Я могу использовать только mallocи read, чтобы справиться с этим, open предназначен только для тестирования, и я не понимаю, почему он это делает, обычно read возвращает количество байтов, прочитанных в этом файле, и 0, если он достигает конца файла, так что это немного странно видеть это.

2 ответа

Решение

Помимо очень элегантного решения, предоставленного ответом chux, вы также можете просто завершить буфер (и с этим только сделать его C-"строкой") перед печатью:

while ((rd = read(fd, buffer, READ_SIZE-1)) > 0) /* read one less, to have a spare 
                                                    char available for the `0`-terminator. */
{
  buffer[rd] = '\0';
  printf("'%s'", buffer);
}

В печати массива символов отсутствует нулевой символ. Это UB с "%s",

printf("%s", buffer);  // bad

Чтобы ограничить печать массива символов без нулевого символа, используйте модификатор точности. Это напечатает массив символов с таким количеством символов или нулевым символом - который когда-либо будет первым.

// printf("%s", buffer);
printf("%.*s", rd, buffer);

Подсказка по отладке: печатайте текст с часовыми, чтобы четко указать результат каждого отпечатка.

printf("<%.*s>\n", rd, buffer);
Другие вопросы по тегам