C编程:用于2D数组的malloc()(使用指针到指针)
昨天我发布了一个问题: 我应该如何传递指向函数的指针并为被调用函数内部传递的指针分配内存?
从我得到的答案中,我能够理解我在做什么错误。
我现在面临一个新问题,任何人都可以帮忙解决这个问题吗?
我想动态分配一个2D数组,所以我将指针从我的main()
传递给另一个名为alloc_2D_pixels(...)
函数,其中我使用malloc(...)
和for(...)
循环为2D数组分配内存。
好吧,从alloc_2D_pixels(...)
函数返回后,指针指针仍然保持为NULL,所以很自然地,当我尝试访问或尝试free(...)
指针到指针时,程序挂起。
谁能告诉我我在这里犯的错误?
救命!!!
维克拉姆
资源:
main() { unsigned char **ptr; unsigned int rows, cols; if(alloc_2D_pixels(&ptr, rows, cols)==ERROR) // Satisfies this condition printf("Memory for the 2D array not allocated"); // NO ERROR is returned if(ptr == NULL) // ptr is NULL so no memory was allocated printf("Yes its NULL!"); // Because ptr is NULL, with any of these 3 statements below the program HANGS ptr[0][0] = 10; printf("Element: %d",ptr[0][0]); free_2D_alloc(&ptr); } signed char alloc_2D_pixels(unsigned char ***memory, unsigned int rows, unsigned int cols) { signed char status = NO_ERROR; memory = malloc(rows * sizeof(unsigned char** )); if(memory == NULL) { status = ERROR; printf("ERROR: Memory allocation failed!"); } else { int i; for(i = 0; i< cols; i++) { memory[i] = malloc(cols * sizeof(unsigned char)); if(memory[i]==NULL) { status = ERROR; printf("ERROR: Memory allocation failed!"); } } } // Inserted the statements below for debug purpose only memory[0][0] = (unsigned char)10; // I'm able to access the array from printf("\nElement %d",memory[0][0]); // here with no problems return status; } void free_2D_pixels(unsigned char ***ptr, unsigned int rows) { int i; for(i = 0; i < rows; i++) { free(ptr[i]); } free(ptr); }
一个错误是发布无法编译的代码:)。 以下是我的评论中的更正代码
/ *这种风格* /:
/* Next four lines get your code to compile */ #include #include #define NO_ERROR 0 #define ERROR 1 /* prototypes for functions used by main but declared after main (or move main to the end of the file */ signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols); void free_2D_pixels(unsigned char** ptr, unsigned int rows); /* main should return int */ int main() { unsigned char** ptr; /* need to define rows and cols with an actual value */ unsigned int rows = 5, cols = 5; if(alloc_2D_pixels(&ptr, rows, cols) == ERROR) // Satisfies this condition printf("Memory for the 2D array not allocated"); // ERROR is returned if(ptr == NULL) // ptr is NULL so no memory was allocated printf("Yes its NULL!"); else { /* Added else clause so below code only runs if allocation worked. */ /* Added code to write to every element as a test. */ unsigned int row,col; for(row = 0; row < rows; row++) for(col = 0; col < cols; col++) ptr[0][0] = (unsigned char)(row + col); /* no need for &ptr here, not returning anything so no need to pass by reference */ free_2D_pixels(ptr, rows); } return 0; } signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols) { signed char status = NO_ERROR; /* In case we fail the returned memory ptr will be initialized */ *memory = NULL; /* defining a temp ptr, otherwise would have to use (*memory) everywhere ptr is used (yuck) */ unsigned char** ptr; /* Each row should only contain an unsigned char*, not an unsigned char**, because each row will be an array of unsigned char */ ptr = malloc(rows * sizeof(unsigned char*)); if(ptr == NULL) { status = ERROR; printf("ERROR: Memory allocation failed!"); } else { /* rows/cols are unsigned, so this should be too */ unsigned int i; /* had an error here. alloced rows above so iterate through rows not cols here */ for(i = 0; i < rows; i++) { ptr[i] = malloc(cols * sizeof(unsigned char)); if(ptr[i] == NULL) { status = ERROR; printf("ERROR: Memory allocation failed!"); /* still a problem here, if exiting with error, should free any column mallocs that were successful. */ } } } /* it worked so return ptr */ *memory = ptr; return status; } /* no need for *** here. Not modifying and returning ptr */ /* it also was a bug...would've needed (*ptr) everywhere below */ void free_2D_pixels(unsigned char** ptr, unsigned int rows) { /* should be unsigned like rows */ unsigned int i; for(i = 0; i < rows; i++) { free(ptr[i]); } free(ptr); }
在alloc_2D_pixels
函数中,访问memory
时需要另一级别的间接。 就像现在一样,您只修改参数,而不是参数指向的指针。 例如,
memory = malloc(rows * sizeof(unsigned char** )); // becomes *memory = malloc(rows * sizeof(unsigned char** )); // and later... memory[i] = malloc(cols * sizeof(unsigned char)); // becomes (*memory)[i] = malloc(cols * sizeof(unsigned char));
(基本上,在你使用memory
任何地方,你需要使用(*memory)
;只有当你使用下标来确保运算符以正确的顺序应用时才需要括号)
它看起来也像,你正在使用未初始化的rows
和cols
变量
在C中以这种方式使用多维数组对于性能来说是“次优的”。
毫不含糊的话: 请不要以你所说明的方式使用 – 并且绝对不会初始化 – 多维数组。 对malloc()
多次调用将创建一批不相交的内存位置,这些位置无法很好地映射到实际图形(如连续的单个缓冲区)存储在何处。 此外,如果你必须做成百次或数千次, malloc()
可能非常昂贵。
此外,由于您经常使用malloc(),因此清理也是一场噩梦(以及最终咬你的错误)。 您甚至在代码中的注释中提到过,但是……为什么?
如果你绝对必须有这个ptr[rows][cols]
东西,那就更好地创建它:
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols) { int colspan = cols * sizeof(char); int rowspan = rows * sizeof(char*); unsigned char **rowptrs = *memory = malloc(rowspan + rows * colspan)); /* malloc failure handling left to the reader */ unsigned char *payload = ((unsigned char *)rowptrs) + rowspan; int i; for (i = 0; i < rows; payload += colspan, i++) rowptrs[i] = payload; }
那样你只分配一块内存,整个东西可以在一个go - ditch free_2D_pixels()
释放。