Неожиданное поведение getline() с ifstream

Для упрощения я пытаюсь прочитать содержимое CSV-файла, используя класс ifstream и его функцию-член getline(). Вот этот CSV-файл:

1,2,3
4,5,6

И код:

#include <iostream>
#include <typeinfo>
#include <fstream>

using namespace std;

int main() {
    char csvLoc[] = "/the_CSV_file_localization/";
    ifstream csvFile;
    csvFile.open(csvLoc, ifstream::in);
    char pStock[5]; //we use a 5-char array just to get rid of unexpected 
                    //size problems, even though each number is of size 1
    int i =1; //this will be helpful for the diagnostic
    while(csvFile.eof() == 0) {
        csvFile.getline(pStock,5,',');
        cout << "Iteration number " << i << endl;
        cout << *pStock<<endl;
        i++;
    }
    return 0;
}

Я ожидаю, что все числа будут прочитаны, поскольку предполагается, что getline берет то, что написано с момента последнего чтения, и останавливается при встрече с ',' или '\n'.

Но, оказывается, он читает все хорошо, КРОМЕ '4', т.е. первого числа второй строки (ср. консоль):

Iteration number 1
1
Iteration number 2
2
Iteration number 3
3
Iteration number 4
5
Iteration number 5
6

Таким образом, мой вопрос: что делает это «4» после (я думаю) «\ n» настолько конкретным, что getline даже не пытается его учитывать?

(Спасибо !)


person Kamixave    schedule 18.08.2010    source источник


Ответы (3)


Вы читаете значения, разделенные запятыми, поэтому последовательно вы читаете: 1, 2, 3\n4, 5, 6.

Затем вы каждый раз печатаете первый символ массива: т. е. 1, 2, 3, 5, 6.

Чего вы ожидали?

Кстати, ваш чек на eof лежит не там. Вы должны проверить, успешно ли выполнен вызов getline. В вашем конкретном случае в настоящее время это не имеет значения, потому что getline что-то читает и запускает EOF за одно действие, но в целом это может привести к сбою, ничего не прочитав, и ваш текущий цикл все равно будет обрабатывать pStock, как если бы он был успешно повторно заполнен.

В общем, лучше было бы что-то вроде этого:

while (csvFile.getline(pStock,5,',')) {
    cout << "Iteration number " << i << endl;
    cout << *pStock<<endl;
    i++;
}
person CB Bailey    schedule 18.08.2010
comment
Чего вы ожидали? На самом деле, если я взгляну на cplusplus.com/reference/iostream/istream/getline мне кажется, что getline действует с '\n' так же, как и с указанным разделителем. А именно, просто останавливаться для чтения при встрече (таким образом, как и в случае с 1,2, он останавливается перед 2, с 3\n4 он должен был останавливаться перед 4). Но я думаю, что это не так, я не все понимаю хорошо! Спасибо за ответ. - person Kamixave; 18.08.2010
comment
@Kamixave: По моему чтению cplusplus.com, я не думаю, что это неправильно. \n — это просто разделитель по умолчанию, если вы его не указали. Если вы поставляете один, он используется вместо этого (не так хорошо). - person CB Bailey; 18.08.2010
comment
@Charles Bailey: Не могли бы вы добавить пример std::getline(‹stream›,‹string›). В этой версии возможно переполнение буфера. - person Martin York; 18.08.2010
comment
@Charles: Да, действительно, ты прав, я не понял это хорошо. Спасибо :) - person Kamixave; 18.08.2010
comment
@Martin York: Как эта версия допускает переполнение буфера? (Я знаю, что существуют магические числа, что не является идеальной практикой, но я не вижу опасности немедленного переполнения буфера.) - person CB Bailey; 18.08.2010
comment
@Charles: извините, неправильно. Он может не прочитать все целое число в буфер, если файл содержит 6-значное число. Я вижу, что в настоящее время каждое число должно быть одной цифрой. Но я уверен, что это не задокументировано во входном файле, и потребуется всего одно небольшое неправильное редактирование файла, чтобы вызвать неправильное поведение. Лучше использовать защитное программирование и читать каждое полное число независимо от его размера. - person Martin York; 18.08.2010

Насколько я знаю, если вы используете параметр терминатора, getline() читается до тех пор, пока не найдет разделитель. Это означает, что в вашем случае он прочитал

3\n4

в массив pSock, но вы печатаете только первый символ, поэтому вы получаете только 3.

person jpalecek    schedule 18.08.2010

проблема с вашим кодом заключается в том, что getline, когда указан разделитель, ',' в вашем случае использует его и игнорирует разделитель по умолчанию '\n'. Если вы хотите отсканировать этот файл, вы можете использовать функцию токенизации.

person Andrea Monelli    schedule 18.08.2010