[英]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”!
所以,按順序:
我是否正確使用所有Java-C“翻譯”?
為什么該代碼有效?
使用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
。
如果數組具有自動存儲(即聲明在函數內部而不是靜態,而不是全局),則每個數組元素都具有不確定的值(並且它會導致嘗試讀取此類值的未定義行為)。 幸運的是,函數調用所做的就是它將數組的第一個元素的地址作為第一個參數,並且可能在函數內初始化它(元素)。
calloc
和malloc
的區別在於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));
你實際上做了三個操作:
int* array
告訴編譯器在棧上保留一個指針(一個包含內存地址的整數變量) malloc(3*sizeof(int))
在堆上分配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.