Почему fread() в c читает лишние символы #newlines?

В то время как я пытаюсь скопировать файл в строку с помощью fread (), я получаю из файла дополнительные символы, которые в точности равны количеству новых строк. Вот мой код:

#include <stdio.h>
#include <stdlib.h>
#define LEN 5000000

int main()
{
   char *in = (char*) malloc(LEN);
   FILE *f=fopen("in.txt","r");
   fread(in,5000000,1,f);
   printf("%ld\n", ftell(f)); 
   in[ftell(f)]=0;
   int l;
   for(l=0;true;l++)
   {
      if(in[l]<10)
        break;
      printf("%d ",in[l]);
   }
   printf("\n");
}

Вход для этой программы:

1  
2  
<newline>

ссылка для ввода: https://paste.fedoraproject.org/388281/46780193/
Для вывода я печатаю значения символов в ASCII:

6  
49 10 50 10 13 10  

если ввод:

1  
2  
3  
<newline>  

ссылка для ввода: https://paste.fedoraproject.org/388280/
тогда вывод:

9  
49 10 50 10 51 10 51 13 10  

Я видел несколько других тестовых случаев. В каждом тестовом примере дополнительное количество символов всегда равно количеству новых строк.
У меня есть несколько вопросов:
-Почему шаблон такой?
-Как это связано с тем, что новая строка занимает 2 байта в Windows?
-Как избавиться от этих лишних персонажей?
Я гуглил подобные вопросы, но не нашел ответа. Пожалуйста, кто-нибудь объяснит?

3 ответа

Решение

Вызов ftell для потока, открытого в текстовом режиме, как, например, в вашем примере, не имеет смысла1.

Использование функции fread не правильно, аргументы size и count переключаются. Это означает, что чтение всегда частичное, поскольку в вашем файле нет 5000000 символов. При этом значения элементов в массиве после вызова имеют неопределенные2 значения. (Логическим элементом в вашем случае является отдельный элемент размером 5000000.)

Результаты, которые вы видите, не имеют смысла. Чтение неопределенных значений может вызвать неопределенное поведение.

Правильный способ чтения вашего файла - передать правильные параметры в fread и использовать возвращаемое значение, чтобы определить количество успешно прочитанных символов:

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

int main()
{
    unsigned char in[500] = { 0 } ;
    FILE *f=fopen("in.txt","r");
    assert( f ) ;

    const size_t read = fread(in,1,500,f);
    printf( "read: %zu\n" , read );

    for( size_t index = 0 ; index < read ; index++ )
    {
        printf( "%hhu " , in[index] );
    }

    fclose( f );
}

Используя эту правильную программу, когда файл имеет содержимое (точки не являются частью файла):

.
1
2
3

.

прочтет и распечатает правильные значения:

read: 7
49 10 50 10 51 10 10

Один символ новой строки, представленный3 значением 10, для каждого номера, и дополнительный в конце.


1 (Цитируется из: ISO:IEC 9899:201x 7.21.9.4 Функция ftell 2)
Для текстового потока его указатель положения файла содержит неопределенную информацию, используемую функцией fseek для возврата указателя положения файла для потока в его положение во время вызова ftell; разница между двумя такими возвращаемыми значениями не обязательно является значимым показателем количества написанных или прочитанных символов.

2 (Цитируется из: ISO:IEC 9899:201x 7.21.8.1 Функция Fread 2)
Если частичный элемент читается, его значение является неопределенным.

3 В файлах Windows новая строка представлена ​​двумя символами: 13, 10. Возврат каретки и перевод строки. Но при чтении файла в текстовом режиме новая строка всегда является просто символом перевода строки: 10. Вы видели символ 13, потому что поведение вашей программы не имело смысла. Если вы (правильно) открыли и прочитали файл в двоичном режиме, вы увидите новую строку, представленную обоими символами.

Я не знаю, как это повлияло на ход программы, но я страдал от той же проблемы, пока не изменил режим доступа к файлу с "r"к "rb", хотя это все еще был обычный текстовый файл.

Так; в дополнение к совету пользователя @2501 (принятый ответ) это следует учитывать, и следующие строки

      FILE* ptrFile = fopen("fileName.txt", "r");
fread(in, 500, 1, ptrFile);

следует исправить, как

      FILE* ptrFile = fopen("fileName.txt", "rb");
fread(in, 1L, 500, ptrFile);

Если вы используете Windows и отредактировали файл в.txt с помощью какого-либо редактора, который прикрепляет CR-LF (Carriage-Return, LINE-FEED) ((ASCII) 13, 10) к каждой новой строке, это обязательно произойдет. Попробуйте написать in.txt программой, а затем прочитайте ее. Это будет делать, как ожидалось. Или используйте редактор, который не прикрепляет CR-LF к eol (конец строки). извините, я не знаю такого редактора [но некоторые редакторы Linux будут работать.].

Другие вопросы по тегам