gpt4 book ai didi

c - 如何查找指针错误?

转载 作者:太空宇宙 更新时间:2023-11-04 02:21:32 25 4
gpt4 key购买 nike

我正在尝试通过创建下国际象棋的 AI 来学习 C。当我尝试释放一些内存时,我不小心释放了一些我正在使用的内存。

我通过 valgrind 运行程序,所以我可以看到内存错误在哪里,但我不明白为什么要释放内存。我在 ubuntu 变体(PopOS!)上运行。

这是生成可能的移动并选择一个的代码,我认为错误出在 while 循环附近,其中包含 tempOut->next 变量。

void initDataSet()
{

printf("Starting Data init\n");
setupBoard(currentBoard->board);
currentBoard->parent = 0;
currentBoard->children = 0;
findPossibleMoves(1, currentBoard); //aiutils.c:189
depth++;
struct boardStateList* temp[6];
int isAITurn[6];
int bestValue[6];

int count = 0;
struct boardStateList* counter = currentBoard->children;

while(counter)
{
count++;
counter = counter->next;
}


for(int i = 0;i < 6;i++)
if(((depth + i)% 2) == isAIWhite)
{
isAITurn[i] = 1;
}
else
{
isAITurn[i] = 0;
}
int turn = 1;
temp[0] = currentBoard->children;
bestValue[0] = (depth - 1) % 2 == isAIWhite ? INT_MIN : INT_MAX;
while(temp[0])
{
printf("calc Move %d out of %d\n", turn++, count);

bestValue[1] = (depth) % 2 == isAIWhite ? INT_MIN : INT_MAX;
findPossibleMoves((depth % 2), temp[0]->element);
temp[1] = temp[0]->element->children;
while(temp[1])
{
bestValue[2] = (depth + 1) % 2 == isAIWhite ? INT_MIN : INT_MAX;
findPossibleMoves(((depth + 1) % 2), temp[1]->element);
temp[2] = temp[1]->element->children;
while(temp[2])
{
bestValue[3] = (depth + 2) % 2 == isAIWhite ? INT_MIN : INT_MAX;
findPossibleMoves(((depth + 2) % 2), temp[2]->element);
temp[3] = temp[2]->element->children;
while(temp[3])
{
bestValue[4] = (depth + 3) % 2 == isAIWhite ? INT_MIN : INT_MAX;
findPossibleMoves(((depth + 3) % 2), temp[3]->element);
temp[4] = temp[3]->element->children;
while(temp[4])
{
bestValue[5] = (depth + 4) % 2 == isAIWhite ? INT_MIN : INT_MAX;
findPossibleMoves(((depth + 4) % 2),temp[4]->element);
temp[5] = temp[4]->element->children;
while(temp[5])
{
temp[5]->element->boardValue = evaluateBoard(temp[5]->element->board, isAIWhite);
if((depth + 4) % 2 == isAIWhite ? temp[5]->element->boardValue > bestValue[5] : temp[5]->element->boardValue < bestValue[5])
bestValue[5] = temp[5]->element->boardValue;
temp[5] = temp[5]->next;
}
temp[4]->element->boardValue = bestValue[5];
if((depth + 3) % 2 == isAIWhite ? temp[4]->element->boardValue > bestValue[4] : temp[4]->element->boardValue < bestValue[4])
bestValue[4] = temp[4]->element->boardValue;
temp[4] = temp[4]->next;
}
temp[3]->element->boardValue = bestValue[4];
if((depth + 2) % 2 == isAIWhite ? temp[3]->element->boardValue > bestValue[3] : temp[3]->element->boardValue < bestValue[3])
bestValue[3] = temp[3]->element->boardValue;
temp[3] = temp[3]->next;
}


temp[2]->element->boardValue = bestValue[3];
if((depth + 1) % 2 == isAIWhite ? temp[2]->element->boardValue > bestValue[2] : temp[2]->element->boardValue < bestValue[2])
bestValue[2] = temp[2]->element->boardValue;
temp[2] = temp[2]->next;
}
temp[1]->element->boardValue = bestValue[2];
if((depth) % 2 == isAIWhite ? temp[1]->element->boardValue > bestValue[1] : temp[1]->element->boardValue < bestValue[1])
bestValue[1] = temp[1]->element->boardValue;
temp[1] = temp[1]->next;
}
temp[0]->element->boardValue = bestValue[1];
if((depth - 1) % 2 == isAIWhite ? temp[0]->element->boardValue > bestValue[0] : temp[0]->element->boardValue < bestValue[0])
bestValue[0] = temp[0]->element->boardValue;
temp[0] = temp[0]->next;
}


if((depth - 1 ) % 2 == isAIWhite)
{

struct boardStateList* tempOut = malloc(sizeof(struct boardStateList));
struct boardStateList* tempOutCopy = tempOut;
tempOut->next = currentBoard->children;


while(tempOut->next)
{
if(tempOut->next->element->boardValue == bestValue[0])
{
currentBoard = tempOut->next->element;
tempOut->next = tempOut->next->next;
break;
}
tempOut = tempOut->next;
}

free(tempOutCopy);

killChildren(currentBoard->parent);

printBoard(currentBoard->board); //aiutils.c:303
}
else
{
int sourceRow, sourceCol, destRow, destCol;
printf("Source Row:");
scanf("%d", &sourceRow);
printf("Source Col:");
scanf("%d", &sourceCol);
printf("destRow:");
scanf("%d", &destRow);
printf("destCol:");
scanf("%d", &destCol);

struct boardStateList* tempOut = malloc(sizeof(struct boardStateList));
struct boardStateList* tempOutCopy = tempOut;
tempOut->next = currentBoard->children;


while(tempOut->next)
{
if(currentBoard->board[sourceRow * 8 + sourceCol] == tempOut->next->element->board[destRow * 8 + destCol])
{
currentBoard = tempOut->next->element;
tempOut->next = tempOut->next->next;
break;
}
tempOut = tempOut->next;
}

if(!tempOut)
{
printf("No Move Found\n");
exit(1);
}

free(tempOutCopy);

killChildren(currentBoard->parent);

}



}

这段代码为开发板分配内存

void addChildBoard(struct boardState* parent, int sourceRow, int sourceCol, int destRow, int destCol)
{
//create new childboard and init values
struct boardState* child = malloc(sizeof(struct boardState));
if(!child)
printf("OOM");
child->parent = parent;
child->children = 0;
//add child to parent linked lisk
struct boardStateList* current = parent->children;
if(!current)
{
parent->children = malloc(sizeof(struct boardStateList));
if(!parent->children)
printf("OOM");
parent->children->element = child;
parent->children->next = 0;
}
else
{
while((current->next))
current = current->next;
current->next = malloc(sizeof(struct boardStateList));
if(!current->next)
printf("OOM");
current->next->element = child;
current->next->next = 0;
}
//init child board to parent then make change
//for(int i = 0;i < 64;i++)
// child->board[i] = parent->board[i];
memcpy(child->board, parent->board, 64);
child->board[destRow * 8 + destCol] = child->board[sourceRow * 8 + sourceCol];
child->board[sourceRow * 8 + sourceCol] = 0;
}

这段代码释放内存

void killChildren(struct boardState* parent)
{
struct boardStateList* temp[7];

temp[0] = parent->children;
while(temp[0])
{
temp[1] = temp[0]->element->children;
while(temp[1])
{
temp[2] = temp[1]->element->children;
while(temp[2])
{
temp[3] = temp[2]->element->children;
while(temp[3])
{
temp[4] = temp[3]->element->children;
while(temp[4])
{
temp[5] = temp[4]->element->children;
while(temp[5])

{
free(temp[5]->element);
temp[6] = temp[5];
temp[5] = temp[5]->next;
free(temp[6]);
}

free(temp[4]->element);
temp[6] = temp[4];
temp[4] = temp[4]->next;
free(temp[6]);
}
free(temp[3]->element);
temp[6] = temp[3];
temp[3] = temp[3]->next;
free(temp[6]);
}


free(temp[2]->element);
temp[6] = temp[2];
temp[2] = temp[2]->next;
free(temp[6]);
}
free(temp[1]->element);
temp[6] = temp[1];
temp[1] = temp[1]->next;
free(temp[6]);
}
free(temp[0]->element); //aiutils.c:742
temp[6] = temp[0];
temp[0] = temp[0]->next;
free(temp[6]);
}


}

当我尝试读取其中一个输出板时,它部分出现乱码,然后程序出现段错误。这是 valgrind 的输出

==3013== Memcheck, a memory error detector
==3013== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==3013== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==3013== Command: ./chess white
==3013== Parent PID: 2898
==3013==
--3013--
--3013-- Valgrind options:
--3013-- --leak-check=full
--3013-- --show-leak-kinds=all
--3013-- --track-origins=yes
--3013-- --verbose
--3013-- --log-file=valgrind-out.txt
--3013-- Contents of /proc/version:
--3013-- Linux version 4.14.123-111.109.amzn2.x86_64 (mockbuild@ip-10-0-1-12) (gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)) #1 SMP Mon Jun 10 19:37:57 UTC 2019
--3013--
--3013-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-avx-avx2-bmi
--3013-- Page sizes: currently 4096, max supported 4096
--3013-- Valgrind library directory: /usr/lib64/valgrind
--3013-- Reading syms from /home/ec2-user/chess-ai/chess
--3013-- Reading syms from /usr/lib64/ld-2.26.so
--3013-- Reading syms from /usr/lib64/valgrind/memcheck-amd64-linux
--3013-- object doesn't have a symbol table
--3013-- object doesn't have a dynamic symbol table
--3013-- Scheduler: using generic scheduler lock implementation.
--3013-- Reading suppressions file: /usr/lib64/valgrind/default.supp
==3013== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-3013-by-ec2-user-on-ip-172-31-14-154.ec2.internal
==3013== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-3013-by-ec2-user-on-ip-172-31-14-154.ec2.internal
==3013== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-3013-by-ec2-user-on-ip-172-31-14-154.ec2.internal
==3013==
==3013== TO CONTROL THIS PROCESS USING vgdb (which you probably
==3013== don't want to do, unless you know exactly what you're doing,
==3013== or are doing some strange experiment):
==3013== /usr/lib64/valgrind/../../bin/vgdb --pid=3013 ...command...
==3013==
==3013== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==3013== /path/to/gdb ./chess
==3013== and then give GDB the following command
==3013== target remote | /usr/lib64/valgrind/../../bin/vgdb --pid=3013
==3013== --pid is optional if only one valgrind process is running
==3013==
--3013-- REDIR: 0x401cd20 (ld-linux-x86-64.so.2:strlen) redirected to 0x5805bed1 (???)
--3013-- REDIR: 0x401cb00 (ld-linux-x86-64.so.2:index) redirected to 0x5805beeb (???)
--3013-- Reading syms from /usr/lib64/valgrind/vgpreload_core-amd64-linux.so
--3013-- Reading syms from /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so
==3013== WARNING: new redirection conflicts with existing -- ignoring it
--3013-- old: 0x0401cd20 (strlen ) R-> (0000.0) 0x5805bed1 ???
--3013-- new: 0x0401cd20 (strlen ) R-> (2007.0) 0x04c2fc50 strlen
--3013-- REDIR: 0x401ad90 (ld-linux-x86-64.so.2:strcmp) redirected to 0x4c30d80 (strcmp)
--3013-- REDIR: 0x401d260 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4c34390 (mempcpy)
--3013-- Reading syms from /usr/lib64/libc-2.26.so
--3013-- REDIR: 0x4ebf9b0 (libc.so.6:memmove) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebebe0 (libc.so.6:strncpy) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfc90 (libc.so.6:strcasecmp) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebe630 (libc.so.6:strcat) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebec10 (libc.so.6:rindex) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ec1260 (libc.so.6:rawmemchr) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfb20 (libc.so.6:mempcpy) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebf950 (libc.so.6:bcmp) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebeba0 (libc.so.6:strncmp) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebe6a0 (libc.so.6:strcmp) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfa80 (libc.so.6:memset) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ed94c0 (libc.so.6:wcschr) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebeb40 (libc.so.6:strnlen) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebe710 (libc.so.6:strcspn) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfce0 (libc.so.6:strncasecmp) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebe6e0 (libc.so.6:strcpy) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfe20 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebec40 (libc.so.6:strpbrk) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebe660 (libc.so.6:index) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebeb10 (libc.so.6:strlen) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ec5b10 (libc.so.6:memrchr) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfd30 (libc.so.6:strcasecmp_l) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebf920 (libc.so.6:memchr) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4eda280 (libc.so.6:wcslen) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebeef0 (libc.so.6:strspn) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfc60 (libc.so.6:stpncpy) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfc30 (libc.so.6:stpcpy) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ec1290 (libc.so.6:strchrnul) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4ebfd80 (libc.so.6:strncasecmp_l) redirected to 0x4a2771e (_vgnU_ifunc_wrapper)
--3013-- REDIR: 0x4f8ebf0 (libc.so.6:__strrchr_avx2) redirected to 0x4c2f5d0 (rindex)
--3013-- REDIR: 0x4ebaf00 (libc.so.6:malloc) redirected to 0x4c2cb0d (malloc)
--3013-- REDIR: 0x4f8edc0 (libc.so.6:__strlen_avx2) redirected to 0x4c2fb90 (strlen)
--3013-- REDIR: 0x4f8ea00 (libc.so.6:__strchrnul_avx2) redirected to 0x4c33ec0 (strchrnul)
--3013-- REDIR: 0x4f8f2e0 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4c33fd0 (mempcpy)
--3013-- REDIR: 0x4ebb590 (libc.so.6:free) redirected to 0x4c2dcba (free)
==3013== Invalid read of size 1
==3013== at 0x404062: prinmtBoard (chessutils.c:254)
==3013== by 0x403625: initDataSet (aiutils.c:303)
==3013== by 0x4006EB: main (main.c:38)
==3013== Address 0x51ef524 is 4 bytes inside a block of size 88 free'd
==3013== at 0x4C2DD28: free (vg_replace_malloc.c:530)
==3013== by 0x402604: killChildren (aiutils.c:742)
==3013== by 0x403615: initDataSet (aiutils.c:301)
==3013== by 0x4006EB: main (main.c:38)
==3013== Block was alloc'd at
==3013== at 0x4C2CB7B: malloc (vg_replace_malloc.c:299)
==3013== by 0x400988: addChildBoard (aiutils.c:657)
==3013== by 0x400DA2: findPossiblePawnMoves (aiutils.c:472)
==3013== by 0x402F6B: findPossibleMoves (aiutils.c:434)
==3013== by 0x402F6B: initDataSet (aiutils.c:189)
==3013== by 0x4006EB: main (main.c:38)
==3013==
==3013==
==3013== Process terminating with default action of signal 1 (SIGHUP)
==3013== at 0x4F1F892: write (in /usr/lib64/libc-2.26.so)
==3013== by 0x4EB1D7C: _IO_file_write@@GLIBC_2.2.5 (in /usr/lib64/libc-2.26.so)
==3013== by 0x4EB105E: new_do_write (in /usr/lib64/libc-2.26.so)
==3013== by 0x4EB2F68: _IO_do_write@@GLIBC_2.2.5 (in /usr/lib64/libc-2.26.so)
==3013== by 0x4EB3011: _IO_file_underflow@@GLIBC_2.2.5 (in /usr/lib64/libc-2.26.so)
==3013== by 0x4EB41E1: _IO_default_uflow (in /usr/lib64/libc-2.26.so)
==3013== by 0x4E9503C: _IO_vfscanf (in /usr/lib64/libc-2.26.so)
==3013== by 0x4EA3957: __isoc99_scanf (in /usr/lib64/libc-2.26.so)
==3013== by 0x4026D3: nextMove (aiutils.c:24)
==3013== by 0x4006F6: main (main.c:42)
==3013==
==3013== HEAP SUMMARY:
==3013== in use at exit: 104 bytes in 2 blocks
==3013== total heap usage: 232,874,525 allocs, 232,874,523 frees, 12,109,477,208 bytes allocated
==3013==
==3013== Searching for pointers to 2 not-freed blocks
==3013== Checked 69,400 bytes
==3013==
==3013== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
==3013== at 0x4C2CB7B: malloc (vg_replace_malloc.c:299)
==3013== by 0x402670: nextMove (aiutils.c:15)
==3013== by 0x4006F6: main (main.c:42)
==3013==
==3013== 88 bytes in 1 blocks are definitely lost in loss record 2 of 2
==3013== at 0x4C2CB7B: malloc (vg_replace_malloc.c:299)
==3013== by 0x4006DD: main (main.c:37)
==3013==
==3013== LEAK SUMMARY:
==3013== definitely lost: 88 bytes in 1 blocks
==3013== indirectly lost: 0 bytes in 0 blocks
==3013== possibly lost: 0 bytes in 0 blocks
==3013== still reachable: 16 bytes in 1 blocks
==3013== suppressed: 0 bytes in 0 blocks
==3013==
==3013== ERROR SUMMARY: 65 errors from 2 contexts (suppressed: 0 from 0)
==3013==
==3013== 64 errors in context 1 of 2:
==3013== Invalid read of size 1
==3013== at 0x404062: printBoard (chessutils.c:254)
==3013== by 0x403625: initDataSet (aiutils.c:303)
==3013== by 0x4006EB: main (main.c:38)
==3013== Address 0x51ef524 is 4 bytes inside a block of size 88 free'd
==3013== at 0x4C2DD28: free (vg_replace_malloc.c:530)
==3013== by 0x402604: killChildren (aiutils.c:742)
==3013== by 0x403615: initDataSet (aiutils.c:301)
==3013== by 0x4006EB: main (main.c:38)
==3013== Block was alloc'd at
==3013== at 0x4C2CB7B: malloc (vg_replace_malloc.c:299)
==3013== by 0x400988: addChildBoard (aiutils.c:657)
==3013== by 0x400DA2: findPossiblePawnMoves (aiutils.c:472)
==3013== by 0x402F6B: findPossibleMoves (aiutils.c:434)
==3013== by 0x402F6B: initDataSet (aiutils.c:189)
==3013== by 0x4006EB: main (main.c:38)
==3013==
==3013== ERROR SUMMARY: 65 errors from 2 contexts (suppressed: 0 from 0)

最佳答案

这段代码读起来没什么吸引力 x) 但我将向您展示如何使用 valgrind 的输出自行查找问题 ;)

==3013== Invalid read of size 1
==3013== at 0x404062: prinmtBoard (chessutils.c:254)
==3013== by 0x403625: initDataSet (aiutils.c:303)
==3013== by 0x4006EB: main (main.c:38)
==3013== Address 0x51ef524 is 4 bytes inside a block of size 88 free'd
==3013== at 0x4C2DD28: free (vg_replace_malloc.c:530)
==3013== by 0x402604: killChildren (aiutils.c:742)
==3013== by 0x403615: initDataSet (aiutils.c:301)
==3013== by 0x4006EB: main (main.c:38)
==3013== Block was alloc'd at
==3013== at 0x4C2CB7B: malloc (vg_replace_malloc.c:299)
==3013== by 0x400988: addChildBoard (aiutils.c:657)
==3013== by 0x400DA2: findPossiblePawnMoves (aiutils.c:472)
==3013== by 0x402F6B: findPossibleMoves (aiutils.c:434)
==3013== by 0x402F6B: initDataSet (aiutils.c:189)
==3013== by 0x4006EB: main (main.c:38)

这里有 1 个内存错误的 3 个详细信息:

  • 错误是大小为 1 的无效读取,因此您尝试访问不在(不再)在您的内存中的 1 字节内存区域。 (发生在 chessutils.c:254 的第 254 行)
  • 地址 xxx 是 88 个已释放 block 中的 4 个字节。这意味着您尝试访问的内存曾经是您的,但现在已经不属于您了,因为您刚刚在 aiutils.c 的第 742 行释放了它
  • 您释放然后使用的内存块在文件 aiutils 的第 657 行分配。

这通常应该足以跟踪您的代码过程并找到错误,找到 malloc,您释放它的地方,然后是您仍然使用不再属于您的内存的任何地方;)

如果在此之后您仍然崩溃,但错误已更改,则您可能取得了进步。不要忘记一个错误总是可以被另一个错误隐藏,在内存调试方面更是如此。

祝你好运

关于c - 如何查找指针错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57236389/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com