Мусор добавляется к выводу при чтении значений из файла - PullRequest
0 голосов
/ 14 февраля 2011

Я новичок в C ++ file io, поэтому на днях я решил написать небольшую программу, которая просто считывает строку в кодировке UTF-8 и парное число с плавающей точкой из двоичного файла.Шаблон является плавающей строкой без каких-либо дополнительных данных или расстояния между парами. РЕДАКТИРОВАТЬ Я пересмотрел код на основе нескольких ответов.Однако вывод остается прежним («RoommateAp 0»);

string readString (ifstream* file)
{
    //Get the length of the upcoming string
    uint16_t stringSize = 0;
    file->read(reinterpret_cast<char*>(&stringSize), sizeof(char) * 2);

    //Now that we know how long buffer should be, initialize it
    char* buffer = new char[stringSize + 1];
    buffer[stringSize] = '\0';

    //Read in a number of chars equal to stringSize
    file->read(buffer, stringSize);
    //Build a string out of the data
    string result = buffer;

    delete[] buffer;
    return result;
}

float readFloat (ifstream* file)
{
    float buffer = 0;
    file->read(reinterpret_cast<char*>(&buffer), sizeof(float));
    return buffer;
}

int main()
{
    //Create new file that's open for reading
    ifstream file("movies.dat", ios::in|ios::binary);
    //Make sure the file is open before starting to read
    if (file.is_open())
    {
        while (!file.eof())
        {
            cout << readString(&file) << endl;
            cout << readFloat(&file)  << endl;
        }
        file.close();
    }
    else
    {
        cout << "Unable to open file" << endl;
    }
}

и выборка данных из файла (места для удобства чтения):

000C 54686520526F6F6D6D617465 41700000

Как можновидите, первые два байта - это длина строки (в нашем случае 12), за которой следуют двенадцать символов (что означает «сосед по комнате»), а последние четыре байта являются плавающими.

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

Ответы [ 4 ]

5 голосов
/ 14 февраля 2011

Есть как минимум две проблемы. Сначала строка:

file->read(reinterpret_cast<char*>(stringSize), sizeof(char) * 2);

Вероятно, следует взять адрес stringSize:

file->read(reinterpret_cast<char*>(&stringSize), sizeof(stringSize));

Вторая строка:

char* buffer = new char[stringSize];

Не выделяет достаточно памяти, так как не учитывает терминатор NUL. Этот код должен сделать что-то вроде:

//Now that we know how long buffer should be, initialize it
char* buffer = new char[stringSize + 1];
//Read in a number of chars equal to stringSize
file->read(buffer, stringSize);
buffer[stringSize] = '\0';

Наконец, строка:

return static_cast<string>(buffer);

Не удается delete[] буфер после создания из него string, что приведет к утечке памяти.

Также обратите внимание, что поддержка UTF-8 в std::string довольно слабая из коробки. К счастью, есть решения .

2 голосов
/ 14 февраля 2011

Ваш код имеет несколько серьезных проблем:

  1. file->read(reinterpret_cast<char*>(stringSize), sizeof(char) * 2);

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

  2. char* buffer = new char[stringSize];

    Это выделяет массив символов, но никто не собирается его освобождать. использование std::vector<char> buffer(stringSize); вместо этого, чтобы память управление будет сделано правильно для вас. Для получения адреса буфера вы можете использовать &buffer[0].

  3. return static_cast<string>(buffer);

    Что вам, вероятно, нужно, так это строковый конструктор, который принимает указатели на первые и последние последние символы. Другими словами: return std::string(&buffer[0], &buffer[0]+stringSize);

0 голосов
/ 14 февраля 2011

Есть некоторые проблемы с вашим кодом.

Вы утверждаете, что размер строки определяется 4 байтами, это означает, что вы должны использовать uint32_t, а не uint16_t.

Вы не освобождаете память, используемую при выделении строкового буфера.

string readString(std::ifstream* file)
{
    // Get the length of the upcoming string.
    // The length of the string is specified with 4 bytes: use uint32_t, not uint16_t
    uint32_t stringSize = 0;    
    file->read(reinterpret_cast<char*>(&stringSize), sizeof(uint32_t));

    // Now that we know how long buffer should be, initialize it
    char* buffer = new char[stringSize + 1];
    buffer[stringSize] = '\0'; // null terminate the string

    //Read in a number of chars equal to stringSize
    file->read(buffer, stringSize);
    string result = buffer;

    delete[] buffer;
    return result;
}
0 голосов
/ 14 февраля 2011

Вы приведете к массиву символов. Включает ли номер размера строки в файле пространство для нулевого символа? Если нет, возможно, вы запускаете конец массива символов и зацикливаетесь на запись cout.

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