C ++-使用基于范围的for循环将字符值分配给向量中的字符串不会分配值

时间:2018-10-07 04:14:18

标签: c++ stdstring

我正在进行自我练习。参数是允许用户输入存储在向量中的名称。打印矢量中的名称列表可为您提供每个名称的位置。您可以选择通过提供名称的位置来加密列表中的名称。加密会将名称中的每个字母与另一个字符串(名称允许的字母)进行比较。当它找到字母表中的字母时,会从另一串随机字符中提取相应的字符,并将新字符分配到同一位置。

使用基于范围的for循环,我几乎可以正常工作了。通过添加输出语句,我可以看到代码正确地将名称的字符与允许的字母进行比较,并在加密密钥中找到相应的值。但是,当循环完成并再次打印名称列表时,要加密的名称中的字符将保持不变。

尝试解决该问题,我已注释掉基于for循环的范围,并尝试使用传统的for循环执行相同的操作。有了这段代码,我在加密过程中出错了:

  

位置1 A与@相同   抛出'std :: out_of_range'实例后调用终止     what():vector :: _ M_range_check:__n(26)> = this-> size()(2)

“位置1 A与@相同” 行是我添加的调试输出,以表明代码能够找到正确的字符串,字符串中的字母以及他们键入相应的字母。

对于理解我为什么会得到这些错误的任何帮助,将不胜感激。

这是我的代码:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    // Declare strings for Encryption and Decryption
    string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ "};
    string key {"mnbvfghytcqwi1234567890`~!@#$%^&*()-=_+[]\{}|;':,./<>?"};

    //Declare collection of names for the list
    vector <string> names {};

    //Declare character to hold the user menu selection
    char selection {};
    string user_input{};
    string banner (50, '=');
    //Print menu
    do
    {
        cout << "\n" << banner << endl;
        cout << "A - Add name to list" << endl;
        cout << "P - Print all names in list" << endl;
        cout << "E - Encrypt a name in the list" << endl;
        cout << "D - Decrypt a name in the list" << endl;
        cout << "S - Show details of a name in the list" << endl;
        cout << "C - Clear all names in the list" << endl;
        cout << "Q - Quit" << endl;
        cout << banner << endl;
        cout << "Selection: ";
        getline(cin, user_input);
        if (user_input.size() != 1)
        {
            cout << "Error 4: Menu selection must be a single character" << endl;
            selection = '1';
        }
        else
        {
            for (auto c: user_input)
            {
                if (!isalpha(c))
                {
                    cout << "Error 5: Menu selection must be an alphabetic character" << endl;
                    selection = '1';
                }
                else
                    selection = c;

            }
        }
        // cin >> selection;
        // cin.clear();
        // cin.sync();

        switch (selection)
        {
            case 'a':
            case 'A':
            {
               string temp_name{};
               bool invalid_name {false};
               cout << "Enter full name: ";
               getline(cin, temp_name);
               if (!isalpha(temp_name[0]))
                   cout << "Error 2: Names must begin with an alphabetic character" << endl << endl;
                else 
                {
                    for (auto c: temp_name)
                    {
                        if (!isalpha(c) && !isspace(c) && c != '-')
                        {
                            invalid_name = true;
                            break;
                        }   
                        else
                            invalid_name = false;
                    }
                    if (invalid_name)
                        cout << "Error 3: Name contains invalid characters" << endl << endl;
                    else
                    {
                        temp_name.at(0) = toupper (temp_name.at(0));
                        for (size_t i {1}; i < temp_name.size(); i++)
                        {
                            size_t position{i-1};
                            if (isspace(temp_name.at(position)) || temp_name.at(position) == '-')
                            {
                                temp_name.at(i) = toupper(temp_name.at(i));
                            }
                        }
                        names.push_back(temp_name);
                        cout << "Added name #" << names.size() << endl;
                    }
                }
               break;
            }
            case 'p':
            case 'P':
            {
                for (size_t i {0}; i < names.size(); i++)
                    cout << i+1 << ". " << names.at(i) << endl;
                break;
            }
            case 'e':
            case 'E':
            {
                size_t encrypt_input{}, key_position{}, name_position {}, name_size {};
                cout << "Enter the position of the name to encrypt: ";
                cin >> encrypt_input;
                cin.clear();
                cin.sync();
                if (encrypt_input < 1 || encrypt_input > names.size())
                    cout << "Error 6: Invalid selection for name to encrypt" << endl << endl;
                else
                {
                    name_position = encrypt_input - 1;
                    name_size = names.at(name_position).size();
                    cout << "Encrypting name: " << names.at(name_position) << " of size " << name_size << endl << endl;
                    cout << "Position 1 " << names.at(name_position).at(0) << " is the same as ";
                    key_position = alphabet.find(names.at(name_position).at(0));
                    cout << key.at(key_position) << endl;
                    for (size_t i {0}; i < name_size; i++)
                    {
                        key_position = alphabet.find(names.at(name_position).at(i));
                        cout << "Finding " << names.at(key_position).at(i) << " in key at position " << key_position << endl;
                        cout << "Found encryption value of " << key.at(key_position) << " at position " << key_position << endl;
                        cout << "Changing " << names.at(key_position).at(i) << " to " << key.at(key_position) << endl;
                        names.at(name_position).at(i) = key.at(key_position);
                    }
                    /*
                    for (auto c: names.at(encrypt_input-1))
                    {
                        cout << "Converting " << c << " to ";
                        key_position = alphabet.find(c);
                        cout << key.at(key_position) << endl;
                        c = key.at(key_position);
                        cout << "C is now " << c << endl << endl;
                    } 
                     */
                }
                cout << names.at(encrypt_input-1) << endl;
                break;
            }
            case 'q':
            case 'Q':
                cout << "Goodbye" << endl << endl;
                break;
            default:
                cout << "Error 1: Invalid menu selection" << endl << endl;
                break;
        }
    } while (selection != 'Q' && selection != 'q');

    return 0;
}

2 个答案:

答案 0 :(得分:0)

欢迎来到Stackoverflow!我完全同意PaulMcKenzie的观点,这么大的功能并不是出于各种原因才是最好的-直接的原因是它难以阅读且难以发现问题-但还有更多原因。

已经说过,您在E案例中发现了一个错误。

                for (size_t i {0}; i < name_size; i++)
                {
                    key_position = alphabet.find(names.at(name_position).at(i));
                    cout << "Finding " << names.at(key_position).at(i) << " in key at position " << key_position << endl;
                    cout << "Found encryption value of " << key.at(key_position) << " at position " << key_position << endl;
                    cout << "Changing " << names.at(key_position).at(i) << " to " << key.at(key_position) << endl;
                    names.at(name_position).at(i) = key.at(key_position);
                }

应该是

        for (unsigned int i{ 0 }; i < name_size; i++)
        {
            key_position = alphabet.find(names.at(name_position).at(i));
            cout << "Finding " << names.at(name_position).at(i) << " in key at position " << key_position << endl;
            cout << "Found encryption value of " << key.at(key_position) << " at position " << key_position << endl;
            cout << "Changing " << names.at(name_position).at(i) << " to " << key.at(key_position) << endl;
            names.at(name_position).at(i) = key.at(key_position);
        }

key_position在2个地方应为name_position

可能还有其他错误,但这应该可以避免崩溃并正确进行编码。

编辑:应OP的要求添加了一个新的代码片段。

int i = 0;  // position counter
for (auto c: names.at(encrypt_input-1))
{
    cout << "Converting " << c << " to ";
    key_position = alphabet.find(c);
    cout << key.at(key_position) << endl;
    c = key.at(key_position);
    cout << "C is now " << c << endl << endl;
    names.at(name_position).at(i++) = c;  // update the names variable.
}

这应该可以解决您在自动循环中提到的问题。

答案 1 :(得分:0)

您正在访问names向量的无效位置,并且错误/异常显示该错误。

执行此操作时:

names.at( key_position ).at( i )
//        ^^^
//        It should be name_position

在此声明中

cout << "Finding " << names.at( key_position ).at( i ) << " in key at position " << key_position << endl;

您正在访问names的无效索引,而该索引应该是:

names.at( name_position ).at( i )

,那将起作用,因为它访问有效的索引。

您在此声明中也犯了同样的错误:

cout << "Changing " << names.at( key_position ).at( i ) << " to " << key.at( key_position ) << endl;

更正这些,它应该可以工作!


提示:

是时候阅读How to debug small programs
它可以帮助您更系统地找出程序的问题。


关于您的代码组织的一般几点:

  • 您应该将程序划分为函数,而不要使main函数混乱。
  • 您可以在case语句中编写与每个switch相对应的函数,例如addName()encryptName()decryptName()
  • 这种模块化绝对可以帮助您和其他人轻松,有效地阅读,调试,维护和扩展您的代码。就您而言,这也将帮助您立即编写Minimal, Complete, and Verifiable example

希望有帮助!
祝你好运!
编码愉快!