2012-12-15 36 views
2

在這個玩具的代碼示例:的C指針的幫助:數組/指針等價

int MAX = 5; 

void fillArray(int** someArray, int* blah) { 
    int i; 
    for (i=0; i<MAX; i++) 
    (*someArray)[i] = blah[i]; // segfault happens here 
} 

int main() { 
    int someArray[MAX]; 
    int blah[] = {1, 2, 3, 4, 5}; 

    fillArray(&someArray, blah); 

    return 0; 
} 

...我要填充數組的someArray,並有持續變化的函數之外。

這是一個非常大的家庭作業的一部分,這個問題解決了這個問題,而不允許我複製解決方案。我給了一個接受int **作爲參數的函數簽名,並且我應該編寫邏輯來填充該數組。我的印象是,取消引用& fillArray()函數中的someArray會給我所需的數組(一個指向第一個元素的指針),並且對該數組使用括號數組元素訪問會給我需要的必要位置分配。但是,我無法弄清楚爲什麼我會遇到段錯誤。

非常感謝!

+1

'嗒嗒[5]''到嗒嗒[999]'是外部邊界。你爲什麼在'fillArray'中訪問它們? –

+0

我很確定指針聲明的指針也是錯誤的。 –

+0

沒有錯,只是多餘的 – StoryTeller

回答

3

我想填充數組someArray,並使更改持久存在於函數之外。

陣列只是傳遞給函數,因爲它衰減到指針的第一個元素:

void fillArray(int* someArray, int* blah) { 
    int i; 
    for (i=0; i<MAX; i++) 
     someArray[i] = blah[i]; 
} 

和調用:

fillArray(someArray, blah); 

的元素的變化將是可見的外的功能。

如果實際代碼是內fillArray()分配數組那麼int**將需要:

void fillArray(int** someArray, int* blah) { 
    int i; 
    *someArray = malloc(sizeof(int) * MAX); 
    if (*someArray) 
    { 
     for (i=0; i<MAX; i++) /* or memcpy() instead of loop */ 
      (*someArray)[i] = blah[i]; 
    } 
} 

和調用:

int* someArray = NULL; 
fillArray(&someArray, blah); 
free(someArray); 
+0

這很有道理,爲什麼這個工程。但是,如果數組已經被分配,爲什麼傳遞&someArray到fillArray()並通過* someArray訪問數組本身導致了分段錯誤? – Maestro1

+0

@ Maestro1,它不應該。例如,請參閱http://ideone.com/4YAMfn。 – hmjd

0

沒有「陣列/指針」等價,並數組和指針是非常不同的。永遠不要混淆它們。 someArray陣列&someArray指向數組的指針,並且類型爲int (*)[MAX]。該函數需要一個指向指針的指針,即int **,它需要指向內存中某處的指針變量。代碼中的任何地方都沒有指針變量。它可能指向什麼?

一個數組值可以隱式地降解成指針右值在某些表達式其第一個元素。有些東西需要左值,比如取地址(&)顯然不適用於這種方式。下面是陣列類型和指針類型之間的一些差異:

  • 數組類型不能被分配或已過去。指針類型可以
  • 指針數組和指針的指針是不同類型的數組和指針的陣列的
  • 陣列不同類型
  • 數組類型的sizeof是長度倍組件類型的大小;指針的sizeof是 指針
1

當創建一個數組,如int myArray的[10] [20],存儲器的保證連續塊從堆棧分配的只是尺寸,並且正常數組算術用於查找數組中的任何給定元素。

如果您想從堆中分配3D「數組」,則使用malloc()並返回一些內存。那個記憶是「愚蠢的」。這只是一塊記憶,應該被認爲是一種向量。與數組無關的導航邏輯都不附帶,這意味着您必須找到另一種方式來導航所需的3D數組。

由於您對malloc()調用返回一個指針,你需要的第一個變量是一個指向持有INT的矢量* S你將需要舉行一些實際的整型數據IE:

INT *粒子陣列;

...但這仍然不是你想要存儲整數的存儲。你有什麼是一個指針數組,目前指向什麼都沒有。爲了獲得數據的存儲空間,需要調用malloc()10次,每個malloc()爲每次調用分配20個整數的空間,其返回指針將存儲在* pArray指針向量中。這意味着,

INT *粒子陣列

需要被改變到

INT **粒子陣列

正確表明它是一個指向指針的矢量的基。第一個解引用,* pArray [i],讓你在一個int指針數組中的某個地方,第二個解引用,* p [i] [j],將你引入一個int數組中的某個地方,指向pArray [i]中的一個int指針。

IE:你有一堆散佈在整個堆中的整數矢量雲,由指向數組的指針指向它們的位置。與堆棧中靜態分配的Array [10] [20]完全不同,它們都是連續存儲的,並且在任何地方都沒有單個指針。如其他人所知,基於指針的堆方法乍一看似乎並沒有多大用處,但事實證明,這種堆方法大大優越。

第一,最重要的是,您可以隨意()或realloc()來隨時調整堆內存大小,並且在函數返回時不會超出範圍。更重要的是,經驗豐富的C編程人員安排他們的功能在可能的情況下對向量進行操作,其中在函數調用中刪除了1級的間接尋址。最後,對於大型數組,相對於可用內存而言,特別是在大型共享機器上,大型連續內存塊通常不可用,並且對於其他需要內存操作的程序不友好。在堆棧上分配大量靜態數組的代碼是維護惡夢。

在這裏你可以看到,該表只是一個收集矢量操作返回的矢量指針的shell,其中所有有趣的事情都發生在矢量級或元素級。在這種特殊情況下,VecRand()中的向量代碼是calloc()它自己的存儲器,並將calloc()的返回指針返回給TblRand(),但TblRand也可以靈活地分配VecRand()僅通過與呼叫替換NULL參數VecRand()來釋放calloc()

/*-------------------------------------------------------------------------------------*/ 
dbl **TblRand(dbl **TblPtr, int rows, int cols) 
{ 
    int i=0; 

    if (NULL == TblPtr){ 
     if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*)))) 
      printf("\nCalloc for pointer array in TblRand failed"); 
    } 
    for (; i!=rows; i++){ 
     TblPtr[i] = VecRand(NULL, cols); 
    } 
    return TblPtr; 
} 
/*-------------------------------------------------------------------------------------*/ 

dbl *VecRand(dbl *VecPtr, int cols) 
{ 
    if (NULL == VecPtr){ 
     if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl)))) 
      printf("\nCalloc for random number vector in VecRand failed"); 
    } 

    Randx = GenRand(VecPtr, cols, Randx); 
    return VecPtr; 
} 
    /*--------------------------------------------------------------------------------------*/ 

static long GenRand(dbl *VecPtr, int cols, long RandSeed) 
{ 
    dbl r=0, Denom=2147483647.0; 

    while (cols--) 
    { 
     RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF; 
     r  = sqrt(-2.0 * log((dbl)(RandSeed/Denom))); 
     RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF; 
     *VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom)); 
     VecPtr++; 
    } 
    return RandSeed; 
}