Хобрук: Ваш путь к мастерству в программировании

Строка становится мусором в конце после преобразования в c_str()

Это домашнее задание, просто для всех, кто хочет знать.

Я пишу словарь-переводчик (английский -> немецкий и наоборот) и должен сохранять все, что делает пользователь, в файл. Достаточно просто.

Это код:

std::string file_name(user_name + ".reg");
std::ifstream file(file_name.c_str(), std::ios::binary | std::ios::ate);
// At this point, we have already verified the file exists. This shouldn't ever throw!
// Possible scenario:  user deletes file between calls.
assert( file.is_open() );

// Get the length of the file and reset the seek.
size_t length = file.tellg();
file.seekg(0, std::ios::beg);

// Create and write to the buffer.
char *buffer = new char[length];
file.read(buffer, length);
file.close();

// Find the last comma, after which comes the current dictionary.
std::string strBuffer = buffer;
size_t position = strBuffer.find_last_of(',') + 1;
curr_dict_ = strBuffer.substr(position);

// Start the trainer; import the dictionary.
trainer_.reset( new Trainer(curr_dict_.c_str()) );

Проблема, по-видимому, в curr_dict_, который должен хранить значение моего словаря. Например, у моего учителя есть один файл словаря с именем 10WS_PG2_P4_de_en_gefuehle.txt. Trainer импортирует все содержимое файла словаря следующим образом:

std::string s_word_de;
std::string s_word_en;
std::string s_discard;
std::string s_count;
int i_word;

std::ifstream in(dictionaryDescriptor);

if( in.is_open() )
{
    getline(in, s_discard); // Discard first line.
    while( in >> i_word &&
        getline(in, s_word_de, '<') &&
        getline(in, s_discard, '>') &&
        getline(in, s_word_en, '(') &&
        getline(in, s_count, ')') )
    {   
        dict_.push_back(NumPair(s_word_de.c_str(), s_word_en.c_str(), Utility::lexical_cast<int, std::string>(s_count)));
    }
}
else
    std::cout << dictionaryDescriptor;

И одна строка написана так

1             überglücklich <-> blissful                     (0) 

Curr_dict_ вроде нормально импортируется, но при выводе я получаю целую кучу ненужных символов в конце файла!

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

Файл реестра, который верхний код читает для словаря:

Кристиан.reg

Christian,abc123,10WS_PG2_P4_de_en_gefuehle.txt

Что я делаю неправильно?

07.12.2010

  • Утечка этого заявления: char *buffer = new char[length]; предпочитает std::vector<char> buffer(length); 07.12.2010
  • Или еще лучше, не читайте в буфер символов, чтение непосредственно в строку. (В качестве бонуса это также предотвратило бы эту конкретную ошибку…) 07.12.2010
  • @Martin: Спасибо, исправлено. @Rudolph: выглядит довольно мило; Я постараюсь это интегрировать. 07.12.2010

Ответы:


1

я бы сделал так:

std::string strBuffer(length, '\0');
myread(file, &strBuffer[read], length); // guranteed to read length bytes from file into buffer

Полностью избегайте необходимости в промежуточном буфере.

07.12.2010
  • -1: полагаться на внутренности реализации std::string. Любой std::string, реализованный несмежным хранилищем, потерпит неудачу. См. stackoverflow.com/questions/ 760790/ 08.12.2010
  • @Zan Lynx: позволю себе не согласиться. 1) C++03 требует, чтобы &str[0] возвращал указатель на непрерывное хранение 2) Чтение не повлияет на длину строки (поскольку строка хранит длину отдельно от строковых данных (т.е. она не в зависимости от того, завершается ли строка '\0')). Причина в том, что data() c_str() и operator[] сделаны таким образом, чтобы позволить (но не требовать) реализации предоставить версию строки с подсчетом ссылок. Поэтому, пожалуйста, удалите свой ошибочный -1. 08.12.2010
  • Очень хорошо, operator[] вернет непрерывное хранилище. Тем не менее, длина все еще неправильная. Он будет установлен на длину файла, но нет гарантии, что чтение действительно прочитает столько данных. 08.12.2010
  • Я предполагаю, что пользователь знает, что чтение может вернуться до завершения и, следовательно, потребуется цикл для чтения всего файла. Это другая проблема. Код примера — это всего лишь код (как и приведенный выше), который также не выполняет проверку ошибок, и, таким образом, исходный код обеспечивает те же самые те же функциональные возможности, что и OP. Но просто чтобы быть педантичным, я добавил необходимый цикл, чтобы действительно гарантировать, что файл будет прочитан в буфер. 08.12.2010
  • Следует также учитывать случай, когда содержимое файла было перезаписано между получением длины файла и чтением данных. 09.12.2010

  • 2

    функция read (как в строке file.read(buffer, length);) не обнуляет символьный буфер. Вам нужно будет сделать это вручную (выделить еще один символ и поместить nul в gcount позицию после reading).

    07.12.2010
  • Так что на самом деле я еще не использовал gcount, но, судя по тому, что мне говорит cplusplus, он просто возвращает позицию последнего прочитанного символа. Сладкий! Как мне использовать это, чтобы прочитать нулевой терминатор в char *? 07.12.2010
  • вам нужно будет ввести его вручную (например, что-то вроде buffer[file.gcount()] = 0. 07.12.2010
  • именно поэтому вам нужно будет выделить один дополнительный символ (при использовании буфера символов или векторного подхода). 07.12.2010
  • Новые материалы

    Библиотеки PyTorch и Python для машинного обучения: приложения в здравоохранении с обнимающим лицом…
    В сфере машинного обучения Python выделяется благодаря своей универсальности и набору предлагаемых библиотек. Развитие машинного обучения в здравоохранении можно частично объяснить простотой и..

    «Что за…» очень хорошо представляет мое выражение лица после того, как я увидел это!
    «Что за…» очень хорошо представляет мое выражение лица после того, как я увидел это!

    5 вещей, которые я сделал, чтобы стать профессиональным разработчиком JavaScript
    Чтобы стать профессиональным JS-разработчиком: 1. Практикуйтесь в рутине, 2. Работайте над проектами, 3. Придерживайтесь одного языка, 4. Наблюдайте за чужим кодом, 5. Будьте последовательны..

    От теории к практике: пошаговое руководство по реализации наивного Байеса
    Вы когда-нибудь застревали в проекте классификации, не зная, как точно предсказать результаты для ваших данных? Вы искали более простой и интуитивно понятный алгоритм, который поможет вам достичь..

    #093 | Моделирование вспышки эпидемии с помощью JavaScript — Часть 3
    TLDR: Я сделал симуляцию вспышки эпидемии, в которую можно поиграть здесь . Мой холст, моя сцена Мой HTML — это всего лишь один div с классом stage, и вот как я настроил на нем свой объект..

    numberToString.js (8kyu 16)
    Алгоритм кодовых войн Проблема Нам нужна функция, которая может преобразовать число в строку. 숫자를 문자열로 변환하는 함수를 작성해라. Решение 01 function numberToString(n) { return n.toString(); }..

    Лучшие практики для быстрого изучения языка программирования
    Изучение языка программирования может быть сложной задачей, но при правильном подходе определенно возможно быстро выучить язык программирования. Хорошее понимание языка программирования может..