【问题标题】:How to repeat a program when user prompted y/n当用户提示y / n时如何重复程序
【发布时间】:2021-02-25 06:07:23
【问题描述】:

这个程序应该加密和解密字符串“myWord”。收到后,通过两种方法加解密,然后返回main。我一直在尝试让它提示用户是否要继续。如果他们输入“n”,则循环停止并且程序结束。如果他们输入“y”,那么它将重复,并且在再次提示他们输入他们的名字后他们将能够再次加密。我尝试了很多不同的方法,但是输入 y 后输出仍然是这样的:

#include <iostream>
#include <string>

using namespace std;

void encrypt(string);
void decrypt(string);

int main() {
    string myWord;

    char choice = 'y';
    while (choice == 'y') {
        cout << "Enter a name: ";
        getline(cin, myWord);
        encrypt(myWord);
        cout << "Would you like to encrypt again? (y/n): ";
        cin >> choice;
        if(choice == 'n') {
            return 0;
        }
        system("pause");
    }
    return 0;
}

void encrypt(string encrypting) { 
    for (int i = 0; encrypting[i] != '\0'; i++) {
        encrypting[i] = encrypting[i] + 1;
    }
    cout <<"Encrypted: " << encrypting << endl;
    decrypt(encrypting);
}

void decrypt(string decrypting) {
    for (int i = 0; decrypting[i] != '\0'; i++) {
        decrypting[i] = decrypting[i] - 1;
    }
    cout << "Decrypted: " << decrypting << endl;
    return;
}

我的输出

【问题讨论】:

  • @FantasticMrFox 这并不完全正确。在实践中它们是,甚至在理论上 someString[someString.length()] 保证返回 '\0'。
  • 嗨 liaforu,欢迎来到 SO!您通过发布一个工作代码示例做到了正确,但最好的问题包含最小复制,其中包含仅与问题相关的内容。您的问题与用户输入有关;加密和解密无关紧要。您可以通过将调用encrypt() 的行替换为std::cout &lt;&lt; "doing encryption\n"; 并删除其他两个函数来简化您的示例。想一想:它不会改变你问题的本质,仍然会重现问题,但是将示例减半并使其阅读速度更快! :)
  • @FantasticMrFox,这不是真的。 N4713,C++17 的最新工作草案(与标准相同,但免费提供)引用,在 §5.13.5.16 中:“在任何必要的连接之后,在翻译阶段 7 [...] 中,'\0' 是附加到每个字符串文字上,以便扫描字符串的程序可以找到它的结尾。”这是在规范性文本中,在方括号之外。如果你的编译器做的不同,那是编译器的一个错误。

标签: c++ loops prompt


【解决方案1】:

您的问题是在以空格分隔的输入和面向行的输入之间切换。由于std::cin 将'\n' 留在了流中,因此对std::getline 的下一次调用会看到并跳过。

您需要跳到流的末尾:

更多信息请参见https://en.cppreference.com/w/cpp/string/basic_string/getline。

这应该可以解决您的问题:

#include <limits>
#include <ios>

//...

cout << "Enter a name: ";
getline(cin, myWord);
encrypt(myWord);
cout << "Would you like to encrypt again? (y/n): ";
cin >> choice;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

【讨论】:

  • 好收获!有没有办法自动刷新流?
  • 没有。在您链接的参考文献中,请参阅要点 1.2.b) "下一个可用的输入字符是 delim,由 Traits::eq(c, delim) 测试,在这种情况下,分隔符字符是从输入中提取的,但是未附加到 str。" - 结束行 _is_extracted。实际上问题是相反的,cin &gt;&gt; choice; 在输入中留下一个\n,因此下一个getline 读取一个空字符串。
  • @churill 你是对的。我倒过来了。这里已经过了午夜,我误读了注释部分。固定的。 :)
  • @AntoninGAVREL 我不知道。
【解决方案2】:

混合格式化输入(例如std::cin &gt;&gt; x)和未格式化输入(例如std::getline)很难做到正确。

在您的示例中,cin &gt;&gt; choice 行将从流中提取一个字符(忽略前导空格)。流中的下一个字符(假设您键入 y 然后输入)将是换行符 \n。

例如,您的输入序列可能如下所示name\ny\nanother_name。

第一个getline调用提取name\n,给你字符串name并丢弃\n(它仍然被提取,只是没有添加到字符串中),留下y\nanother_name。

然后cin &gt;&gt; choice提取y,留下\nanother_name。

然后你再次调用getline,它查看流的开头,看到\n,并认为它得到一个空行。所以它会提取 \n 并丢弃它...您希望它读取 another_name,但它读取的是一个空行。

最简单的解决方案是在调用std::getline 之前先调用cin &gt;&gt; std::ws。这会从输入流中提取所有前导空格并丢弃它们(包括虚假的空行)

在您的示例中,它将是:

cout << "Would you like to encrypt again? (y/n): ";
cin >> choice;     
cin >> std::ws; // Note the added std::ws here
if(choice == 'n') {
    return 0;
}

【讨论】:

    【解决方案3】:

    好吧,正如这里的人告诉你的那样,混合 char、strings、getline() 和 cin 的东西是不安全的......

    您可能会发现继续使用 C++ 方式并仅在其中使用 getline() 和 string 会更简单

    示例

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    void decrypt(string);
    void encrypt(string);
    
    int main(void)
    {
        string  choice;
        do
        {
            string  myWord; // only exists here
            cout << "Enter a name: ";
            getline( cin, myWord );
            encrypt(myWord);
            cout << "Would you like to encrypt again? (y/n): ";
            getline( cin, choice );
            
        }   while (choice == "y");
        return 0;
    }
    
    void encrypt(string encrypting) { 
        for (int i = 0; encrypting[i] != '\0'; i++) {
            encrypting[i] = encrypting[i] + 1;
        }
        cout <<"Encrypted: " << encrypting << endl;
        decrypt(encrypting);
    }
    
    void decrypt(string decrypting) {
        for (int i = 0; decrypting[i] != '\0'; i++) {
            decrypting[i] = decrypting[i] - 1;
        }
        cout << "Decrypted: " << decrypting << endl;
        return;
    }
    

    这表明

    PS C:\test> g++ -o x -Wall x.cpp
    PS C:\test> ./x  
    Enter a name: A test
    Encrypted: B!uftu
    Decrypted: A test
    Would you like to encrypt again? (y/n): y
    Enter a name: Another test
    Encrypted: Bopuifs!uftu
    Decrypted: Another test
    Would you like to encrypt again? (y/n): y
    Enter a name: Last One
    Encrypted: Mbtu!Pof
    Decrypted: Last One
    Would you like to encrypt again? (y/n): n
    PS C:\test> 
    

    【讨论】:

      猜你喜欢
      • 2018-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      • 2017-01-09
      • 1970-01-01
      • 2015-09-17
      相关资源
      最近更新 更多