c++ getline проблема с cin

 while (true)
 {
    int read = recvData(clientSocket, buf, sizeof(buf));
    if(read == SOCKET_ERROR)
    {
        cout<<"Connection with the server is lost. Do you want to exit?" << endl;
        string input;
        getline(cin,input);
        if(input == "yes")
            cout<<"test";
    }
    if(read == SHOW )
    {
        char *p = strtok(buf, " ");
        while (p) 
        {
            cout<<p<<endl;
            p = strtok(NULL, " ");
        }
    }

    else if(read == SEND )
    {
        UDPinfo* info = new UDPinfo;
        char *p = strtok(buf, " ");
        info->_IP = p;
        p = strtok(NULL, " ");
        info->_Port= p;
        info->_filePath = filePath;
        info->_UPDsock = UDPSocket;
        //Starting UDP send thread.
        _beginthread(UDPsendThread, 0, (void*)info);
    }
  }

в этом примере, если я получаю ошибку сокета, я любезно спрашиваю пользователя, хочет ли он выйти из программы, получив ввод. А затем сравнение этого ввода с каким-либо другим значением, в данном случае это строка «да». Но по какой-то причине, даже если я набираю «да», он пропускает проверку «если». и печатает "Соединение с сервером потеряно. Вы хотите выйти?" опять таки. Странно то, что если я снова наберу «да», все сработает. Я попытался исправить это с помощью cin.ignore(); и все такое прочее, а решения нет.


person akk kur    schedule 07.07.2011    source источник
comment
Этот код отлично работает, по крайней мере, на gcc. Вам нужно предоставить еще кое-что. Это getline внутри цикла?   -  person iammilind    schedule 07.07.2011
comment
извините, я забыл цикл while. Я редактирую вопрос.   -  person akk kur    schedule 07.07.2011


Ответы (4)


Что ж, у вас, кажется, нет никакого способа выйти из цикла, если вы введете yes, он просто напечатает test и продолжит свой веселый путь, пытаясь прочитать больше данных.

Если вы имеете в виду, что он не печатает test при первом вводе yes, вам нужно временно изменить:

getline(cin,input);

to:

getline (cin, input);
cout << "[" << input << "]" << endl;

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


Что бы это ни стоило, этот код (очень похожий на ваш) работает просто отлично:

#include <iostream>

int main (void) {
    while (true) {
        int read = -1;
        if (read == -1) {
            std::cout << "Connection lost, exit?" << std::endl;
            std::string input;
            getline (std::cin, input);
            std::cout << "[" << input << "]" << std::endl;
            if (input == "yes") {
                std::cout << "You entered 'yes'" << std::endl;
                break;
            }
        }
        std::cout << "Rest of loop" << std::endl;
    }
    return 0;
}

Вы также должны знать, что у вас есть зияющая дыра в вашей логике. Когда вы делаете strtok в своем буфере, он изменяет буфер и дает вам указатель на него (т.е. фактический буфер). Он не делает копию для вас.

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

Если вы должны использовать strtok для получения информации, убедитесь, что вы strdup ее и передаете копии в другой поток (не забудьте освободить их, когда закончите). Большинство реализаций C будут иметь strdup (хотя это не стандарт ISO). Если у вас нет, см. здесь.

Есть довольно большая вероятность, что эта дыра может быть причиной вашего странного поведения.

Лучший способ исправить это — изменить две строки:

    info->_IP = p;
    info->_Port= p;

в:

    info->_IP = strdup (p);
    info->_Port= strdup (p);

и не забудьте free оба этих выделения памяти в другом потоке, когда он закончит с ними (обычно я бы не рекомендовал операции типа malloc для С++, но, поскольку вы уже используете буферы символов, а не строки, это кажется самым простым решением) .

person paxdiablo    schedule 07.07.2011
comment
Да, точно. это не тест печати, когда я в первый раз ввожу да. он также пропускает опубликованный вами оператор cout. - person akk kur; 07.07.2011
comment
что бы я ни пытался, это всегда пропускает следующую строку после getline в первый раз. - person akk kur; 07.07.2011
comment
Это действительно странно. это точно такой же код, как и у меня, но у меня почему-то не работает. - person akk kur; 07.07.2011
comment
Помните, что стандартный вывод буферизован. Таким образом, просто запись теста в cout не обязательно означает, что именно тогда он будет записан на терминал. Либо сбросить stdout после печати, либо вместо этого использовать stderr (cerr), поскольку он обычно не буферизуется. - person Sodved; 07.07.2011
comment
@Sodved, да, cout буферизуется. Однако ОП заявил, что connection lost печатается снова без промежуточного test. Никакая буферизация не приведет к этому :-) - person paxdiablo; 07.07.2011

Возможно, попробуйте:

cin.clear(); 
cin.ignore(INT_MAX,'\n');

Потому что похоже, что у вас может быть \n в буфере cin (возможно, из предыдущей операции cin). Этот код выше должен очистить cin, готовый для getline().

person fileoffset    schedule 07.07.2011
comment
Я перепробовал все возможные комбинации cin.ignore, cin.clear, fflush, которые все еще не работают. - person akk kur; 07.07.2011
comment
я не думаю, что это могло быть из-за буфера ... если бы это было так, он бы не запрашивал его для ввода ... он сразу извлекал бы любой символ-разделитель ... и цикл снова запускался бы с очищенным потоком cin ... - person jemmanuel; 07.07.2011

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

person Sharath    schedule 07.07.2011
comment
Хорошо, теперь понятно. Вы не выходите из цикла, даже если ответ положительный. Используйте break или exit(0), если ответ положительный. - person Sharath; 07.07.2011
comment
Нет, это не проблема. проблема в том, что бы я ни пробовал, она всегда пропускает следующую строку после getline в первый раз. Поэтому, даже если я наберу if(input == yes) break; он пропускает перерыв; - person akk kur; 07.07.2011

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

string input;
getline(cin,input);
if (input == "yes")
    cout<<"test";

Пожалуйста, рассмотрите возможность изменения этого на:

string input;
if (getline(std::cin, input))
    std::cerr << "input [" << input.size() << "] '" << input << "'\n";
else
    std::cerr << "getline() was unable to read a string from std::cin\n";

Тогда расскажи нам, что ты видишь...

person Tony Delroy    schedule 07.07.2011