簡體   English   中英

我對C上的malloc()和calloc()非常困惑

[英]I'm very confused about malloc() and calloc() on C

我總是用Java編程,這可能就是為什么我對此很困惑:

在Java中我聲明了一個指針:

int[] array

並初始化它或為其分配一些內存:

int[] array = {0,1,0}
int[] array = new int[3]

現在,在C中,這一切都讓人感到困惑。 起初我以為它就像宣布它一樣容易:

int array[]

並初始化它或為其分配一些內存:

int array[] = {0,1,0}
int array[] = malloc(3*sizeof(int))
int array[] = calloc(3,sizeof(int))

除非我錯了,以上所有內容都等同於Java-C,對嗎?

然后,今天我遇到了一個代碼,其中我發現了以下內容:

pthread_t tid[MAX_OPS];

以及下面的一些行,沒有任何初始化......

pthread_create(&tid[0],NULL,mou_usuari,(void *) 0);

令人驚訝的是(至少對我而言)代碼有效! 至少在Java中,會返回一個很好的“NullPointerException”!

所以,按順序:

  1. 我是否正確使用所有Java-C“翻譯”?

  2. 為什么該代碼有效?

  3. 使用malloc(n*sizeof(int))calloc(n,sizeof(int))之間有什么區別嗎?

提前致謝

您無法將內存分配給陣列。 數組在整個生命周期內都有固定的大小。 數組永遠不能為空。 數組不是指針。

malloc將地址返回給為程序保留的內存塊。 你不能將(作為內存塊)“分配”給一個數組,但你可以將這個內存塊的地址存儲在一個指針中:幸運的是,數組預訂是通過指針定義的 - 所以你可以“使用像數組一樣的指針” ,例如

int *ptr = malloc(5 * sizeof *ptr);
ptr[2] = 5; // access the third element "of ptr"
free(ptr); // always free at the end

當聲明一個沒有大小的數組(即array[] )時,它只是意味着數組的大小是從初始化列表中確定的。 那是

int array[] = {1, 2, 3, 4, 5}; // is equal to
int array[5] = {1, 2, 3, 4, 5};

嘗試聲明沒有大小而沒有初始化程序的數組是一個錯誤。


代碼pthread_t tid[MAX_OPS]; 聲明一個名為tid的數組,類型為pthread_t ,大小為MAX_OPS

如果數組具有自動存儲(即聲明在函數內部而不是靜態,而不是全局),則每個數組元素都具有不確定的值(並且它會導致嘗試讀取此類值的未定義行為)。 幸運的是,函數調用所做的就是它將數組的第一個元素的地址作為第一個參數,並且可能在函數內初始化它(元素)。


callocmalloc的區別在於calloc返回的內存塊被初始化為零。 那是;

int *ptr = calloc(5, sizeof *ptr);
// is somewhat equal to
int *ptr = malloc(5 * sizeof *ptr);
memset(ptr, 0, 5 * sizeof *ptr);

和...之間的不同

int *ptr = malloc(5 * sizeof *ptr);
// and
int array[5];

是該array具有自動存儲(存儲在堆棧中),並在超出范圍后“釋放”。 然而, ptr (存儲在堆上)是動態分配的,並且必須由程序員free d。

你缺少三個非常基本和緊縮(和誤導!)C主題:

  • 數組和指針之間的區別
  • 靜態和動態分配之間的區別
  • 與在堆棧或堆上聲明變量的區別

如果你寫int array[] = malloc(3*sizeof(int)); ). 你會得到一個編譯錯誤(類似 )。

這意味着聲明一個數組只允許靜態初始化:

  • int array[] = {1,2,3}; 在堆棧上保留3個連續的整數;
  • int array[3] = {1,2,3}; 與前一個相同;
  • int array[3]; 仍然在堆棧上保留3個連續的整數,但不初始化它們(內容將是隨機垃圾)
  • int array[4] = {1,2,3}; 當初始化列表沒有初始化所有元素時,其余的被設置為0(C99§6.7.8/ 19):在這種情況下你將獲得1,2,3,0

請注意,在所有這些情況下,您沒有分配新內存,您只是使用已經提交到堆棧的內存。 只有當堆棧已滿時才會遇到問題(猜測它會是堆棧溢出 )。 因此聲明int array[]; 會是錯誤的,毫無意義的。

要使用malloc您必須聲明一個指針: int* array

當你寫int* array = malloc(3*sizeof(int)); 你實際上做了三個操作:

  1. int* array告訴編譯器在棧上保留一個指針(一個包含內存地址的整數變量)
  2. malloc(3*sizeof(int))在堆上分配3個連續的整數並返回第一個的地址
  3. =將返回值(已分配的第一個整數的地址)的副本分配給指針變量

那么,回到你的問題:

pthread_t tid[MAX_OPS];

堆棧中是一個數組,因此不需要分配(如果MAX_OPS是16,那么堆棧上將保留適合16 pthread_t所需的連續字節數)。 這個內存的內容將是垃圾(堆棧變量未初始化為零),但pthread_create在其第一個參數(指向pthread_t變量的指針)中返回一個值,並忽略任何先前的內容,因此代碼就可以了。

C提供靜態內存分配以及動態 - 您可以從堆棧或可執行內存(由編譯器管理)分配數組。 這與Java中的方式相同,您可以在堆棧上分配int或在堆上分配Integer。 C中的數組就像任何其他堆棧變量一樣 - 它們超出范圍等。在C99中,它們也可以具有可變大小,盡管它們無法調整大小。

{}和malloc / calloc之間的主要區別在於{}數組是靜態分配的(不需要釋放)並自動為您初始化,而malloc / calloc數組必須顯式釋放,您必須顯式初始化它們。 但是,當然,malloc / calloc數組不會超出范圍,你可以(有時)realloc()它們。

2 - 此數組聲明是靜態的:

pthread_t tid[MAX_OPS];

我們不需要分配內存塊,而不是動態分配:

pthread_t *tid = (pthread_t *)malloc( MAX_OPS * sizeof(pthread_t) );

別忘了釋放記憶:

free(tid);

3 - malloc和calloc之間的區別是calloc為數組分配一塊內存,並將其所有位初始化為0。

我發現當你用C語言編程(而不是C ++)來明確指示*數組時要記住有一個可以移動的指針。 所以我想首先將你的例子改為:

int array[] = {0,1,2};
int *array = malloc(3*sizeof(int));
int *array = calloc(3,sizeof(int));

第一個清楚地表明有一個叫做數組的東西指向一個包含0,1和2的內存塊。數組不能在其他地方移動。

你的下一個代碼:pthread_t tid [MAX_OPS];

實際上是否會導致分配sizeof(pthread_t)* MAX_OPS的數組。 但它沒有分配一個名為* tid的指針。 有一個數組基址的地址,但你不能把它移到別處。

ptherad_t類型實際上是指針的封面。 所以上面的tid實際上是一個指針數組。 它們都是靜態分配的,但它們沒有初始化。

pthread_create獲取數組開頭的位置( &tid[0] ),它是一個指針,並分配一塊內存來保存pthread數據結構。 指針設置為指向新數據結構並分配數據結構。

你的最后一個問題--- malloc(n*sizeof(int))calloc(n,sizeof(int))之間的區別在於后者將每個字節初始化為0 ,而第一個不是。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM