【问题标题】:NOTE:(getline was not the issue) C++ getline() stops working in user defined function but works in main function注意:(getline 不是问题)C++ getline() 在用户定义的函数中停止工作,但在主函数中工作
【发布时间】:2014-12-06 00:11:43
【问题描述】:

注意:已解决,问题不是 getline() 而是 find 函数 数组填充不当!

在发布我自己的问题之前,我已经查找了几个问题,但我找不到我的问题的答案。这是我发布的第一个问题,但在发布我自己的问题之前,我确实做了一些研究并尝试了其他问题的其他解决方案。所以我不完全确定这不是重复的。我很抱歉!感谢您提前理解!

我正在尝试使用 getline() (c++) 来获取用户输入。它在我的 main 中运行良好,但在我的用户定义函数中却没有。我认为这可能与缓冲区有关,所以我按照以下建议使用了 cin.ignore():

C++ getline method not working

我检查了:

How does getline work with cin?

以确保我正确理解 getline()。但是我的程序仍然无法正常运行。

我的程序从用户输入(控制台输入)获取英文文本作为字符串,并将其转换为摩尔斯电码并将结果作为字符串输出(控制台输出)。

基本上我的问题是这样的:

getline 在我的主函数中适用于字符串和带空格的字符串,例如:“This”和“This Code”。

但是,在我的用户定义函数中,它仅适用于没有空格的字符串,例如:“This”。

感谢您的帮助!代码如下:sn-ps!

#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;

using namespace std;


string textToMorse(const string alphabet, const string morseAlphabet[]);

int main()
{
    const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
    const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
    ..",".---","-.-",".-..","--","-.","---",".--.",
    "--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
    "...--","....-",".....",
    "-....","--...","---..","----.",".-.-.-","--..--","..--.."};
    int userSelection;
    string resultString;


    cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
    cout << "Please select an option by typing the integer shown: " << endl << endl;
    cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
    cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
    cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
    cin >> userSelection;

   while(userSelection == 1 || userSelection == 2)
   {

        if(userSelection == 1)
        {

            resultString = textToMorse(alphabet, morseAlphabet); // function where I use 
                                                                 // getline() but does not work
            cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
            cout << resultString << endl << endl << endl << endl;
        }
   }

    return 0;
}

// does not work
string textToMorse(const string alphabet, const string morseAlphabet[])
{
    string userInput;
    cout << endl << "Enter English text to encode to Morse code,
    with only a space between words: " << endl << endl;

    cin.ignore();
    getline(cin,userInput); //code works with strings without spaces, 
                            //but breaks with others. ex: "This" works as input
                            //but "This code" breaks and the console seems to freeze
                            // then crashes out

    cin.clear();

    // rest of code, but program breaks before this.

    string encodedEnglishText = "";

    for(int i = 0; i < userInput.length(); i++)
    {
        userInput[i] = toupper(userInput[i]);
    }

    for(int i = 0; i < userInput.length(); i++)
    {
       encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
       encodedEnglishText += " "; // extra spacing added for output clarity

       if(userInput[i] == ' ')
       {
           encodedEnglishText += "  "; // extra spacing added for output clarity
       }
    }

    return encodedEnglishText;
}

但是,如果我编辑我的代码并从我的 main 获取输入并将其作为参数传递,它就可以工作。

#include <iostream>;
#include <stdio.h>;
#include <ctype.h>;

using namespace std;


string textToMorse(const string alphabet, const string morseAlphabet[], string userInput);
int main()
{
    const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,?";
    const string morseAlphabet[39] = {".-","-...","-.-.","-..",".","..-.","--.","....","
    ..",".---","-.-",".-..","--","-.","---",".--.",
    "--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--..","-----",".----","..---",
    "...--","....-",".....",
    "-....","--...","---..","----.",".-.-.-","--..--","..--.."};
    int userSelection;
    string resultString;


    cout << "TEXT TO MORSE CODE or MORSE CODE TO TEXT program" << endl << endl;
    cout << "Please select an option by typing the integer shown: " << endl << endl;
    cout << "Type(Selects option) 1 to decode Morse code to English text" << endl;
    cout << "Type(Selects option) 2 to encode English text to Morse code" << endl;
    cout << "Type(Select option) any other integer that is NOT 1 or 2 to QUIT" << endl << endl;
    cin >> userSelection;

   while(userSelection == 1 || userSelection == 2)
   {

        if(userSelection == 1)
        {
            string userInput;
            cout << endl << "Enter English text to encode to Morse code,
            with only a space between words: " << endl << endl;

            cin.ignore();
            getline(cin,userInput); //code works with both "This" and "This code"

            cin.clear();
            resultString = textToMorse(alphabet, morseAlphabet, userInput); //function modified 
                                                                           //to take one more
                                                                           //parameter
            cout << endl << "This is the Morse code decoded to English text: " << endl << endl;
            cout << resultString << endl << endl << endl << endl;
        }
   }

    return 0;
}

string textToMorse(const string alphabet, const string morseAlphabet[], string userInput)
{
    //code, but program works.

    string encodedEnglishText = "";

    for(int i = 0; i < userInput.length(); i++)
    {
        userInput[i] = toupper(userInput[i]);
    }

    for(int i = 0; i < userInput.length(); i++)
    {
       encodedEnglishText += morseAlphabet[alphabet.find(userInput[i])];
       encodedEnglishText += " "; // extra spacing added for output clarity

       if(userInput[i] == ' ')
       {
           encodedEnglishText += "  "; // extra spacing added for output clarity
       }
    }

    return encodedEnglishText;
}

我没有包含所有代码,仅包含我认为与问题相关的部分。

我的意思是:

getline 成功接受输入。 getline 在 main 函数中使用时成功地将诸如“this”和“this code”之类的字符串分配给变量 userInput。

在我的用户定义函数中使用时,它只会成功分配没有空格的字符串,例如“this”。在该函数中,由于某种原因,当我输入“此代码”之类的字符串或中间有空格的任何字符串时,它不起作用。

注意:程序尚未完成,因为我计划添加其他方法来执行相反的操作(如代码中所示 额外的用户选项,但这些还没有实现或定义,代码仍然运行和编译我面临的问题。

【问题讨论】:

  • 在您的第一个示例中,您调用morseToText,而不是textToMorse。是不是笔误?
  • 我怀疑你不知何故超出了 morseAlphabet 数组的末尾。您确定它在“其余代码”之前崩溃吗?确定崩溃位置的一种方法是将 cout 语句放在整个代码中以进行调试,但希望您的调试器能比这更有帮助。如果您使用的是 Linux,valgrind 可以帮助您确定程序崩溃的位置。
  • 我确实试过这个,我在 Windows 8.1 上使用 Code::Blocks。但数组似乎工作正常!
  • 我修复了您的代码,使其能够编译,但由于alphabet 中没有空格字符而导致崩溃,因此find 返回std::string::npos 并尝试将越界索引到morseAlphabet
  • 谢谢!然而,我认为这不是问题,因为它在我的 main 中使用完全相同的代码工作(数组在 main 中未更改但仍然适用于空格),但这确实在我的函数中修复了它!如果没有数组中的空间,它会在 main() 中工作而不是在我的函数中工作吗?

标签: c++ find


【解决方案1】:

问题是空格没有摩尔斯电码。

进行验证:

    int n = alphabet.find(userInput[i]);
    encodedEnglishText += (n == string::npos) ? "  ":  morseAlphabet[n];

然后它将起作用。

【讨论】:

  • 谢谢!它在我的 main 中使用完全相同的代码工作(数组在 main 中没有更改,但仍然适用于空格)这确实在我的函数中修复了它!是否有任何理由说明为什么它会在 main() 中工作,而不是在我的函数中没有数组中的空间? - Retired Ninja 和 Christophe 都给出了相似的答案,所以谢谢你们。
  • 这就是尝试访问无效对象时“未定义行为”的乐趣所在:相同的代码可能会产生不同的症状,有时甚至可以正常工作。那是因为一切都取决于代码将在它访问的内存中找到什么。这就是为什么这些错误令人讨厌且难以发现的原因。
【解决方案2】:

当您在alphabet 字符串中查找您的输入字符时,您不会找到' 'std::string::find() 返回std::string::npos(通常-1 转换为std::string::size_type 类型但值不是'保证)。使用这个值来索引morseAlphabet 对你没有多大好处:这是未定义的行为。当您只输入一个字符串时不会出现此问题,因为所有字符都在 alphabet 中找到。

处理这种情况的正确方法是寻找角色并捕捉结果。在使用结果之前,您需要测试输入,例如:

std::string::size_type pos(alphabet.find(userInput[i]));
if (pos == std::string::npos) {
    // deal with the character not being part of the alphabet
}
else {
    encodedEnglishText += morseAlphabet[pos];
}

请注意,您的程序还有其他一些问题:

  1. 选项的选择应该在循环内部!它的实现方式进入,例如2 导致无限循环。

  2. std::toupper()char 一起使用也可能导致未定义的行为!问题是std::toupper() 期望值EOF 的非负值,但char 可能已签名。为避免此问题,您应该使用&lt;cctype&gt;&lt;ctype.h&gt; 中的任何函数和unsigned char

    userInput[i] = toupper[static_cast<unsigned char>(userInput[i]));
    
  3. 如果用户没有输入整数,但是,例如,foo 读取 userSelection 将失败,并且流将进入失败状态,在输入 std::cin.clear() 之前它不会执行任何操作。处理这种情况的最佳方法是在执行任何操作之前测试读取值的结果。如果输入失败,您可以通过清除状态并跳过违规字符来恢复,例如:

    if (std::cin >> userSelection) {
        // use the selection
    }
    else {
        std::cout << "ignoring invalid input\n";
        std::cin.clear();
        std::cin.ignore();
    }
    

    请注意,您应该需要使用std::cin.clear()。此外,您应该验证您使用std::getline() 读取的输入是否成功:通常,所有用户输入都应测试是否成功。

  4. 如果您在读取userSelection 时在整数后输入空格字符,您对std::cin.ignore() 的调用将忽​​略此空格而不是换行符!为避免此问题,您可以读取所有字符直到第一个换行符或跳过非空白字符之前的所有空白:

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // all till newline
    std::cin >> std::ws; // skip all whitespace to first non-whitespace character
    
  5. Do not use std::endl!它不仅会创建换行符,还会刷新流。这很容易造成性能问题。

  6. 您可能应该通过引用而不是值传递 std::string 参数。通过值传递参数alphabet 会创建一个副本效率低下(morseAlphabet 参数是通过指针传递的,尽管它看起来像一个数组)。

  7. 某些字符串文字似乎被拆分为多行。这样做是非法的(不过我猜想,这个问题是在将代码粘贴到上述问题时引入的)。

【讨论】:

  • Dietmar Kühl,感谢您非常详细的回答!我是 C++ 新手,因为我通常使用 Java 编程,所以我仍然需要学习很多约定,感谢您的输入和出色的回答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-31
  • 2012-09-21
  • 1970-01-01
  • 1970-01-01
  • 2019-08-09
  • 2016-12-06
相关资源
最近更新 更多