Visual Studio put a breakpoint there to be helpful because you got an error at that place. If I do it on a somewhat recent Linux (Mint 20) with a somewhat recent clang (12.0.0) I got the following output:
$ 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's (GNU debugger) backtrace points to the same line as VS did.
And if I (your mileage may vary because: Google) copy and paste it as it is into Google I got Why do I get a C malloc assertion failure? as the first hit. The accepted answer points in the right way and we shall ask Valgrind for some hints.
$ 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==
...
We can stop here because we found the reason: you have a buffer overflow because you start with count = 0
in createMatrix(int r, int c)
which results in the lack of the memory necessary for the last Tuple
. Change it to count = 1
and it should work.
Let's check:
$ 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)
...
There is still a problem and it is in printTuple(Tuple* tuple)
now, because we changed the initialization of count
but did not adapt the value in tuple[0].data
so the upper limit in the line for (int i = 0; i <= tuple[0].data; i++)
is too large. Either correct it here or there, does not matter much, I would correct the upper limit in the loop because tuple[0].data
holds the correct number of non-zero entries. So change the loop to for (int i = 0; i < tuple[0].data; i++)
Check again:
$ 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)
...
Looking at the lines in question (your line numbers may be different): it is the same upper limit problem as before. Change it and check again.
$ 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)
Nice, no problems anymore. For that exact input at least. But I squeezed a little printf("tuple[0].data + 1 = %d, sizet(Tuple) = %zu\n",tuple[0].data + 1, sizeof(Tuple) );
in before the calloc()
and it says
tuple[0].data + 1 = 14, sizet(Tuple) = 12
That is one Tuple
too much; save some memory and change it by removing the + 1
in calloc
. That's it.
I used Unix tools here, most of them are available for Windows, but VS has all necessary tools, too, they just have different names and get used differently. Try to find them and check your original code (of which you know the errors now) with them to get familiar with that toolchain. You really need that knowledge!