out_of_range at memory location c++

out_of_range at memory location c++

本文关键字:location c++ memory range of out at      更新时间:2023-10-16

在这个程序中,用户在命令行中输入两个字符串。其中一个是数字,另一个是字符串。该程序旨在根据电话拨号盘每个按钮上的数字/字母来检查输入的数字和字符串是否相等。我得到了一个例外,上面写着:

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;
}
for (int k = 0; k < phoneButtons[j].length(); k++) {

k将在这里从0迭代到比`phoneButtons[j]中的字符数少1

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)) {

这里也有同样的bug。我还没有分析显示的代码的其他部分是否出现了相同的逻辑错误。

这就是为什么应该使用#include <algorithm>,而不是使用这些容易出错的C样式for循环。std::find()比这种基于C风格循环的搜索更不容易出错。

问题的原因

手动循环多个数组并从中读取是很容易出错的。

  • 您的循环不断覆盖temp2,而不是附加到它
  • 稍后,您的代码假设temp2keystrokes的长度相同

这就是为什么你没有像以前那样"手工"做。很难完美地跟踪所有内容,也很难始终知道访问给定索引是安全的。

更好的方法

一个更好的方法是制作一个将一件事转换为另一件事的函数。您可以使用迭代器来实现一种非常通用的方法。迭代器可以引用许多数据结构,甚至可以读取/写入流。它非常灵活。

由于编译器可以"看到一切"并了解所有类型的一切,因此它可以生成非常安全的高效代码。

这里是一个基于迭代器的实现,它将字符转换为数字,然后比较数字。

现场演示

#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函数为数字int值设置一个vector,并使用std::back_inserter生成一个输出迭代器,每次存储向量时对其执行push_back

翻译器函数只是在查找表中进行线性搜索。我选择了线性搜索,因为列表太小了。它将被紧密地封装在内存中,并且开销非常低。无论如何,速度在这里无关紧要。它是瞬间的。

我将'0'添加到数字值中以将其转换为ASCII,因此它们与命令行字符串相当。

剩下的是显而易见的,看看转换后的字符串是否与期望的字符串匹配,如果匹配,则使用0退出代码退出。