我正在为一个学校项目编写一个程序,该程序使用A *搜索遍历可能状态列表并选择下一个最佳状态以继续解决。
我想明确表示我不是在寻找我的作业解决方案,而是帮助解决这些错误。我在网上看了很多其他问题,发现在某些时候地址0x0意味着我试图访问NULL因为内存不再存在。我不明白我的计划在哪里或如何发生。
我遇到了一些我无法在我的程序中使用gdb和valgrind追踪或理解的错误。
有人可以看看这些错误和我的代码,并可能说明程序段错误的原因吗?我已经坚持了很长一段时间了。
运行Valgrind的结果:
==80117== Invalid read of size 8
==80117== at 0x4011AB: freeList (AST.c:403)
==80117== by 0x401E24: main (main.c:129)
==80117== Address 0x51a8dd8 is 24 bytes inside a block of size 32 free'd
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x400E58: removeFringe (AST.c:267)
==80117== by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid read of size 8
==80117== at 0x4011B7: freeList (AST.c:404)
==80117== by 0x401E24: main (main.c:129)
==80117== Address 0x51a8dc0 is 0 bytes inside a block of size 32 free'd
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x400E58: removeFringe (AST.c:267)
==80117== by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid read of size 8
==80117== at 0x401511: freeDiscs (discs.c:140)
==80117== by 0x4011C1: freeList (AST.c:404)
==80117== by 0x401E24: main (main.c:129)
==80117== Address 0x51a8e30 is 16 bytes inside a block of size 24 free'd
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x401521: freeDiscs (discs.c:141)
==80117== by 0x400E4F: removeFringe (AST.c:266)
==80117== by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid free() / delete / delete[] / realloc()
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x401521: freeDiscs (discs.c:141)
==80117== by 0x4011C1: freeList (AST.c:404)
==80117== by 0x401E24: main (main.c:129)
==80117== Address 0x51a8e20 is 0 bytes inside a block of size 24 free'd
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x401521: freeDiscs (discs.c:141)
==80117== by 0x400E4F: removeFringe (AST.c:266)
==80117== by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid free() / delete / delete[] / realloc()
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x4011CA: freeList (AST.c:405)
==80117== by 0x401E24: main (main.c:129)
==80117== Address 0x51a8dc0 is 0 bytes inside a block of size 32 free'd
==80117== at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117== by 0x400E58: removeFringe (AST.c:267)
==80117== by 0x401DB4: main (main.c:104)
==80117==
==80117==
==80117== HEAP SUMMARY:
==80117== in use at exit: 0 bytes in 0 blocks
==80117== total heap usage: 128 allocs, 134 frees, 3,112 bytes allocated
==80117==
==80117== All heap blocks were freed -- no leaks are possible
==80117==
==80117== For counts of detected and suppressed errors, rerun with: -v
==80117== ERROR SUMMARY: 13 errors from 5 contexts (suppressed: 4 from 4)
运行GDB的结果:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401511 in freeDiscs (discs=0x0, MAX_SLOTS=5) at discs.c:140
140 discs = discs->next;
(gdb) backtrace
#0 0x0000000000401511 in freeDiscs (discs=0x0, MAX_SLOTS=5) at discs.c:140
#1 0x00000000004011c2 in freeList (list=0x604220, MAX_SLOTS=5) at AST.c:404
#2 0x0000000000401e25 in main (argc=2, argv=0x7fffffffe048) at main.c:129
(gdb)
从边缘删除多个具有相同状态的节点的函数:
/* removes nodes from the fringe and then returns the fringe */
struct AST_Node * removeFringe(struct AST_Node * fringe, struct AST_Node * remove, int MAX_SLOTS) {
struct AST_Node * head, * current, * prev, * delete;
int remove_switch = 0;
head = fringe;
current = fringe;
prev = fringe;
/* traverse the fringe until the end */
while (current != NULL) {
/* when the current node has the same state as the one for removal */
if (isSame(current->state, remove->state, MAX_SLOTS)) {
/* when removing from the head */
if (current == head) {
head = current->parent;
delete = current;
current = head;
freeDiscs(delete->state, MAX_SLOTS);
free(delete);
delete = NULL;
remove_switch = 1;
}
/* when the node to be removed is at the end of the list */
else if (current->parent == NULL && current != NULL) {
delete = current;
current = NULL;
freeDiscs(delete->state, MAX_SLOTS);
free(delete);
delete = NULL;
remove_switch = 1;
}
/* when the node to be removed is in the middle of the list */
else {
delete = current;
current = current->parent;
prev->parent = current;
/* ---- line 266 and 267 below ---- */
freeDiscs(delete->state, MAX_SLOTS);
free(delete);
delete = NULL;
remove_switch = 1;
}
}
if (remove_switch == 0) {
prev = current;
current = current->parent;
}
remove_switch = 0;
}
return head;
}
免费列表功能:
/* free's an AST_Node list */
void freeList(struct AST_Node * list, int MAX_SLOTS) {
struct AST_Node * current, * prev;
current = list;
/* when a list must be free'd, free it */
if (current != NULL) {
/* traverse and free until the last node */
while (current != NULL) {
prev = current;
current = current->parent;
/* ---- line 404 below ---- */
freeDiscs(prev->state, MAX_SLOTS);
free(prev);
prev = NULL;
}
}
}
免费光盘功能:
/* frees's a discs_slot list */
void freeDiscs(struct discs_slot * discs, int MAX_SLOTS) {
int i = 0;
struct discs_slot * temp;
while (i < MAX_SLOTS) {
temp = discs;
discs = discs->next;
/* ---- line 141 below ---- */
free(temp);
i++;
}
}
主要相关守则:
/* until reaching a solution or the maximum traversals allowed */
while (!isGoal(best_current->state) && Towards_Solution < Solution_Count) {
/* when the best current node has not already been expanded */
if (!inClosed(closed_list, best_current, Max_Slots)) {
/* expand it and add the nodes to the fringe */
fringe_list = addFringe(fringe_list, best_current, goal_state, Max_Slots);
/* add the expanded node to the closed list */
closed_list = addClosed(closed_list, best_current);
}
/* when the best node is in the closed list */
else {
/* do nothing */
}
printSmallDiscs(best_current->state, Max_Slots);
/* get a new best node to evaluate and remove it from the fringe */
best_current = fringeTraverse(fringe_list, best_current, goal_state, Max_Slots);
/* ---- line 104 below ---- */
fringe_list = removeFringe(fringe_list, best_current, Max_Slots);
Towards_Solution++;
/* when all possible nodes have been expanded and no solution exists */
if (fringe_list == NULL) {
printf("No solution\n");
break;
}
}
/* return memory */
freeDiscs(discs_list, Max_Slots);
freeDiscs(goal_state, Max_Slots);
freeList(best_current, Max_Slots);
/* ---- line 129 below ---- */
freeList(fringe_list, Max_Slots);
freeList(closed_list, Max_Slots);
return 0;
}
这是添加条纹函数:
/* creates new nodes from the best current state and adds those nodes to the fringe */
struct AST_Node * addFringe(struct AST_Node * list, struct AST_Node * best, struct discs_slot * goal, int MAX_SLOTS) {
struct AST_Node * move_LCW, * move_LCCW, * move_ACW, * move_ACCW;
struct AST_Node * current, * head, * prev;
current = list;
head = list;
/* break apart the current best state for a possible solution */
move_LCW = largeCW(best, goal, MAX_SLOTS);
move_LCCW = largeCCW(best, goal, MAX_SLOTS);
move_ACW = adjacentCW(best, goal, MAX_SLOTS);
move_ACCW = adjacentCCW(best, goal, MAX_SLOTS);
/* store these new nodes in the fringe */
/* when storing in the fringe for the first time */
if (current == NULL) {
//printf("Empty Fringe:\n\n");
current = move_LCW;
current->parent = move_LCCW;
current->parent->parent = move_ACW;
current->parent->parent->parent = move_ACCW;
current->parent->parent->parent->parent = NULL;
//printf("List Start --------------------\n");
//printList(current, MAX_SLOTS);
//printf("List End --------------------\n");
}
/* when storing in a partially filled fringe */
else {
/* traverse to the end and start adding nodes from there */
while (current != NULL) {
prev = current;
current = current->parent;
//printf("*\n");
}
//printf("Fringe not empty new nodes added:\n\n");
current = move_LCW;
current->parent = move_LCCW;
current->parent->parent = move_ACW;
current->parent->parent->parent = move_ACCW;
current->parent->parent->parent->parent = NULL;
//printf("List Start --------------------\n");
//printList(current, MAX_SLOTS);
//printf("List End --------------------\n");
prev->parent = current;
current = head;
}
//printf("Entire Fringe: \n\n");
//printList(head, MAX_SLOTS);
//printf("____________________\n");
return current;
}
这是复制大小为MAX_SLOTS的光盘列表的函数(它最终读为NULL)
/* creates a copy of a disc slot list */
struct discs_slot * copy_dlist(struct discs_slot * discs, int MAX_SLOTS) {
struct discs_slot * head, * current;
current = malloc(sizeof(struct discs_slot));
if (current == NULL) {
printf("\nAn error ocurred when trying to allocate memory.\n");
exit(0);
}
head = current;
/* traverse for as many disc slots that exist and copy the data from
the disc slot list passed in to the new one */
for (int i = 0; i < MAX_SLOTS; i++) {
current->large = discs->large;
current->small = discs->small;
current->position = discs->position;
if (i < (MAX_SLOTS - 1)) {
struct discs_slot * new_dslot;
new_dslot = malloc(sizeof(struct discs_slot));
if (new_dslot == NULL) {
printf("\nAn error ocurred when trying to allocate memory.\n");
exit(0);
}
current->next = new_dslot;
current = new_dslot;
}
discs = discs->next;
}
current->next = head;
current = head;
return current;
}
答案 0 :(得分:1)
根据问题的症状,您的程序会遇到某种无效的堆内存读取。这通常发生在我们的程序尝试读取内存free
或内存free
两次之后。如果我们看到Valgrind报告摘要,我们会收到以下信息:
total heap usage: 128 allocs, 134 frees, 3,112 bytes allocated
您的计划已分配 128 分配并尝试释放 134 时间。这表示程序中的双重自由场景。由于在释放内存后已将指针指定为NULL,因此稍后程序会在程序尝试访问NULL指针时遇到分段错误。
查看堆栈跟踪,几乎不可能找出导致此问题的根本原因,因为这些分段错误会在真正坏的情况发生后(在释放内存后将指针设置为NULL)完成通过早期执行中的程序。
识别这些内存损坏的最佳方法是同时使用GDB
和Valgrind
。为此,您可能希望在Valgrind / GDB中附加您的程序(a.out)。
$ valgrind --tool=memcheck --db-attach=yes ./a.out
这样,当您检测到第一个内存错误时,Valgrind会将您的程序附加到调试器中,以便您可以进行实时调试(GDB)。这应该是理解和解决问题的最佳方式。一旦你能够弄清楚你的第一个错误,修复它并重新运行它,看看你得到的其他错误。这个步骤应该完成,直到Valgrind没有报告错误。