fread сохраняет случайные символы в буфере

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

#include <iostream>

using namespace std;

void ReadFile(char* filename,char*& buffer)
{
    FILE *file = fopen(filename,"rb");

    fseek(file,0,SEEK_END);
    int size = ftell(file);
    rewind(file);

    buffer = new char[size];
    memset(buffer,0,size);

    int r = fread(buffer,1,size,file);
    cout << buffer;

    fclose(file);
}

int main()
{
    char* buffer;
    ReadFile("test.txt",buffer);
    cin.get();
}

Скажем, в данном случае «размер» равен 50. по какой-то причине размер буфера достигает 55 или 56 после вызова fread. Я очистил буфер перед его использованием и попробовал вывести его, все в норме (он пуст). Сразу после вызова fread буфер как-то становится больше и заполняется случайными символами. Я открыл текстовый файл в шестнадцатеричном редакторе, чтобы убедиться, что я ничего не вижу, но нет. Размер файла 50 байт. fread возвращает количество прочитанных байтов, в данном случае возвращается в 'r', 'r' - это то, что должно быть. так откуда мать эти байты берутся?

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

Я хоть убей не могу понять, как это происходит.

Кроме того, прежде чем кто-либо предложит мне простое решение, я уже знаю, что могу просто сделать buffer [r] = '\ 0' и больше не выводить случайные символы, но я бы лучше знал, ПОЧЕМУ это происходит.


person David    schedule 17.07.2013    source источник
comment
Вы можете решить эту проблему и проблему с утечкой памяти, используя вместо этого std::string buffer(size);.   -  person Casey    schedule 17.07.2013
comment
Функция чтения файла низкого уровня не завершает массив.   -  person Grijesh Chauhan    schedule 17.07.2013
comment
Решите, какой язык вы используете. fread() - это C. fstream - это C ++. Не смешивайте их. Кроме того, вы abusing namespace std;, чего не стоит.   -  person    schedule 17.07.2013


Ответы (3)


Оператор cout << в char* ожидает строки C, поэтому вам нужно завершить buffer:

int size = ftell(file)+1; // Leave space for null terminator
...
int r = fread(buffer,1,size-1,file); 
buffer[r] = '\0';
cout << buffer;

Дополнительные символы, которые вы видите, - это случайные данные в адресах памяти после конца вашего buffer. operator << не знает, что строка закончилась, поэтому продолжает печать, пока не найдет первый '\0' байт.

person Sergey Kalinichenko    schedule 17.07.2013
comment
Спасибо, мне почему-то показалось, что fread увеличил размер буфера. знак равно - person David; 18.07.2013
comment
Да, я сделал. Спасибо! - person David; 18.07.2013

Вы, наверное, просто забыли об окончании буфера нулем. Вместо этого используйте cout.write и укажите длину буфера:

Добавляем немного обработки ошибок (не достаточно, но начало), пропущенные включает и операторы using: http://coliru.stacked-crooked.com/view?id=8bc4f3b7111554c705de96450d806104-f674c1a6d04c632b71a62362c0ccfcfc

#include <iostream>
#include <string>
#include <vector>
#include <cstring>

using namespace std;

void ReadFile(const char* filename,char*& buffer)
{
    FILE *file = fopen(filename,"rb");

    if (!file)
         return;

    fseek(file,0,SEEK_END);
    int size = ftell(file);
    rewind(file);

    buffer = new char[size];
    memset(buffer,0,size);

    int r = fread(buffer,1,size,file);
    cout.write(buffer, r);

    fclose(file);
}

int main()
{
    char* buffer;
    ReadFile("test.txt",buffer);
    cin.get();
}
person sehe    schedule 17.07.2013

На самом деле cout будет печатать строку до тех пор, пока она не получит ни одного символа NULL. Это означает, что для завершения требуется NULL.

Но присвоение NULL не всегда хорошее решение. Ваши данные могут быть двоичными, тогда cout будет печатать только вывод до NULL char. Я имею в виду, что двоичные данные могут быть чем угодно, и это также может быть нечитаемый символ. и cout будет рассматривать его как NULL char. Вот почему всегда безопасно использовать цикл for до длины строки или вашего набора данных.

len = strlen(buffer)
for (int i = 0; i < len; i++)
     printf("%c", buffer[i])     

// или вы можете использовать FILE * fp; for (int i = 0; i ‹len; i ++) fprintf (fp,"% c ", buffer [i]); еще один хороший подход - использовать fwrite.

person Mohiul Alam    schedule 17.07.2013