c-ApplicationName.exe在visual studio中触发了一个断点


typedef struct Tuple
{
int row;
int col;
int data;
} Tuple;
int** createMatrix(int r, int c)
{
int** mat = (int**)malloc(sizeof(int*) * r);
for (int i = 0; i < r; i++)
mat[i] = malloc(sizeof(int) * c);
return mat;
}
Tuple* createTuple(int** mat, int r, int c)
{
int count = 0;
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
if (mat[i][j])
count++;
Tuple* tuple = (Tuple*)malloc(sizeof(Tuple) * count);
tuple[0].col = c;
tuple[0].row = r;
tuple[0].data = count;
int k = 1;
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
if (mat[i][j])
{
tuple[k].col = j;
tuple[k].row = i;
tuple[k++].data = mat[i][j];
}
return tuple;
}
Tuple* fastTranspose(Tuple* tuple)
{
Tuple* trans = (Tuple*)calloc((tuple[0].data + 1),sizeof(Tuple) );
trans[0].col = tuple[0].row;
trans[0].row = tuple[0].col;
trans[0].data = tuple[0].data;
int* rowTerms = (int*)malloc(sizeof(int) * tuple[0].col);
int* startingPos = (int*)malloc(sizeof(int) * tuple[0].col);
for (int i = 0; i < tuple[0].col; i++)
rowTerms[i] = 0;
for (int i = 1; i <= tuple[0].data; i++)
rowTerms[tuple[i].col]++;
startingPos[0] = 1;
for (int i = 1; i < tuple[0].col; i++)
startingPos[i] = startingPos[i - 1] + rowTerms[i - 1];
for (int i = 1; i <= tuple[0].data; i++)
{
int j = startingPos[tuple[i].col]++;
trans[j].col = tuple[i].row;
trans[j].row = tuple[i].col;
trans[j].data = tuple[i].data;
}
free(rowTerms);
free(startingPos);
return trans;
}
void printTuple(Tuple* tuple)
{
printf("nRow Col Val:n");
for (int i = 0; i <= tuple[0].data; i++)
{
printf("%3d%4d%4dn", tuple[i].row, tuple[i].col, tuple[i].data);
}
}
int main()
{
int** mat = createMatrix(3, 4);
printf("Enter data:n");
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
scanf("%d", &mat[i][j]);
Tuple* tuple = createTuple(mat, 3, 4);
printf("Original tuple:");
printTuple(tuple);
Tuple* trans = fastTranspose(tuple);
printf("Tuple transpose:");
printTuple(trans);
free(trans);
free(tuple);
for (int i = 0; i < 3; i++)
free(mat[i]);
free(mat);
}

为什么断点是在函数fastTranspose的第一行触发的,尽管我没有在那里放一个?

我研究过类似的问题,但没能找到解决办法。这是一个求矩阵转置的程序。我们首先动态地分配一个二维矩阵。然后将其转换为稀疏矩阵表示形式,该形式使用结构来存储行、列和数据的值。我尝试打印矩阵和元组的值。它奏效了。但是当进入快速转置函数时,会突然触发一个断点。

我们通常自己在visual studio中设置一个断点。为什么IDE会放一个?

Visual Studio在那里放置了一个断点以提供帮助,因为您在那个地方遇到了错误。如果我在最近的Linux(Mint 20(上使用最近的clang(12.0.0(,我会得到以下输出:

$ echo -e '1n2n3n4n5n6n7n8n9n10n11n12' | ./so_tmat 
Enter data:
Original tuple:
Row Col Val:
3   4  12
0   0   1
0   1   2
0   2   3
0   3   4
1   0   5
1   1   6
1   2   7
1   3   8
2   0   9
2   1  10
2   2  11
2   3  12
tuple[0].data + 1 = 13, sizet(Tuple) = 12
so_tmat: malloc.c:2379: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed.
Aborted (core dumped)

GDB(GNU调试器(的回溯指向与VS相同的行。

如果我(你的里程数可能会有所不同,因为:谷歌(将其原样复制并粘贴到谷歌中,我会得到为什么我会得到C malloc断言失败?作为第一支安打。公认的答案指向正确的方向,我们将向Valgrind寻求一些提示。

$ echo -e '1n2n3n4n5n6n7n8n9n10n11n12' |  valgrind  --track-origins=yes --leak-check=full --show-leak-kinds=all  ./so_tmat 
==16047== Memcheck, a memory error detector
==16047== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16047== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==16047== Command: ./so_tmat
==16047== 
Enter data:
==16047== Invalid write of size 8
==16047==    at 0x40144D: createTuple (so_tmat.c:38)
==16047==    by 0x40144D: main (so_tmat.c:89)
==16047==  Address 0x4a796a0 is 0 bytes after a block of size 144 alloc'd
==16047==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16047==    by 0x401377: createTuple (so_tmat.c:28)
==16047==    by 0x401377: main (so_tmat.c:89)
==16047== 
==16047== Invalid write of size 4
==16047==    at 0x401452: createTuple (so_tmat.c:39)
==16047==    by 0x401452: main (so_tmat.c:89)
==16047==  Address 0x4a796a8 is 8 bytes after a block of size 144 alloc'd
==16047==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16047==    by 0x401377: createTuple (so_tmat.c:28)
==16047==    by 0x401377: main (so_tmat.c:89)
==16047== 
...

我们可以在这里停止,因为我们找到了原因:您有缓冲区溢出,因为您在createMatrix(int r, int c)中从count = 0开始,这导致缺少最后一个Tuple所需的内存。将其更改为count = 1,它应该可以工作。

让我们检查一下:

$ echo -e '1n2n3n4n5n6n7n8n9n10n11n12' |  valgrind  --track-origins=yes --leak-check=full --show-leak-kinds=all  ./so_tmat 
==16215== Memcheck, a memory error detector
==16215== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16215== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==16215== Command: ./so_tmat
==16215== 
Enter data:
Original tuple:
Row Col Val:
3   4  13
0   0   1
0   1   2
0   2   3
0   3   4
1   0   5
1   1   6
1   2   7
1   3   8
2   0   9
2   1  10
2   2  11
2   3  12
==16215== Invalid read of size 4
==16215==    at 0x4014A0: printTuple (so_tmat.c:78)
==16215==    by 0x4014A0: main (so_tmat.c:91)
==16215==  Address 0x4a796b4 is 8 bytes after a block of size 156 alloc'd
==16215==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16215==    by 0x40137A: createTuple (so_tmat.c:28)
==16215==    by 0x40137A: main (so_tmat.c:89)
...

仍然存在一个问题,现在它在printTuple(Tuple* tuple)中,因为我们更改了count的初始化,但没有调整tuple[0].data中的值,所以for (int i = 0; i <= tuple[0].data; i++)行中的上限太大。在这里或那里纠正它,没有太大关系,我会在循环中纠正上限,因为tuple[0].data包含正确数量的非零条目。因此,将循环更改为for (int i = 0; i < tuple[0].data; i++)

再次检查:

$ echo -e '1n2n3n4n5n6n7n8n9n10n11n12' |  valgrind  --track-origins=yes --leak-check=full --show-leak-kinds=all  ./so_tmat 
==16328== Memcheck, a memory error detector
==16328== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16328== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==16328== Command: ./so_tmat
==16328== 
Enter data:
Original tuple:
Row Col Val:
3   4  13
0   0   1
0   1   2
0   2   3
0   3   4
1   0   5
1   1   6
1   2   7
1   3   8
2   0   9
2   1  10
2   2  11
2   3  12
tuple[0].data + 1 = 14, sizet(Tuple) = 12
==16328== Invalid read of size 4
==16328==    at 0x4015B1: fastTranspose (so_tmat.c:56)
==16328==    by 0x4015B1: main (so_tmat.c:92)
==16328==  Address 0x4a796b0 is 4 bytes after a block of size 156 alloc'd
==16328==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16328==    by 0x40137A: createTuple (so_tmat.c:28)
==16328==    by 0x40137A: main (so_tmat.c:89)
==16328== 
==16328== Invalid read of size 4
==16328==    at 0x4017D0: fastTranspose (so_tmat.c:63)
==16328==    by 0x4017D0: main (so_tmat.c:92)
==16328==  Address 0x4a796b0 is 4 bytes after a block of size 156 alloc'd
==16328==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16328==    by 0x40137A: createTuple (so_tmat.c:28)
==16328==    by 0x40137A: main (so_tmat.c:89)
==16328== 
==16328== Invalid read of size 4
==16328==    at 0x4017DF: fastTranspose (so_tmat.c:64)
==16328==    by 0x4017DF: main (so_tmat.c:92)
==16328==  Address 0x4a796ac is 0 bytes after a block of size 156 alloc'd
==16328==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16328==    by 0x40137A: createTuple (so_tmat.c:28)
==16328==    by 0x40137A: main (so_tmat.c:89)
==16328== 
==16328== Invalid read of size 4
==16328==    at 0x4017ED: fastTranspose (so_tmat.c:66)
==16328==    by 0x4017ED: main (so_tmat.c:92)
==16328==  Address 0x4a796b4 is 8 bytes after a block of size 156 alloc'd
==16328==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==16328==    by 0x40137A: createTuple (so_tmat.c:28)
==16328==    by 0x40137A: main (so_tmat.c:89)
...

看看有问题的行(你的行号可能不同(:这是和以前一样的上限问题。更改并再次检查。

$ echo -e '1n2n3n4n5n6n7n8n9n10n11n12' |  valgrind  --track-origins=yes --leak-check=full --show-leak-kinds=all  ./so_tmat 
==16420== Memcheck, a memory error detector
==16420== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16420== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==16420== Command: ./so_tmat
==16420== 
Enter data:
Original tuple:
Row Col Val:
3   4  13
0   0   1
0   1   2
0   2   3
0   3   4
1   0   5
1   1   6
1   2   7
1   3   8
2   0   9
2   1  10
2   2  11
2   3  12
tuple[0].data + 1 = 14, sizet(Tuple) = 12
Tuple transpose:
Row Col Val:
4   3  13
0   0   1
0   1   5
0   2   9
1   0   2
1   1   6
1   2  10
2   0   3
2   1   7
2   2  11
3   0   4
3   1   8
3   2  12
==16420== 
==16420== HEAP SUMMARY:
==16420==     in use at exit: 0 bytes in 0 blocks
==16420==   total heap usage: 10 allocs, 10 frees, 5,548 bytes allocated
==16420== 
==16420== All heap blocks were freed -- no leaks are possible
==16420== 
==16420== For lists of detected and suppressed errors, rerun with: -s
==16420== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

很好,没有问题了。至少对于那个精确的输入。但我在calloc()之前挤了一点printf("tuple[0].data + 1 = %d, sizet(Tuple) = %zun",tuple[0].data + 1, sizeof(Tuple) );,上面写着

tuple[0].data + 1 = 14, sizet(Tuple) = 12

这是一个Tuple太多;保存一些内存并通过删除CCD_ 15中的CCD_。就是这样。

我在这里使用了Unix工具,其中大多数都适用于Windows,但VS也有所有必要的工具,它们只是有不同的名称,使用方式也不同。试着找到它们,并与它们一起检查您的原始代码(您现在知道其中的错误(,以熟悉该工具链。你真的需要这些知识!

最新更新