我需要在C语言中实现动态矩阵。
我主要有这段代码:
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows, cols;
scanf("%d", &rows);
scanf("%d", &cols);
int** A = create_matrix(rows, cols);
fill_matrix(A, rows, cols);
add_row(A, &rows, cols);
print_matrix(A, rows, cols);
free_matrix(A, rows);
return 0;
}
如您所见,我分配矩阵,然后通过以下方式填充它:
4 3
1 1 1
2 2 2
3 3 3
4 4 4
我想添加新行 [1, 1, 1],然后打印,然后自由。以下是函数
void add_row(int **matrix, int *rows_amount, int cols_amount)
{
printf("startedn");
(*rows_amount)++;
matrix = (int**)realloc(matrix, (*rows_amount) * sizeof(int*));
matrix[*rows_amount - 1] = (int*)malloc(cols_amount * sizeof(int));
for (int j = 0; j < cols_amount; j++)
matrix[*rows_amount - 1][j] = 1;
printf("endedn");
return;
}
int **create_matrix(int rows_amount, int cols_amount)
{
int **matrix = (int**)malloc(rows_amount * sizeof(int*));
for(int i = 0; i < rows_amount; i++)
matrix[i] = (int*)malloc(cols_amount * sizeof(int));
return matrix;
}
void fill_matrix(int **matrix, int rows_amount, int cols_amount)
{
for(int i = 0; i < rows_amount; i++)
for(int j = 0; j < cols_amount; j++)
scanf("%d", matrix[i] + j);
}
void free_matrix(int **matrix, int rows_amount)
{
for(int i = 0; i < rows_amount; i++)
free(matrix[i]);
free(matrix);
}
void print_matrix(int **matrix, int rows_amount, int cols_amount)
{
for(int i = 0; i < rows_amount; i++)
{
for(int j = 0; j < cols_amount; j++)
printf("%d ", matrix[i][j]);
printf("n");
}
}
当我使用 valgrind 找到导致 SEGFAULT 的线时,我得到这个:
stepan@WIN-KBCGJ2G97TU:/mnt/d/Desktop/study/sem3/c_prog/lab_09$ valgrind ./app.out < 1.txt
==2715== Memcheck, a memory error detector
==2715== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2715== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2715== Command: ./app.out // I add < d.txt which contains test
==2715==
==2715== error calling PR_SET_PTRACER, vgdb might block
started // between this and next lines no errors! this is in add_row
ended
==2715== Invalid read of size 8
==2715== at 0x1089F9: print_matrix (matrix.c:33)
==2715== by 0x109048: main (main.c:19)
==2715== Address 0x522e080 is 0 bytes inside a block of size 32 free'd
==2715== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2715== by 0x108DC5: add_row (matrix.c:102)
==2715== by 0x109034: main (main.c:17)
==2715== Block was alloc'd at
==2715== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2715== by 0x1088A9: create_matrix (matrix.c:8)
==2715== by 0x109006: main (main.c:11)
==2715==
1 1 1
2 2 2
3 3 3
4 4 4 // on the next line must have been 1 1 1
==2715== Invalid read of size 4
==2715== at 0x108A09: print_matrix (matrix.c:33)
==2715== by 0x109048: main (main.c:19)
==2715== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==2715==
==2715==
==2715== Process terminating with default action of signal 11 (SIGSEGV)
==2715== Access not within mapped region at address 0x0
==2715== at 0x108A09: print_matrix (matrix.c:33)
==2715== by 0x109048: main (main.c:19)
==2715== If you believe this happened as a result of a stack
==2715== overflow in your program's main thread (unlikely but
==2715== possible), you can try to increase the size of the
==2715== main thread stack using the --main-stacksize= flag.
==2715== The main thread stack size used in this run was 8388608.
==2715==
==2715== HEAP SUMMARY:
==2715== in use at exit: 100 bytes in 6 blocks
==2715== total heap usage: 9 allocs, 3 frees, 8,324 bytes allocated
==2715==
==2715== LEAK SUMMARY:
==2715== definitely lost: 40 bytes in 1 blocks
==2715== indirectly lost: 60 bytes in 5 blocks
==2715== possibly lost: 0 bytes in 0 blocks
==2715== still reachable: 0 bytes in 0 blocks
==2715== suppressed: 0 bytes in 0 blocks
==2715== Rerun with --leak-check=full to see details of leaked memory
==2715==
==2715== For counts of detected and suppressed errors, rerun with: -v
==2715== ERROR SUMMARY: 14 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
所以,似乎有些事情发生在add_row:
matrix = (int**)realloc(matrix, (*rows_amount) * sizeof(int*));
matrix[*rows_amount - 1] = (int*)malloc(cols_amount * sizeof(int));
这是真的 99.9%,因为不添加行,只需创建、填充和释放,没有内存错误。
而且我不明白为什么Invalid read of size 8
在所有打印行之前(matrix.c:33
是printf("%d ", matrix[i][j]);
(,然后他尝试读取 4 个字节 ̄_(ツ(_/̄。
怎么了?
更新。
我添加了返回矩阵;在主 A = add_row... 它有效!感谢大家的C记忆课:)
add_row
函数修改matrix
并使旧值无效,但不会将新值返回给调用方。
问题是add_row()
通过realloc()
更改matrix
的值,但调用函数 - 在main()
,也许? 没有看到这种变化。
同样,如果add_row()
更改了cols_amount
的值,则调用者将看不到该更改。你不在乎这个。
但是您确实关心行计数更改对调用方可见,因此您正确传递了rows_amount
的地址,以便当add_row()
将一个添加到行计数时,调用方会看到该更改。
通过传递指针的地址对matrix
执行相同的操作:
int add_row(int ***pMatrix, int *rows_amount, int cols_amount)
{
(*pMatrix) = realloc(*pMatrix, ...)
(*pMatrix)[*rows_amount - 1] = ...
// use (*pMatrix) where you used to use matrix
}
int main()
{
...
add_row(&matrix, &rows, cols);
编辑:从评论中回答一些问题;
当您分配内存时,该空间将为您保留,并且您会得到一个指针,并且下一个内存请求通常在第一个请求之后立即分配,可能由一些填充或内务管理隔开。 这意味着第一个和第二个分配或多或少彼此相邻。
|---alloc1---|
|---alloc1---| |---alloc2---|
realloc(alloc1)
返回相同指针的唯一方法是分配后是否有可用空间:如果发生这种情况,那么它将调整内务处理并返回相同的指针。
但在这里我们发现alloc2
挡住了,没有空间扩展alloc1
,所以它别无选择,只能保留一个新的位置,复制东西过来,然后发布第一个:
|---alloc1---|
|---alloc1---| |---alloc2---|
|---alloc2---| |---bigger alloc1-------|
我想向realloc()
请求更少的内存会返回相同的指针,因为它可以更新内务管理,但这不是必需的,实际上你永远不会依赖它。
EDIT2在实践中,我不会以这种方式解决问题。我会创建一个结构来保存指针加上行/列计数,这样它就可以作为单个项目传递,而不是一次传递所有三个部分。
struct matrix {
int rows;
int cols;
int **cells;
};