解引用返回malloc分配指针的函数是否合法?能否用calloc替代?
二维数组单块内存分配的技术疑问
相关代码
结构体定义
struct sam { int **single_arr_mtrx; int *ptr; int row; int col; };
单块内存分配函数
//############################## single array matrix struct sam *alloc_sam (struct sam *matrix, int row, int col) { matrix -> single_arr_mtrx = malloc (row * col * sizeof(int) + row * sizeof(int*)); printf ("matrix at: %p\n", (void*) (matrix -> single_arr_mtrx)); matrix -> ptr = (int*) (matrix -> single_arr_mtrx + row); if (!matrix -> single_arr_mtrx) { printf ("can't allocate single array matrix\n"); exit(1); } else { printf ("Allocated chunk of %ld bytes(single array matrix).\n", row * col * sizeof (int) + row * sizeof(int*)); } matrix -> row = row; matrix -> col = col; for (int i = 0; i < row; ++i) { matrix -> single_arr_mtrx[i] = matrix -> ptr + col * i; printf ("Addr %d: %p\n", i, (void*) &(matrix -> single_arr_mtrx[i])); } return matrix; }
调用代码
void run_sam (void) { struct sam matrix; matrix = *alloc_sam (&matrix, ROW, COL); fill_sam (&matrix); print_sam (&matrix); dealloc_sam (&matrix); }
疑问与解答
我用单块内存实现了二维数组的分配,经valgrind检测无内存泄漏,但有两个技术疑问:
- 直接解引用
alloc_sam函数的返回值是否合法? - 能否使用
calloc替代当前的malloc实现该二维数组分配方式?当前malloc语句包含两种不同的sizeof计算,感觉实现难度较大。
问题1:直接解引用alloc_sam的返回值是否合法?
合法,但完全没必要。
你传入的&matrix是栈上结构体实例的地址,alloc_sam内部已经直接修改了这个结构体的所有成员(single_arr_mtrx、ptr、row、col),最后返回的也是这个指针。后续执行matrix = *alloc_sam(...),只是把已经修改好的结构体内容再拷贝一遍到栈上的matrix变量里——这步拷贝完全多余,直接调用alloc_sam(&matrix, ROW, COL);即可,不需要赋值操作。
从语法和内存安全角度,这么做完全合法:函数返回的是指向栈上合法结构体的指针,解引用它不会触发未定义行为,只是多了一次无意义的拷贝。
问题2:能否用calloc替代malloc实现?
当然可以,逻辑和malloc完全一致,只是替换函数调用即可。calloc的作用是分配指定大小的内存并初始化为0,参数为元素数量和每个元素的大小。你只需要把原来malloc的总字节数作为calloc的第二个参数(第一个参数传1),写法如下:
matrix->single_arr_mtrx = calloc(1, row * sizeof(int*) + row * col * sizeof(int));
或者也可以把总字节数拆成总元素数(以字节为单位)和每个元素1字节,写成calloc(row * sizeof(int*) + row * col * sizeof(int), 1),效果完全一样。
需要注意的是,calloc会把分配的内存初始化为0,所以行指针数组single_arr_mtrx的初始值会是0,但之后你会通过循环给每个single_arr_mtrx[i]赋值,会覆盖这些初始值,完全不影响功能。
内容的提问来源于stack exchange,提问作者Moses
相关产品推荐
相关产品推荐

