C++ - 使用基于范围的 for 循环将字符值分配给向量中的字符串不会分配值
C++ - Assigning character values to a string in a vector using range based for loop doesn't assign the value
我正在做一个自我练习练习。参数是我允许用户输入存储在向量中的名称。打印向量中的名称列表可为您提供每个名称的位置。您可以选择通过提供名称的位置来加密列表中的名称。加密会将名称中的每个字母与另一个字符串进行比较,该字符串是允许的名称字母表。当它在字母表中找到该字母时,它会从另一串随机字符中提取一个对应的字符,并将新字符分配到相同的位置。
使用基于范围的 for 循环我几乎让它工作了。通过添加输出语句,我可以看到代码正确地将名称字符与允许的字母进行比较,并在加密密钥中找到相应的值。然而,当循环完成并且我再次打印名称列表时,要加密的名称中的字符没有改变。
为了解决这个问题,我注释掉了基于范围的 for 循环,并尝试用传统的 for 循环做同样的事情。使用此代码,我在加密过程中遇到错误:
Position 1 A is the same as @
terminate called after throwing an instance of 'std::out_of_range'
what(): vector::_M_range_check: __n (which is 26) >= this->size() (which is 2)
"Position 1 A is the same as @" 行是我添加的调试输出,用于显示代码能够找到正确的字符串、字符串中的字母以及他们键中的相应字母。
如果能帮助我理解为什么会出现这些错误,我们将不胜感激。
这是我的代码:
#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;
}
欢迎使用 Whosebug!我完全同意 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;
更正这些,它应该可以工作!
提示:
是时候阅读 How to debug small programs。
它将帮助您以更系统的方式找出您的程序出了什么问题。
关于一般代码组织的几点:
- 您应该将程序划分为多个函数,而不是使
main
函数混乱。
- 您可以在
switch
语句中编写对应于每个 case
的函数,例如addName()
、encryptName()
、decryptName()
等
- 这种模块化一定会帮助您和其他人轻松高效地阅读、调试、维护和扩展您的代码。在您的情况下,它还可以帮助您立即编写 Minimal, Complete, and Verifiable example。
希望对您有所帮助!
祝你好运!
编码愉快!
我正在做一个自我练习练习。参数是我允许用户输入存储在向量中的名称。打印向量中的名称列表可为您提供每个名称的位置。您可以选择通过提供名称的位置来加密列表中的名称。加密会将名称中的每个字母与另一个字符串进行比较,该字符串是允许的名称字母表。当它在字母表中找到该字母时,它会从另一串随机字符中提取一个对应的字符,并将新字符分配到相同的位置。
使用基于范围的 for 循环我几乎让它工作了。通过添加输出语句,我可以看到代码正确地将名称字符与允许的字母进行比较,并在加密密钥中找到相应的值。然而,当循环完成并且我再次打印名称列表时,要加密的名称中的字符没有改变。
为了解决这个问题,我注释掉了基于范围的 for 循环,并尝试用传统的 for 循环做同样的事情。使用此代码,我在加密过程中遇到错误:
Position 1 A is the same as @ terminate called after throwing an instance of 'std::out_of_range' what(): vector::_M_range_check: __n (which is 26) >= this->size() (which is 2)
"Position 1 A is the same as @" 行是我添加的调试输出,用于显示代码能够找到正确的字符串、字符串中的字母以及他们键中的相应字母。
如果能帮助我理解为什么会出现这些错误,我们将不胜感激。
这是我的代码:
#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;
}
欢迎使用 Whosebug!我完全同意 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;
更正这些,它应该可以工作!
提示:
是时候阅读 How to debug small programs。
它将帮助您以更系统的方式找出您的程序出了什么问题。
关于一般代码组织的几点:
- 您应该将程序划分为多个函数,而不是使
main
函数混乱。 - 您可以在
switch
语句中编写对应于每个case
的函数,例如addName()
、encryptName()
、decryptName()
等 - 这种模块化一定会帮助您和其他人轻松高效地阅读、调试、维护和扩展您的代码。在您的情况下,它还可以帮助您立即编写 Minimal, Complete, and Verifiable example。
希望对您有所帮助!
祝你好运!
编码愉快!