【问题标题】:ApplicationName.exe has triggered a breakpoint in visual studioApplicationName.exe 在 Visual Studio 中触发了断点
【发布时间】:2021-07-12 07:31:33
【问题描述】:
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%4d\n", 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 放了一个?

【问题讨论】:

  • 你确定这是一个断点吗?也许这只是一次崩溃,您正在越界访问内存?
  • 您的代码不完整。 createMatrix 在哪里? (好像你在一开始就切断了一些东西,因为你发布的代码中的第 47 行是你对第 47 行的评论下方的几行)。其余的请补充,谢谢。
  • 第 47 行是哪一行?
  • @CherryDT 是的,这是一个断点

标签: c visual-studio debugging matrix breakpoints


【解决方案1】:

Visual Studio 在那里放置了一个断点以提供帮助,因为您在该位置遇到了错误。如果我在最近的 Linux (Mint 20) 和最近的 clang (12.0.0) 上执行此操作,我会得到以下输出:

$ echo -e '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12' | ./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 相同的行。

如果我(您的里程可能会有所不同,因为:Google)将其复制并粘贴到 Google 中,我会得到Why do I get a C malloc assertion failure? 作为第一个点击。接受的答案指向正确的方式,我们将向 Valgrind 寻求一些提示。

$ echo -e '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12' |  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 '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12' |  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 &lt;= tuple[0].data; i++)这一行的上限太大了。在这里或那里更正它并不重要,我会更正循环中的上限,因为tuple[0].data 拥有正确数量的非零条目。所以把循环改成for (int i = 0; i &lt; tuple[0].data; i++)

再次检查:

$ echo -e '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12' |  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 '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12' |  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) = %zu\n",tuple[0].data + 1, sizeof(Tuple) );,它说

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

那一个Tuple太多了;节省一些内存并通过删除calloc 中的+ 1 来更改它。就是这样。

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

【讨论】:

    猜你喜欢
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2014-11-02
    • 2018-09-25
    相关资源
    最近更新 更多