使用 cin 安全提示是/否

发布于 2024-08-20 19:07:25 字数 376 浏览 11 评论 0原文

我正在学习 C++ 类的介绍,我想知道一种更好的方法来检查输入是否是所需的类型。

这是这样做的好方法吗?我有 PHP/PERL 背景,这让我对使用 while 循环相当担心。

char type;
while (true) {
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;

    if ((type == 'y') || (type == 'n')) {
        break;
    }
}

这是一种安全的做法吗?还是我怀疑自己正面临一个充满伤害的世界?确保我在继续之前获得所需的输入的更好方法是什么?

I'm in an intro to C++ class and I was wondering of a better method of checking if input was the desired type.

Is this a good way of doing this? I come from a PHP/PERL background which makes me rather apprehensive of using while loops.

char type;
while (true) {
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;

    if ((type == 'y') || (type == 'n')) {
        break;
    }
}

Is this a safe way of doing this or am I opening myself up to a world of hurt, which I suspect? What would be a better way of making sure I get the input I want before continuing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

旧竹 2024-08-27 19:07:25

就我个人而言,我会选择:

do
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;
}
while( !cin.fail() && type!='y' && type!='n' );

Personally I'd go with:

do
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;
}
while( !cin.fail() && type!='y' && type!='n' );
给我一枪 2024-08-27 19:07:25

就我个人而言,我会将提示作为一个单独的函数,这使得它将提示输出和读取响应作为逻辑表达式放入 while 循环中。

测试读取是否成功对于代码的正确运行至关重要。

我还更喜欢使用 std::getline 一次获取一行,因为它有助于减少因读取一半读取行的其余部分而导致的错误,这是部分读取到较早的结果的结果用户响应。

bool PromptForChar( const char* prompt, char& readch )
{
    std::string tmp;
    std::cout << prompt << std::endl;
    if (std::getline(std::cin, tmp))
    {
        // Only accept single character input
        if (tmp.length() == 1)
        {
            readch = tmp[0];
        }
        else
        {
            // For most input, char zero is an appropriate sentinel
            readch = '\0';
        }
        return true;
    }
    return false;
}

void f()
{
    char type = '\0';

    while( PromptForChar( "Were you admitted? [y/n]", type ) )
    {
        if (type == 'y' || type == 'n')
        {
            // Process response
            break;
        }
    }
}

Personally I'd make the prompt a separate function, this makes it putting the prompt output and reading a response a logical expression to put in a while loop.

Testing whether the read was successful is critical to the correct functioning of the code.

I'd also prefer to use std::getline to get a line at a time as it helps reduce errors caused by reading the rest of a half read line that was the result of a partial read to earlier user responses.

bool PromptForChar( const char* prompt, char& readch )
{
    std::string tmp;
    std::cout << prompt << std::endl;
    if (std::getline(std::cin, tmp))
    {
        // Only accept single character input
        if (tmp.length() == 1)
        {
            readch = tmp[0];
        }
        else
        {
            // For most input, char zero is an appropriate sentinel
            readch = '\0';
        }
        return true;
    }
    return false;
}

void f()
{
    char type = '\0';

    while( PromptForChar( "Were you admitted? [y/n]", type ) )
    {
        if (type == 'y' || type == 'n')
        {
            // Process response
            break;
        }
    }
}
乖乖公主 2024-08-27 19:07:25

可以使用

do {
    program;
} while (condition_to_repeat);

如果算法与您的示例类似,则 。否则这个例子是“安全的”,但我不确定可读性。

Use can use

do {
    program;
} while (condition_to_repeat);

if the algorithm is similar to your example. Otherwise the example is "safe", but I am not sure about the readablity.

っ左 2024-08-27 19:07:25

为什么不这样做呢?

do
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;
}while(  type !='y' && type !='n');

Why not do it this way?

do
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;
}while(  type !='y' && type !='n');
萌酱 2024-08-27 19:07:25

没关系。如果您希望它在多次失败后超时,您可以使用i<10,但它不值得。

That's fine. If you want it to time out after a number of failures, you could use the i<10 but its not worth it.

云朵有点甜 2024-08-27 19:07:25

并且不要忘记让潜在用户的生活更轻松地解释每个步骤,甚至提供不区分大小写的输入。

#include <iostream>

#define MAX_USER_INPUT_ATTEMPTS 3

int _tmain(int argc, _TCHAR* argv[])
{
char input_value = ' ';
int current_attempt = 1;

while(true)
{
    std::cout << "Please confirm your choice (press y[es] or n[o] and Enter): ";

    std::cin >> input_value;

    input_value = tolower( input_value );

    if(input_value=='y' || input_value=='n')
    {
        break;
    }
    else
    {
        std::cout << "You have used " << current_attempt << " of " << MAX_USER_INPUT_ATTEMPTS << " attempts" << std::endl;
        ++current_attempt;
    }

    if( current_attempt > MAX_USER_INPUT_ATTEMPTS )
    {
        std::cout << "Warning: Maximum number of attempts reached." << std::endl;
        break;
    }
}

return 0;
}

And don't forget to make your potential user's life easier explaining each step and even provide the case insensitive input.

#include <iostream>

#define MAX_USER_INPUT_ATTEMPTS 3

int _tmain(int argc, _TCHAR* argv[])
{
char input_value = ' ';
int current_attempt = 1;

while(true)
{
    std::cout << "Please confirm your choice (press y[es] or n[o] and Enter): ";

    std::cin >> input_value;

    input_value = tolower( input_value );

    if(input_value=='y' || input_value=='n')
    {
        break;
    }
    else
    {
        std::cout << "You have used " << current_attempt << " of " << MAX_USER_INPUT_ATTEMPTS << " attempts" << std::endl;
        ++current_attempt;
    }

    if( current_attempt > MAX_USER_INPUT_ATTEMPTS )
    {
        std::cout << "Warning: Maximum number of attempts reached." << std::endl;
        break;
    }
}

return 0;
}
野心澎湃 2024-08-27 19:07:25

基于行的输入不必很冗长,您可以使其 简洁,使用您编写一次的单个函数,仍然可以处理极端情况:

bool yesno_repeat(char const* prompt) {
  using namespace std;
  while (true) {
    cout << prompt << " [yn] ";
    string line;
    if (!getline(cin, line)) {
      throw std::runtime_error("unexpected input error");
    }
    else if (line.size() == 1 and line.find_first_of("YyNn") != line.npos) {
      return line == "Y" || line == "y";
    }
  }
}

int main() try {
  if (yesno_repeat("Blow up?")) {
    take_off_every<Zig>(); // in the future, a zig is a nuclear missile...
  }
  return 0;
}
catch (std::exception& e) {
  std::cerr << e.what() << '\n';
  return 1;
}

Line-based input does not have to be verbose, you can make it succinct, with a single function you write once, that still handles corner cases:

bool yesno_repeat(char const* prompt) {
  using namespace std;
  while (true) {
    cout << prompt << " [yn] ";
    string line;
    if (!getline(cin, line)) {
      throw std::runtime_error("unexpected input error");
    }
    else if (line.size() == 1 and line.find_first_of("YyNn") != line.npos) {
      return line == "Y" || line == "y";
    }
  }
}

int main() try {
  if (yesno_repeat("Blow up?")) {
    take_off_every<Zig>(); // in the future, a zig is a nuclear missile...
  }
  return 0;
}
catch (std::exception& e) {
  std::cerr << e.what() << '\n';
  return 1;
}
瑕疵 2024-08-27 19:07:25

这是一个更短的方法

char type;
while (type != 'y') 
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;   
}

Here is a shorter way

char type;
while (type != 'y') 
{
    cout << "Were you admitted? [y/n]" << endl;
    cin >> type;   
}
情深已缘浅 2024-08-27 19:07:25

我以前从未用 PERL/PHP 编写过代码,但根据您的问题,这里的示例是一个简单的解决方案。

    char c;
while(true){
    cout << "Were you admitted? [y/n]" << endl;
    cin >> c;
    if(c == 'y')
        break;
}
cin.get(c);
return 0;

您将继续收到提示,直到您输入“y”,输入“y”后,这个简单的程序就会退出。

I've never coded in PERL/PHP before but based off of your question and the example here's a simple solution.

    char c;
while(true){
    cout << "Were you admitted? [y/n]" << endl;
    cin >> c;
    if(c == 'y')
        break;
}
cin.get(c);
return 0;

You will continue to be prompted until you enter a 'y' after entering a 'y' this simple program will exit.

童话 2024-08-27 19:07:25

do...while 构造就是为此而设计的,但您也可以在循环条件中完成所有工作:

while (std::cout << "Were you admitted [y/n]\n" && std::cin >> answer && !(answer == 'y' || answer == 'n'));

:)

如果您不想测试 std::cin > 是否成功, >答案(例如想用Ctrl+Z无限循环),您可以将&&替换为逗号:)

并不完全严重,尽管我认为将提示放在条件中有时可以增强此类循环的逻辑(避免break)。

The do...while construct is sort of made for this, but you can also do all the work in the loop condition:

while (std::cout << "Were you admitted [y/n]\n" && std::cin >> answer && !(answer == 'y' || answer == 'n'));

:)

And if you don't want to test the success of std::cin >> answer (e.g want to loop infinitely with Ctrl+Z), you can replace && for comma :)

Not entirely serious, even though methinks putting the prompt in the condition can sometimes enhance the logic of such loops (avoid break).

时光沙漏 2024-08-27 19:07:25

我在这里看到两个“问题”。第一个是 while( true ) 的使用。我认为这不是一个好的做法(尽管这可能是许多人的品味问题)。然而,在循环内部进行中断对于搜索来说很有趣:

for(i = 0; i < MAX; ++i) {
  if ( v[ i ] == searchedElement ) {
      break;
  }
}

这是不言自明的:您会一直运行到向量的末尾,但如果找到该元素,您会在到达它之前中断。这是有道理的。

关于从控制台获取信息,直接从 cin 读取可能会遇到很多麻烦,例如,如果输入有一个空格,则仅返回第一个空格之前的内容。 getline() 是一个读取字符串的实用函数,它(几乎)总是安全的。 getline() 在实用程序标头中定义。您还需要字符串标头。如果你想使用 EOF,还有 cstdio。

int main()
{
    int ch;
    std::string type;

    do {
        getline( std::cin, type );

        if ( cin.fail() ) {
            ch = EOF;
            break;
        }

        ch = tolower( type[ 0 ] );
    } while( ch != 'y' && ch != 'n' );

    // interesting things here...

    return 0;
}

I see two "problems" here. First one is the use of while( true ). I don't think that's a good practice (though probably this is a matter of taste for many people). Breaking inside a loop is however interesting for searching:

for(i = 0; i < MAX; ++i) {
  if ( v[ i ] == searchedElement ) {
      break;
  }
}

This is self-explanatory: you run until the end of the vector, though if the element is found, you break before reaching it. It is justifiable.

About getting information from the console, you can run into a lot of trouble reading directly from cin, for example, being returned the contents only until the first space if the input has one. getline() is an utility function that reads to a string, which is (nearly) always safe. getline() is defined in the utility header. You do also need the string header. And cstdio if you want to use EOF.

int main()
{
    int ch;
    std::string type;

    do {
        getline( std::cin, type );

        if ( cin.fail() ) {
            ch = EOF;
            break;
        }

        ch = tolower( type[ 0 ] );
    } while( ch != 'y' && ch != 'n' );

    // interesting things here...

    return 0;
}
软的没边 2024-08-27 19:07:25

修改@McAden所说的,尝试修复以下错误:如果输入多个字符,测试仅检查第一个字母。

    char type;
    char buffer[128];
    do
    {
      cout << "Were you admitted? [y/n]" << endl;
      cin >> buffer;
      type = buffer[0];
      cout << type << "\n";
    }while( !cin.fail() && type!='y' && type!='n' );

Modifying what @McAden said, try this fix the bug where if you enter multiple characters, the test only checks the first letter.

    char type;
    char buffer[128];
    do
    {
      cout << "Were you admitted? [y/n]" << endl;
      cin >> buffer;
      type = buffer[0];
      cout << type << "\n";
    }while( !cin.fail() && type!='y' && type!='n' );
零崎曲识 2024-08-27 19:07:25

另一种提示 y/n 的方法。 “当”你没有得到你想要的东西时“做”这个。用它做任何你喜欢做的事;它就是有效的。

#include "stdafx.h"
#include <iostream>

int main()
{
    bool accepted;
    char answer;
    do
    { // Ask for 'y' or 'n' at least once
        std::cout << "Accepted? [y/n] -> ";
        std::cin >> answer;
        if (std::cin.fail())
        {                                // not a valid character?
            std::cin.clear();
            std::cin.ignore(1024, '\n');
        }
        if (answer == 'n')
        {                                // character is 'n'?
            accepted = false;
        }
        else
        {                                // character is 'y'?
            accepted = true;
        }
         //    not valid    |or|    not 'n'     |or|    not 'y'
    } while (std::cin.fail() || !(answer == 'n') || !(answer == 'y'));  
}

这也没有任何不良后遗症!

Another way to prompt for y/n . "Do" this "while" you don't get what you want. Do whatever else you like with it; it just works.

#include "stdafx.h"
#include <iostream>

int main()
{
    bool accepted;
    char answer;
    do
    { // Ask for 'y' or 'n' at least once
        std::cout << "Accepted? [y/n] -> ";
        std::cin >> answer;
        if (std::cin.fail())
        {                                // not a valid character?
            std::cin.clear();
            std::cin.ignore(1024, '\n');
        }
        if (answer == 'n')
        {                                // character is 'n'?
            accepted = false;
        }
        else
        {                                // character is 'y'?
            accepted = true;
        }
         //    not valid    |or|    not 'n'     |or|    not 'y'
    } while (std::cin.fail() || !(answer == 'n') || !(answer == 'y'));  
}

This also comes with no adverse after effects!

青衫负雪 2024-08-27 19:07:25

这是提示 y/n 的另一种方法。 “当”你没有得到你想要的东西时,“切换”你的输入。用它做任何你喜欢做的事;它就是有效的。

#include "stdafx.h"
#include <iostream>

int main()
{
    bool play = true; // Initialize play to true.
    char choice;
    while (play) // While play is true, do the following:
    {
        std::cout << "Play again? [y/n] -> ";
        std::cin >> choice;
        switch (choice)
        {
        case 'n':           // We can fall through here because we
            play = false;   // don't do anything with 'y' anyway.
        case 'y':           // Remember; play is already true unless
            break;          // we changed it to false with 'n'.
        default:  // We'll simply assume anything else is a fail!
            std::cin.clear();
            std::cin.ignore(1024, '\n');
            break;
        }
        // Break out here and check the "while" condition again...
    }
    // When play becomes false, we exit the while statement.
}

这没有任何不良后遗症!

Here's another way to prompt for y/n. "While" you don't get what you want, "switch" on your input. Do whatever else you like with it; it just works.

#include "stdafx.h"
#include <iostream>

int main()
{
    bool play = true; // Initialize play to true.
    char choice;
    while (play) // While play is true, do the following:
    {
        std::cout << "Play again? [y/n] -> ";
        std::cin >> choice;
        switch (choice)
        {
        case 'n':           // We can fall through here because we
            play = false;   // don't do anything with 'y' anyway.
        case 'y':           // Remember; play is already true unless
            break;          // we changed it to false with 'n'.
        default:  // We'll simply assume anything else is a fail!
            std::cin.clear();
            std::cin.ignore(1024, '\n');
            break;
        }
        // Break out here and check the "while" condition again...
    }
    // When play becomes false, we exit the while statement.
}

This comes with no adverse after effects!

澉约 2024-08-27 19:07:25
char yn;
bool choice;
do
    {
           
        cout<<"Would you like try again?\n";
        cout<<"Y for yes N for no: ";
        cin>>yn;
    
        while (yn != 'n'&& yn != 'N'&&yn != 'y'&&yn != 'Y')
        {
            cout<<"Y or N please: ";
            cin>>yn;
        }
        
        if (yn == 'n'||yn == 'N')
            choice = false;
        if(yn == 'y'||yn == 'Y')
            choice = true;
        
    } while (choice == true);
char yn;
bool choice;
do
    {
           
        cout<<"Would you like try again?\n";
        cout<<"Y for yes N for no: ";
        cin>>yn;
    
        while (yn != 'n'&& yn != 'N'&&yn != 'y'&&yn != 'Y')
        {
            cout<<"Y or N please: ";
            cin>>yn;
        }
        
        if (yn == 'n'||yn == 'N')
            choice = false;
        if(yn == 'y'||yn == 'Y')
            choice = true;
        
    } while (choice == true);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文