Знание начального пользовательского ввода после назначения строки getline - PullRequest
1 голос
/ 07 марта 2012

Вот моя функция C ++:

void SetUserName(char username[])
{
    cout << "\nPlease enter a username.\n"
         << "Must not be longer than 12 characters.\n>> ";

    cin.getline(username, MAX) // MAX is globally defined

    while(strlen(username) > MAX)
    {
        cout << "\nUsername too long, try again.\n>> ";
        cin.getline(username, MAX);
    }
}

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

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

Редактировать: Использование cstring здесь является требованием. Я уже знаю, как легко работать со строками.

Редактировать # 2: Это был определенно плодотворный вопрос для меня, поскольку он многому меня научил. Окончательный код: http://pastie.org/3537894

Ответы [ 4 ]

4 голосов
/ 07 марта 2012

Завершенные строки в стиле C довольно сложны в работе, и почти во всех случаях я бы рекомендовал вместо них C ++ std::string.Однако, поскольку вы говорите, что конкретно хотите прочитать завершенную строку в массив, вот один из способов сделать это.

Помните, что размер массива должен быть MAX+1, поэтому есть место для MAX символовза ним следует терминатор.

istream::getline устанавливает флаг потоков failbit, если строка слишком длинная;Вы можете проверить это после прочтения.Если была извлечена только частичная строка, и вы хотите перейти к следующей строке, то вам нужно очистить состояние ошибки и игнорировать оставшуюся строку.

while (!std::cin.getline(buffer, MAX+1)) {
    std::cout << "Too long\n";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
3 голосов
/ 07 марта 2012

Используйте правильный C ++ (в частности, string s и свободную функцию getline):

#include <string>
#include <iostream>

std::string line;
while (std::getline(std::cin, line))
{
    if (line.length() > 12)
    {
        // error, line too long

        continue;
    }

    // process line
}
3 голосов
/ 07 марта 2012

Если вы хотите выяснить, является ли std::istream::getline() считанным массивом, полным символов, как требуется, но не символом конца строки, вам необходимо выяснить, совпадает ли количество сохраненных символов (за исключением завершающего нуля) с извлеченнымперсонажи.То есть следующее определяет, есть ли в строке более 12 символов (для завершающего нуля необходим 13-й символ):

#include <iostream>
#include <string.h>

int main()
{
    char array[13];
    if (std::cin.getline(array, 13).gcount() == strlen(array)) {
        std::cout << "excess characters on the line\n";
    }
}

Если вы затем хотите удалить лишние символы из потокавы бы использовали что-то вроде std::cin.ignore(std::numeric_limits<std::streamsize>::max());.Поскольку это тоже помечено как C, я не знаю, как это сделать с C, но я уверен, что есть что-то похожее на gcount().

На самом деле, если присмотретьсяв спецификации std::istream:getline() фактически устанавливает std::ios_base::failbit, если он не встречает символ новой строки при чтении символа (он также устанавливает std::ios_base:failbit, когда символ не читается, но не устанавливает std::ios_base::failbit, если хотя бы один символ являетсячитать до достижения конца файла).Это означает, что вы также хотите очистить поток перед игнорированием лишних символов, и вы можете работать с std::ios_base::failbit и std::ios_base::eof():

#include <iostream>
#include <limits>
#include <string.h>

int main()
{
    char array[13];
    std::cout << "enter password: ";
    while (!std::cin.getline(array, 13) && !std::cin.eof())
    {
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "password is too long: enter max 12 chars: ";
    }
    std::cout << "the password is '" << array << "'\n";
}

Так как std::ios_base::failbit установлен, вам нужно вызвать clear() до того, какВы можете использовать поток для чего угодно.

1 голос
/ 07 марта 2012

Чтобы пользователь мог ввести больше символов, чем вы позволяете, он должен пройти как минимум на один символ сверх лимита.Поскольку для вас не имеет значения, на сколько символов пользователь «перешагнул» ваш лимит, вы можете передать MAX+1 в качестве лимита и посмотреть, превышает ли длина MAX.

Конечновам нужно сделать достаточно места в буфере для хранения 13-го символа и нулевого терминатора. РЕДАКТИРОВАТЬ Вам также необходимо вызывать ignore, чтобы переходить к концу строки при каждой неудачной попытке.

...