日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

c语言malloc引用类型作参数,C语言动态内存函数的理解和总结

發(fā)布時間:2024/8/1 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言malloc引用类型作参数,C语言动态内存函数的理解和总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

第一:內(nèi)存的使用

內(nèi)存可以分為以下三個主要的部分:棧區(qū)、堆區(qū)、靜態(tài)區(qū)

棧區(qū)(stack):存放的是局部變量、函數(shù)的形參等都是在該區(qū)上存放的。

堆區(qū)(heap):動態(tài)內(nèi)存函數(shù)開辟的空間。比如malloc realloc等函數(shù)。

靜態(tài)區(qū):存放的是全局變量或者靜態(tài)變量(由static關鍵字修飾的變量)。

第二:動態(tài)內(nèi)存函數(shù)

2.1 存在的價值

動態(tài)內(nèi)存函數(shù)可以向內(nèi)存申請大小可變的的空間,比如創(chuàng)建長度可以改變的數(shù)組時,就需要用到動態(tài)內(nèi)存函數(shù)malloc和realloc函數(shù)來實現(xiàn)。

但是C語言也是支持創(chuàng)建可變長度數(shù)組的(C99是支持的,以前是不支持的。如gcc編譯器是支持的)

在棧上開辟的空間大小是固定的,是不可改變的。

數(shù)組在定義時,其大小必須指明大小,不能是變量,因為其所需的內(nèi)存是在編譯時分配。

根據(jù)需求,我們所需要的的空間只有在運行時,才可知,則數(shù)組在編譯時開辟空間的方式就沒法滿足,因此需要動態(tài)開辟內(nèi)存空間。

如:

但是VS2019是不支持的。

2.2 動態(tài)內(nèi)存分配函數(shù)malloc和free

2.2.1 malloc函數(shù)介紹

作 用:向內(nèi)存的堆區(qū)申請一塊連續(xù)可用的空間:Allocates memory blocks.

函數(shù)原型:void *malloc( size_t size );

參 數(shù):size:Bytes to allocate(申請空間大小,單位:字節(jié))

返 回 值:返回void類型的指針(指向所申請空間的地址)(申請成功)

返回NULL(空指針)(如果沒有足夠內(nèi)存空間可用時,申請失敗)

注 意:返回類型是void類型的指針,因此使用的時候根據(jù)需求對其進行強制轉化為所需要的類型的指針變量。

如果參數(shù)值為0,C對此沒有做出明確解釋,具體結果,依據(jù)編譯器而定,因此,盡量不要出現(xiàn)這種情況。

需要對malloc的返回值進行檢查,因為有可能申請失敗的情況。

因為返回的是void類型的指針,因此需要對結果進行相應的強制類型轉化。

2.2.2 free函數(shù)的介紹

作 用:釋放和回收在堆區(qū)動態(tài)開辟的內(nèi)存空間:Deallocates or frees a memory block.

函數(shù)原型:void free( void *memblock );

參 數(shù):將要被釋放的內(nèi)存空間的地址

返 回 值:無返回值

注 意:只能釋動在堆區(qū)上開辟的態(tài)內(nèi)存的地址,否則報錯。

只能釋放一次,不能釋放多次。

free函數(shù)沒有將指針設為NULL的能力,即指針的值沒有發(fā)生變化,因此需要手動將其設為NULL,這樣避免后面不小心進行非法訪問內(nèi)存的情況發(fā)生。

如果沒有free,則會發(fā)生內(nèi)存泄露的情況,即申請的空間不釋放,也不同,別人也沒法用,

如果沒有free,只有當程序結束時,系統(tǒng)自動還給內(nèi)存,但是如果不結束,且會多次申請且不釋放,則會發(fā)生嚴重的內(nèi)存泄露。

因此要做到,誰申請,誰使用,誰釋放,誰使其設為空的原則。

2.2.3 malloc和free函數(shù)的使用

開辟成功時:

#include

#include

#include

#include

int main()

{

int i;

int len = 10;

// 向內(nèi)存開辟10個連續(xù)整型的空間,申請成功時,把空間的地址賦值給arr

int* arr = (int*)malloc(len * sizeof(int));

// 判斷開辟內(nèi)存空間是否成功,因為會開辟失敗

if (NULL == arr)

{

printf("%s\n", strerror(errno));

}

else

{

for (i = 0; i < len; i++)

{

*(arr + i) = i * i;

}

for (i = 0; i < len; i++)

{

printf("%d ",*(arr + i));

}

// 動態(tài)開辟的內(nèi)存,需要進行釋放,否則會導致內(nèi)存泄露

free(arr);

// 手動將指針設為空指針,因為free沒有將其設為空指針的能力

// 如果沒有將其手動設為空指針,且別別人使用該指針,則引起非法訪問內(nèi)存的錯誤。

arr = NULL;

}

return 0;

}

開辟失敗時:

#include

#include

#include

#include

int main()

{

int* arr = (int*)malloc(INT_MAX);

if (NULL == arr)

{

printf("%s\n", strerror(errno));

}

else

{

// do something.

free(arr);

arr = NULL;

}

return 0;

}

2.3 動態(tài)內(nèi)存分配函數(shù)calloc

2.3.1 calloc函數(shù)介紹

作 用:開始num個,每個大小為size個字節(jié)的一塊內(nèi)存空間,并將每個字節(jié)設為0。Allocates an array in memory with elements initialized to 0.

函數(shù)原型:void *calloc( size_t num, size_t size );

參 數(shù):num:Number of elements(申請元素的個數(shù))

size:Length in bytes of each element(每個元素所占字節(jié)空間大小)

返 回 值:同malloc

注 意:與malloc函數(shù)的區(qū)別:申請成功后,把空間的每個字節(jié)進行初始化為0,然后再講空間的地址進行返回。

2.3.2 malloc和calloc函數(shù)的比較

#include

#include

#include

#include

int main()

{

int len = 10;

int* p1 = (int*)malloc(len * sizeof(int));

int* p2 = (int*)calloc(len, sizeof(int));

int i;

if (NULL == p1)

{

printf("%s\n", strerror(errno));

}

else

{

// do something

printf("malloc 返回指針空間的內(nèi)容:隨機值:");

for (i = 0; i < len; i++) { printf("%d ",*(p1+i)); }

printf("\n");

free(p1);

p1 = NULL;

}

if (NULL == p2)

{

printf("%s\n", strerror(errno));

}

else

{

// do something...

printf("calloc 返回指針空間的內(nèi)容:0: ");

for (i = 0; i < len; i++) { printf("%d ", *(p2 + i)); }

printf("\n");

free(p2);

p2 = NULL;

}

return 0;

}

2.4 動態(tài)內(nèi)存分配函數(shù)realloc

2.4.1 realloc函數(shù)的說明

作 用:可以對動態(tài)申請的內(nèi)存空間大小進行調(diào)整。

函數(shù)原型:Reallocate memory blocks.

參 數(shù):memblock: Pointer to previously allocated memory block(將要修改的開辟內(nèi)存塊的地址)

size: New size in bytes(調(diào)整后的內(nèi)存塊的大小,新的大小)

返 回 值:同malloc和calloc,如果調(diào)整失敗,返回NULL,否則返回重新分配內(nèi)存塊的空間地址(該地址有可能會發(fā)生變化)

注 意:

1. 會將原來內(nèi)存空間上的數(shù)據(jù)移動到新的空間內(nèi)存中。

2. 調(diào)整內(nèi)存時存在兩種情況:

2.1. 原來申請的內(nèi)存空間后面有足夠的空間用于調(diào)整內(nèi)存。則會在原來內(nèi)存空間的后面直接追加空間到指定大小,并返回原空間的地址。

原來空間的內(nèi)容不發(fā)生變化。

2.2. 原來的空間沒有足夠的空間來滿足新的空間大小,則會在堆區(qū)重新找一塊連續(xù)空間來存放新的內(nèi)存空間。

原空間的內(nèi)容拷貝到新的空間中,釋放原來的內(nèi)存空間,把新的內(nèi)存空間的地址進行返回。

3. 用于接收realloc返回值的指針名最好不要和realloc的第一個參數(shù)名相同,即不要把原空間的地址作為接收realloc返回值,如:

建 議:p1 = (int*)realloc(p, newsize);p = p1;

不建議:p = (int*)realloc(p, newsize);

4. 釋放內(nèi)存時:如上述例子

4.1. free(p1);p1 = NULL;

4.2. free(p);p = NULL;(推薦)

4.3. free(p1);p1 = NULL;free(p);p = NULL;(報錯,因為他們指向同一個空間,只能釋放一次,如注意2.1,

如果如注意2.2所示,realloc函數(shù)會把原來的內(nèi)存塊釋放掉,所以不需要手動調(diào)用free(原來的內(nèi)存地址))

5. 如果第一個參數(shù)為NULL,第二個參數(shù)為size,則相當于直接開辟size個字節(jié)的大小

此時realloc(NULL, size)等價于malloc(size);

2.4.2 realloc函數(shù)的使用

realloc的第一個參數(shù)不為NULL時:

#include

#include

#include

#include

int main()

{

int len = 5;

int add1 = 5;

int add2 = 50000;

int i;

// malloc函數(shù)申請空間

int* p = (int*)malloc(len * sizeof(int));

if (NULL == p)

{

printf("%s", strerror(errno));

return 0;

}

printf("malloc: %p\n", p);

for (i = 0; i < len; i++) { *(p + i) = i; }

// realloc函數(shù)申請增加少量的空間,原來內(nèi)存空間后面有足夠的空間用于增加的空間

int* p1 = (int*)realloc(p, (len+add1) * sizeof(int));

if (NULL == p1)

{

printf("%s", strerror(errno));

return 0;

}

else

{

p = p1;

}

printf("realloc 增加小的內(nèi)存空間: %p\n", p);

for (i = len; i < len + add1; i++) { *(p + i) = i; }

printf("會把原來的值給復制過來:\n");

for (i = 0; i < len + add1; i++) { printf("%d ", *(p + i)); }

// realloc函數(shù)申請增加大量的的空間,原來內(nèi)存空間后面沒有足夠的空間用于增加的空間

// 需要重新找一塊足夠大的空間,足以存放原來和新增加的空間的大小,內(nèi)存空間的地址則會變化

int* p2 = (int*)realloc(p, (len + add1 + add2) * sizeof(int)); printf("\n");

if (NULL == p2)

{

printf("%s", strerror(errno));

return 0;

}

else

{

p = p2;

}

printf("realloc 增加大的內(nèi)存空間: %p\n", p);

for (i = len+add1; i < len + add1 + add2; i++) { *(p + i) = i; }

free(p);

p = NULL;

return 0;

}

realloc的第一個參數(shù)為NULL時:

#include

#include

#include

#include

int main()

{

int i;

int* p = (int*)realloc(NULL, 20);

if (NULL != p)

{

for (i = 0; i < 5; i++) { printf("%d ", *(p + i)); }

free(p);

p = NULL;

}

return 0;

}

第三:常見的內(nèi)存錯誤

3.1 對開辟內(nèi)存失敗且沒有檢查而進行解引用

錯誤寫法:

正確寫法:一定要對malloc、calloc、realloc函數(shù)的返回值進行判斷

3.2 對開辟的內(nèi)存進行越界訪問

3.3 對非動態(tài)內(nèi)存使用free函數(shù)

free函數(shù)只能對堆區(qū)上的空間進行釋放

而非動態(tài)內(nèi)存函數(shù)開辟的空間不再堆區(qū)上,而在棧區(qū)或者靜態(tài)區(qū)上。

3.4 free開辟的部分空間

如果free釋放的空間的地址不是開辟空間的地址,都屬于free部分空間的范圍

編譯通過,運行報錯,因為會釋放不屬于開辟空間的內(nèi)存。

3.5 free同一開辟空間多次

為了避免這種問題,應該遵守誰開辟,誰釋放,釋放后立馬將其設為NULL;

因為free(NULL);不起任何作用。

3.6 忘記free

如果對動態(tài)開辟的空間沒有free,則該空間,只有在程序結束時,才被回收。但是如果程序為一直運行狀態(tài),且開辟空間為重復過程。則會持續(xù)開辟空間而不會被回收,因此就會導致可用的內(nèi)存越來越少,即發(fā)生內(nèi)存泄露的情況。

執(zhí)行之前:

執(zhí)行之后:

第四:經(jīng)典易錯的面試題

4.1 非法訪問內(nèi)存和內(nèi)存泄露:

錯誤代碼:

#include

#include

#include

#include

void runtest(char* p) // 為實參的一份臨時拷貝

{

p = (char*)malloc(40);

} // 當函數(shù)調(diào)用結束后,創(chuàng)建的局部變量會自動銷毀

int main()

{

// 代碼運行時,會發(fā)生錯誤,或者崩潰

char* str = NULL;

runtest(str); // 參數(shù)為變量本身,指針變量也是變量,str以值的形式傳給形參p

strcpy(str, "hello, C/C++"); // 將字符串拷貝到空指針中,非法訪問內(nèi)存

printf(str);

// 動態(tài)開辟的內(nèi)存沒有釋放,會有內(nèi)存泄露的問題

return 0;

}

正確代碼1:傳遞變量的地址

#include

#include

#include

#include

void runtest(char** p)

{

*p = (char*)malloc(40);

}

int main()

{

char* str = NULL;

runtest(&str); // 傳遞變量的地址

if (NULL != str)

{

strcpy(str, "hello, C/CPP");

printf(str);

free(str);

str = NULL;

}

return 0;

}

正確代碼2:將動態(tài)內(nèi)存的地址返回

#include

#include

#include

#include

char* runtest(char* p) // 為實參的一份臨時拷貝

{

p = (char*)malloc(40);

return p;

}

int main()

{

char* str = NULL;

str = runtest(str); // 參數(shù)為變量本身,指針變量也是變量,str以值的形式傳給形參p

if (NULL != str)

{

strcpy(str, "hello, C/C++");

printf(str);

free(str);

str = NULL;

}

return 0;

}

4.2 返回棧區(qū)空間的地址

錯誤代碼:

#include

#include

#include

#include

char* runtest(void)

{

// 問題因為這是個局部變量,當函數(shù)調(diào)用結束后

// 雖然返回了該變量的指針,但是其所指向的空間的內(nèi)容將會被銷毀

// 當函數(shù)調(diào)用后,對該地址進行訪問,就屬于非法訪問內(nèi)存

// 數(shù)據(jù)經(jīng)典的返回棧區(qū)空間的地址

char p[] = "hello c/cpp"; // p位于棧區(qū)

return p;

}

int main()

{

char* str = NULL;

str = runtest();

printf(str);

return 0;

}

正確代碼:將局部變量用static修飾,即將棧區(qū)的變量,修改為靜態(tài)區(qū)的變量

總結

以上是生活随笔為你收集整理的c语言malloc引用类型作参数,C语言动态内存函数的理解和总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。