2017-04-11 159 views
0

在嘗試自己學習C時,我遇到了這個我想開發的簡單程序。它只是試圖利用指針數組的指針來創建類似於矩陣的東西。我在Windows上編譯,當我運行它時,它只是崩潰,同時,在Linux上嘗試這個代碼它說segmentation fault,這是因爲函數參數是數組?我在這裏做錯了什麼?瞭解指針數組的指針作爲函數的參數

#include <stdio.h> 
#include <stdlib.h> 

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"); 
    } 
} 

回答

1

做時:

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); 
+2

功能(並且是三星級的程序員不是恭維) –

+0

是,三星級的程序員:你會避免這種情況。 –

+0

@ Jean-FrançoisFabre啊,我明白了,沒有注意到,但在那之後,我應該如何在main()中調用函數?分配給'array_1'足夠了嗎? – lorenzattractor

0

如果你想有一個函數來修改參數的值,則必須將指針傳遞給該參數:

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運營商您的取消引用目標,而不是類型名稱:

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); 

那留出空間,爲連續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(); 
    } 
}