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

C++ - Assigning character values to a string in a vector using range based for loop doesn't assign the value

本文关键字:分配 字符 向量 字符串 循环 for 于范围 范围 C++      更新时间:2023-10-16

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

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

为了解决这个问题,我已经注释掉了基于for循环的范围,并尝试用传统的for循环做同样的事情。使用此代码,我在加密过程中出现错误:

位置 1 A 与 @ 相同 在抛出"std::out_of_range"实例后终止调用 what((: vector::_M_range_check: __n (即 26(>= this->size(( (即 2(

"位置 1 A 与 @ 相同">行是我添加的调试输出,用于显示代码能够找到正确的字符串、字符串中的字母以及 them 键中的相应字母。

任何帮助了解我为什么得到这些错误将不胜感激。

这是我的代码:

#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;
}

欢迎来到 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.
}

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

您正在访问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;

纠正这些,它应该有效!


提示:

是时候阅读如何调试小程序了。
它将帮助您以更系统的方式找出程序的问题所在。


关于代码组织的几点:

  • 您应该将程序划分为函数,而不是使main函数混乱。
  • 您可以在语句中编写与您的每个case对应的函数switch例如addName()encryptName()decryptName()等。
  • 这种模块化肯定会帮助您和其他人轻松有效地阅读、调试、维护和扩展您的代码。在您的情况下,它还可以帮助您立即编写最小、完整和可验证的示例。

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