c++ - 我的代码段有时会运行,有时会抛出错误。我的内存编程有问题吗?代码是怎么回事?
问题描述
第一个文件。现在我们在“Position.h”
struct Position{
int digit;
int possible[9];
int logicalSize;
bool isPermanent;
Position* next;
Position* last;
};
typedef Position* Positionptr;
下一个文件。现在我们在“Board.h”
#include "Position.h"
class Board{
private:
//maybe use an array of structures
Position elements[81];
bool membership(int arr[], int digit);
public:
void print();
Board(int input[]);
int* getRow(int row);
int* getColumn(int col);
//make private
void makePossibleList(int row, int col);
void solve();
};
下一个文件。现在我们在“Board.cpp”
#include "Board.h"
#include <iostream>
using namespace std;
Board::Board(int input[]){
for(int i = 0; i < 81; i++){
Position temp;
temp.digit = input[i];
//possible is already initialized
if(input[i] == 0){
temp.isPermanent = false;
}
else{
//this position is set and cannot be changed
temp.isPermanent = true;
}
elements[i] = temp;
}
}
void Board::print(){
for(int i = 0; i < 9; i++){
int* arr = getRow(i);
for(int j = 0; j < 9; j++){
cout << arr[j] << " ";
}
cout << endl;
}
//confirmed that it can print backwards
}
bool Board::membership(int arr[], int digit){
for(int i = 0; i < 9; i++){
if(arr[i] == digit) return true;
}
return false;
}
void Board::makePossibleList(int row, int col){
Position temp = elements[row*9 + col];
int* tempRow = getRow(row);
int* tempColumn = getColumn(col);
for(int i = 0; i < 9; i++){
if(membership(tempRow, i)){
continue;
}
else if(membership(tempColumn, i)){
continue;
}
else{
temp.possible[temp.logicalSize] = i;
temp.logicalSize++;
}
}
//find the possible values for this position
}
int* Board::getRow(int row){
int* temp = new int[9];
for(int i = (row*9); i < (9*(row+1)); i++){
temp[i-row*9] = elements[i].digit;
}
return temp;
}
int* Board::getColumn(int col){
int* temp = new int[9];
for(int i = 0; i < 81; i+= 9){
temp[((i+1)/9)] = elements[(i+col)].digit;
}
return temp;
}
void Board::solve(){
cout << "here";
for(int i = 0; i < 81; i++){
Position temp = elements[i];
if(temp.isPermanent){
continue;
}
///*
else{
int row = i/9;
int col = i%9;
makePossibleList(row, col);
if(temp.logicalSize == 0){
break; //something messed up
}
else{
for(int i = 0; i < 9; i++){
cout << temp.possible[i] << " ";
}
cout << endl;
//use the end of possible list value
temp.digit = temp.possible[temp.logicalSize-1];
temp.digit = *(temp.possible + temp.logicalSize-1);
temp.logicalSize--;
//logicalSize will equal 0 if we use up the last one!!
}
}
//*/
}
cout << "here";
//either the loop broke because something is wrong
// or the loop finished and the puzzle is solved
print();
}
//在main.cpp文件中我运行驱动代码
//上面的一切都来自 Board.h 文件下一个文件。我们现在在 main.cpp
#include <iostream>
#include "Board.h"
using namespace std;
int main() {
cout << "Hello World!\n";
int puzzle[] = {0, 2, 0, 0, 9, 0, 0, 6, 0,
0, 0, 9, 0, 5, 0, 3, 0, 2,
0, 8, 0, 7, 0, 0, 0, 5, 0,
0, 6, 0, 0, 1, 0, 0, 0, 3,
0, 7, 0, 0, 3, 0, 0, 9, 0,
9, 0, 0, 0, 6, 2, 0, 7, 0,
0, 3, 0, 0, 0, 1, 0, 2, 0,
8, 0, 2, 0, 7, 0, 4, 0, 0,
0, 9, 0, 0, 8, 0, 0, 3, 0};
Board x = Board(puzzle);
//x.print();
cout << "here";
x.solve();
}
我无法理解为什么我的代码段始终无法正常运行。它会运行一次,生病再运行一次,然后它不会运行。我正在使用 repl.it 编译器。当我在编写solve() 方法之前测试程序的其他部分时,我有一种暗示,solve() 方法是问题的根源。我的内存分配有什么问题吗?谢谢!
解决方案
有时有效的 C++ 代码是Undefined Behavior的强烈指示。
所以,作为第一步,我通过UBSan运行了这个
这是 Godbolt 上的结果:https ://godbolt.org/z/jqpubW
example.cpp:60:12: runtime error: member call on address 0x00000044a300 which does not point to an object of type 'std::basic_ostream<char>'
0x00000044a300: note: object has invalid vptr
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior example.cpp:60:12 in
example.cpp:62:10: runtime error: member call on address 0x00000044a300 which does not point to an object of type 'std::basic_ostream<char>'
0x00000044a300: note: object has invalid vptr
<memory cannot be printed>
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior example.cpp:62:10 in
这些是突出显示的行:
int* arr = getRow(i);
for(int j = 0; j < 9; j++){
cout << arr[j] << " ";
}
cout << endl;
返回的行尚未初始化。
记忆消毒剂
您必须解决此问题,以查看是否存在更多问题。
之后,还要通过Address Sanitizer运行它。
让我们首先通过 Memory Sanitizer 运行它(因为有人写了一条评论说有未初始化的内存)。
这是在运行“debian-10-buster-v20200210”的 GCP micro-us-1 实例上,以防您手边没有 Linux 机器。只需启动一个实例并安装sudo apt install clang
.
user@micro-us-1:~$ clang++ -fsanitize=memory -g q61003206.cc && ./a.out
Hello World!
==6314==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x4991d4 in Board::makePossibleList(int, int) /home/user/q61003206.cc:89:39
#1 0x499789 in Board::solve() /home/user/q61003206.cc:125:7
#2 0x499ce4 in main /home/user/q61003206.cc:164:5
#3 0x7fcc3fd3609a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)
#4 0x41f379 in _start (/home/user/a.out+0x41f379)
SUMMARY: MemorySanitizer: use-of-uninitialized-value /home/user/q61003206.cc:89:39 in Board::makePossibleList(int, int)
Exiting
这是指向temp.possible
未初始化的,因为默认构造函数Position
没有初始化该possible
字段。解决这个问题的正确方法是制作possible
一个std::array<int, 9> possible;
. 此外,默认初始化Position::logicalSize
。
void Board::makePossibleList(int row, int col) {
Position temp = elements[row * 9 + col];
int *tempRow = getRow(row);
int *tempColumn = getColumn(col);
for (int i = 0; i < 9; i++) {
if (membership(tempRow, i)) {
continue;
} else if (membership(tempColumn, i)) {
continue;
} else {
// This is the problematic line as highlighted by MSAN
temp.possible[temp.logicalSize] = i;
temp.logicalSize++;
}
}
// find the possible values for this position
}
使固定
这就是Position
我之后结构的样子:
struct Position {
int digit;
std::array<int, 9> possible ; // This should be a vector
int logicalSize {0};
bool isPermanent;
Position *next;
Position *last;
};
这足以解决问题,但你真的应该这样做。默认初始化所有成员,并删除未使用的成员,并为可变大小(向量)的东西使用正确的容器。
struct Position {
int digit {-1};
// logicalSize and possible get combined into one vector that can grow and shrink.
std::vector<int> possible;
bool isPermanent {false};
// These two are unused!
// Position *next;
// Position *last;
};
旁注,您还必须像这样修复此块:
// use the end of possible list value
temp.digit = temp.possible[temp.logicalSize - 1];
// temp.digit = *(temp.possible + temp.logicalSize - 1);
temp.digit = temp.possible.at(temp.logicalSize - 1);
temp.logicalSize--;
代码审查
我建议您将其发布在 Code Review SE 上。
一些值得注意的项目,但不是唯一的:
- 评论你的数据结构。例如,中的
int possible[9]
字段是什么意思Position
。 - 使用现代 C++。
- 使用 STL 提供的容器。在您的情况下,这意味着很多
std::array
. - 更少的原始指针,并且绝对不使用
new
. - 不要使用
using namespace std
.
- 使用 STL 提供的容器。在您的情况下,这意味着很多
推荐阅读
- r - 针对分组坐标运行 DBSCAN
- python - python pyqt5将文件名添加到getSaveFileName
- javascript - 试图将消息转换为小写但它不起作用
- javascript - PayPal 集成 400 错误请求/订单无法捕获
- sharepoint - 使用 PowerApps 如何在总共有 20k+ 条记录的 SharePoint 列表中批量更新 1% 到 10% 的记录
- windows - 无法 git checkout master:无效路径“?”
- android - 如何获取发送按键事件的键盘名称?
- azure-sql-database - Azure SQL 超大规模层
- java - 使用 java 扫描仪时如何检查 \n?
- vue.js - 在托管的 Nuxt 应用程序中利用错误布局