Вопрос

В следующем коде C++ я понял, что gcount() возвращал большее количество, чем мне хотелось, потому что getline() потребляет последний символ новой строки, но не отправляет его во входной поток.

Однако чего я до сих пор не понимаю, так это вывода программы.Почему для ввода «Тест » я получаю «est »?Почему моя ошибка влияет на первый символ строки, а не добавлять нежелательный мусор в конец?И почему вывод программы не совпадает с тем, как строка выглядит в отладчике («Test », как я и ожидал)?

#include <fstream>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main()
{
    const int bufferSize = 1024;
    ifstream input( "test.txt", ios::in | ios::binary );

    vector<char> vecBuffer( bufferSize );
    input.getline( &vecBuffer[0], bufferSize );
    string strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() );
    cout << strResult << "\n";

    return 0;
}
Это было полезно?

Решение

Я также продублировал этот результат, Windows Vista, Visual Studio 2005 SP2.

Когда я выясню, что, черт возьми, происходит, я обновлю этот пост.

edit . Хорошо, поехали. Проблема (и разные результаты, которые люди получают) от \ r. Что происходит, вы вызываете input.getline и помещаете результат в vecBuffer. Функция getline удаляет \ n, но оставляет \ r на месте.

Затем вы переносите vecBuffer в строковую переменную, но используете функцию gcount из input, что означает, что вы получите один символ слишком много, потому что входная переменная все еще содержит \ n, а vecBuffer - нет.

Результирующий strResult:

-       strResult   "Test"
        [0] 84 'T'  char
        [1] 101 'e' char
        [2] 115 's' char
        [3] 116 't' char
        [4] 13 '␍'  char
        [5] 0   char

Итак, "Тест" печатается с последующим возвратом каретки (переводит курсор назад в начало строки), нулевым символом (перезаписывая T) и, наконец, \ n, что правильно ставит курсор на новую строку.

Таким образом, вы должны либо удалить \ r, либо написать функцию, которая получает длину строки непосредственно из vecBuffer, проверяя наличие нулевых символов.

Другие советы

Я продублировал проблему Томми в системе Windows XP Pro Service Pack 2 с кодом, скомпилированным с использованием Visual Studio 2005 SP2 (на самом деле там написано «Версия 8.0.50727.879»), созданным как консольный проект.

Если мой файл test.txt содержит только «Test» и CR, при запуске программа выдает «est» (обратите внимание на начальный пробел).

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


Обновлять:Немного поиграв с этим, я уверен, что именно это и происходит.Если вы посмотрите на strResult в отладчике, вы увидите, что в конце он скопировал десятичное значение 13.Это CR, который в Windows-land — это « », а везде — «возврат к началу строки».Если вместо этого я изменю ваш конструктор на следующее:

строка strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() - 1);

... (чтобы CR не копировался), затем он печатает «Тест», как и следовало ожидать.

Я почти уверен, что буква T на самом деле записывается, а затем перезаписывается.Запуск той же программы в окне rxvt (cygwin) дает ожидаемый результат.Вы можете сделать пару вещей.Если вы избавитесь от ios::binary в своем открытом файле, он автоматически преобразует в , и все будет работать так, как вы ожидаете.

Вы также можете открыть свой текстовый файл в двоичном редакторе, щелкнув маленькую стрелку вниз на кнопке открытия диалогового окна открытия файла и выбрав «Открыть с помощью...->Двоичный редактор».Это позволит вам просмотреть файл и убедиться, что он действительно имеет , а не только .

Редактировать:Я перенаправил вывод в файл, и он пишет:

Test\r\0\r\n

Причина, по которой вы получаете \0, заключается в том, что gcount возвращает 6 (6 символов были удалены из потока), но последний разделитель не копируется в буфер, вместо этого копируется «\0».когда вы создаете строку, вы фактически указываете ей включить «\0».std::string не имеет проблем со встроенным 0 и выводит его по запросу.Некоторые оболочки, по-видимому, выводят пустой символ и перезаписывают букву T, в то время как другие ничего не делают, и вывод выглядит нормально, но, вероятно, все равно неверен, поскольку в него встроен символ '\0'.

cout << strResult.c_str() << "\n";

Изменение последней строки на это остановится на \0 и также получит ожидаемый результат.

Я протестировал ваш код с помощью Visual Studio 2005 с пакетом обновления 2 (SP2) на Windows XP Pro с пакетом обновления 3 (32-разрядная версия), и все работает нормально.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top