在此程序中,用户在命令行中输入两个字符串。其中一个是数字,另一个是字符串。该程序用于根据电话拨号盘上每个按钮上的数字/字母检查输入的数字和字符串是否相同。我得到一个例外,说:
Unhandled exception at 0x775DDAE8 in Project10.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0018F158.
非常感谢任何帮助,非常感谢你们。)
using namespace std;
bool checkPswd(string keyStrokes, string password) {
string temp;
string temp2;
bool temporary = 1;
string phoneButtons[10] = {
"", ""
"abc", "def", "ghi", "jkl",
"mno", "pqrs", "tuv", "wxyz"
};
for (int i = 0; i < keyStrokes.length(); i++) {
for (int j = 2; j < 10; j++) {
for (int k = 0; k < phoneButtons[j].length(); k++) {
temp = phoneButtons[j];
if (password.at(k) == temp.at(k)) {
temp2 = +(char)k;
}
else {
//do nothing
}
}
}
}
cout << temp2;
for (int m = 0; m < temp2.length(); m++) {
if (temp2.at(m) == keyStrokes.at(m)) {
//keep searching
}
else {
return 0;
}
}
return 1;
}
int main(int argc, char ** argv) {
if (argc != 3) {
cout << "Please input the key strokes from the phone and the password." << endl;
return 1;
}
string keyStrokes = argv[1];
string password = argv[2];
bool check;
check = checkPswd(keyStrokes, password);
if (check) {
cout << "Password Verified" << endl;
}
else {
cout << "Wrong Password" << endl;
}
return 0;
}
答案 0 :(得分:5)
for (int k = 0; k < phoneButtons[j].length(); k++) {
k将在这里迭代,从0到1,小于`phoneButtons [j]
中的字符数 if (password.at(k) // ... rest of the code is irrelevant
流行测验:如果password
的字符少于phoneButtons[j]
,您认为这会发生什么?
for (int m = 0; m < temp2.length(); m++) {
if (temp2.at(m) == keyStrokes.at(m)) {
这里也有同样的错误。我没有分析所显示代码的其余部分是否存在同一逻辑错误的其他任何内容。
这就是为什么你应该使用#include <algorithm>
,而不是使用这些容易出错的C风格for
循环。 std::find()
比这种基于C风格的循环搜索更不容易出错。
答案 1 :(得分:1)
手动循环遍历多个数组并从中读取它们容易出错。
temp2
,而不是附加到它。temp2
与keystrokes
的长度相同。这就是为什么你不像你那样“手工”做到这一点。很难完全跟踪所有内容,并且很难始终知道访问给定索引是安全的。
更好的方法是创建一个将一个事物转换为另一个事物的函数。您可以使用迭代器实现一种非常通用的方法。迭代器可以引用许多数据结构,甚至可以读/写流。它非常灵活。
由于编译器可以“查看所有内容”并了解所有类型的所有内容,因此可以生成非常高效的代码,非常安全。
这是一个基于迭代器的实现,它将字符转换为数字,然后比较数字。
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
template<
typename InputIt,
typename OutputIt,
typename V = typename std::iterator_traits<InputIt>::value_type,
typename OutTag = typename std::iterator_traits<OutputIt>::iterator_category,
typename = typename std::enable_if<
std::is_same<OutTag, std::output_iterator_tag>::value>::type
>
OutputIt convertToDigits(InputIt st, InputIt en, OutputIt dest)
{
using ButtonPair = std::pair<char, int>;
using ButtonLookup = std::vector<ButtonPair>;
static ButtonLookup lookup{
{ 'a', 2 }, { 'b', 2 }, { 'c', 2 },
{ 'd', 3 }, { 'e', 3 }, { 'f', 3 },
{ 'g', 4 }, { 'h', 4 }, { 'i', 4 },
{ 'j', 5 }, { 'k', 5 }, { 'l', 5 },
{ 'm', 6 }, { 'n', 6 }, { 'o', 6 },
{ 'p', 7 }, { 'q', 7 }, { 'r', 7 }, { 's', 7 },
{ 't', 8 }, { 'u', 8 }, { 'v', 8 },
{ 'w', 9 }, { 'x', 9 }, { 'y', 9 }, { 'z', 9 }
};
auto ls = std::begin(lookup);
auto le = std::end(lookup);
std::for_each(st, en, [&](char c) {
if (c >= 'A' && c <= 'Z')
c += 'a' - 'A';
auto m = std::find_if(ls, le, [&](auto const& p) {
return p.first == c;
});
if (m != le)
*dest++ = m->second;
});
return dest;
}
int main(int argc, char **argv)
{
if (argc != 3)
return 1;
std::vector<std::string> args(argv, argv + argc);
std::string const& numbers = args.at(1);
std::string const& characters = args.at(2);
std::cout << " Chars: \"" << characters << '\"' << std::endl;
std::cout << " Check: \"" << numbers << '\"' << std::endl;
std::vector<int> digits;
convertToDigits(std::begin(characters), std::end(characters),
std::back_inserter(digits));
for (int& digit : digits)
digit += '0';
std::cout << "Expect: \"" << std::string(
std::begin(digits), std::end(digits)) << '\"' << std::endl;
bool match = std::equal(std::begin(numbers), std::end(numbers),
std::begin(digits), std::end(digits));
return !match;
}
convertToDigits
接受一对迭代器,指的是要转换的范围的开头和结尾。第三个参数是输出迭代器,用于存储输出。
main
函数为数字vector
值设置int
,并使用std::back_inserter
创建在向量上执行push_back
的输出迭代器每次存储到。
翻译功能只是在查找表中进行线性搜索。我选择了线性搜索,因为列表很小。它将紧密地封装在内存中,并且开销非常低。无论如何,速度在这里无关紧要。这是瞬间的。
我将'0'
添加到数字值以将其转换为ASCII,因此它们与命令行字符串相当。
其余的很明显,看看转换的字符串是否与预期的字符串匹配,如果匹配则退出0退出代码。