将指针指针的指针理解为函数中的参数
在尝试自己学习C的同时,我遇到了这个我想要开发的简单程序。 它只是试图利用指向指针数组的指针来制作类似于矩阵的东西。 我在Windows上编译,当我运行它时,它只是崩溃,同时,在Linux上尝试这个代码它说segmentation fault
,这是因为函数参数是数组吗? 我在这做错了什么?
#include #include void initializeArray(float** array, int size); void printArray(float** array, int size); int main() { float** array_1 = NULL; int array_size = 3; initializeArray(array_1, array_size); // Free memory from array for (int i = 0; i < array_size; i++) { free(array_1[i]); } free(array_1); return 0; } void initializeArray(float** array, int size) { array = malloc(size * sizeof(float*)); if (array) { for (int i = 0; i < size; i++) { array[i] = malloc(size * sizeof(float)); if (!array[i]) { exit(0); } } } for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { array[i][j] = 0; } } } void printArray(float** array, int size) { for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { printf("%f\t", array[i][j]); } printf("\n"); } }
做的时候:
void initializeArray(float** array, int size) { array = malloc(size * sizeof(float*));
你没有在函数外部更改array
,所以array_1
在调用之后(像之前一样)指向NULL(并创建内存泄漏)。 您需要返回它(或将其作为三重***
指针传递并将其用作*array
,但这不太方便)。
float **initializeArray(int size) { float** array = malloc(size * sizeof(float*)); ... return array; }
从主要:
array_1 = initializeArray(array_size);
如果希望函数修改参数的值,则必须传递指向该参数的指针:
void foo( T *ptr ) { *ptr = new_value(); // write a new value to the thing ptr points to } void bar( void ) { T var; foo( &var ); // write a new value to var }
对于任何类型T
都是如此,包括指针类型。 用P *
替换T
,我们得到
void foo( P **ptr ) { *ptr = new_value(); // write a new value to the thing ptr points to } void bar( void ) { P *var; foo( &var ); // write a new *pointer* value to var }
基本上,无论var
的类型如何,你都需要为ptr
一个间接级别。
将其应用于您的代码:
void initializeArray(float*** array, int size) { *array = malloc(size * sizeof(float*)); if (*array) { for (int i = 0; i < size; i++) { (*array)[i] = malloc(size * sizeof(float)); // parens matter; you want if (!(*array)[i]) // to index into what array *points { // to*, not array itself exit(0); } } } for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { (*array)[i][j] = 0; } } }
将从main
调用:
initializeArray(&array_1, array_size);
一些建议:
首先,在调用malloc
,将sizeof
运算符的操作数sizeof
取消引用的目标,而不是类型名称:
ptr = malloc( N * sizeof *ptr );
在你的情况下,它会
*array = malloc( size * sizeof **array ); // sizeof operand has one more level of // indirection than target
和
(*array)[i] = malloc( size * sizeof *(*array)[i] );
如果你改变array
的类型,这将保护你; 你不必追逐sizeof (float)
或sizeof (float *)
每个实例并更改它们。
其次,你分配的不是2D数组 - 它是一个指针数组,每个指针指向一个单独的float
数组。 哪个是完美的,取决于你正在做什么,只要知道行在内存中不相邻 - array[1][2]
后面的对象不会是array[2][0]
。
如果你想分配一个连续的多维数组,你可以使用类似的东西
float (*array)[3] = malloc( 3 * sizeof *array );
这为连续的3x3arrays留出了空间。 使用VLA语法,您可以编写类似的函数
void initializeArray( size_t rows, size_t cols, float (**array)[cols] ) { *array = malloc( rows * sizeof **array ); if ( *array ) { for ( size_t i = 0; i < rows; i++ ) for ( size_t j = 0; j < rows; j++ ) (*array)[i][j] = initial_value(); } }