Понимание указателя на указательные массивы как аргументы в функции

Пытаясь самостоятельно изучить 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 , включая типы указателей. Заменим T на P * , и получим

 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 вашей разыменованной цели, а не типом имени:

 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 *) и изменять их.

Во-вторых, то, что вы выделяете, не является двумерным массивом - это массив указателей, каждый из которых указывает на отдельный массив float . Что отлично, в зависимости от того, что вы делаете, просто помните, что строки не смежны в памяти - объект, следующий за array[1][2] , не будет array[2][0] .

Если вы хотите выделить смежный multidimensional array, вы должны использовать что-то вроде

 float (*array)[3] = malloc( 3 * sizeof *array ); 

Это выделяет пространство для смежного массива 3x3. С синтаксисом 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(); } }