将指针指针的指针理解为函数中的参数

在尝试自己学习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(); } }