C語(yǔ)言?動(dòng)態(tài)內(nèi)存管理全面解析
1. 為什么存在動(dòng)態(tài)內(nèi)存分配
*動(dòng)態(tài)內(nèi)存開(kāi)辟在堆區(qū)*
我們已經(jīng)掌握的開(kāi)辟內(nèi)存方式是類(lèi)型直接定義變量,開(kāi)辟的內(nèi)存是固定的,像:
int a=20; //在??臻g上開(kāi)辟四個(gè)字節(jié)
還有數(shù)組,我們可以指定開(kāi)辟空間的大小,像:
char arr[10] = {0}; ///在??臻g上開(kāi)辟10個(gè)字節(jié)的連續(xù)空間但在程序運(yùn)行時(shí),很多時(shí)候我們會(huì)遇到內(nèi)存不夠或者內(nèi)存過(guò)多引起的浪費(fèi)問(wèn)題,那么有沒(méi)有那種使用多少內(nèi)存開(kāi)辟多少內(nèi)存的方法?這就是本篇文章要介紹的動(dòng)態(tài)內(nèi)存。
2. 動(dòng)態(tài)內(nèi)存函數(shù)的介紹
2.1 malloc和free
malloc和free都聲明在 stdlib.h 頭文件中
void* malloc (size_t size); //向內(nèi)存申請(qǐng)一塊連續(xù)可用的空間,并返回指向這塊空間的指針
如果開(kāi)辟成功,則返回一個(gè)指向開(kāi)辟好空間的指針。 如果開(kāi)辟失敗,則返回一個(gè)NULL指針。 返回值的類(lèi)型是 void* ,malloc函數(shù)并不知道開(kāi)辟空間的類(lèi)型,在使用的時(shí)候自己來(lái)決定。
void free (void* ptr); //free函數(shù)用來(lái)釋放動(dòng)態(tài)開(kāi)辟的內(nèi)存
如果參數(shù) ptr 指向的空間不是動(dòng)態(tài)開(kāi)辟的,那free函數(shù)的行為是未定義的。
如果參數(shù) ptr 是NULL指針,則函數(shù)什么事都不做。
舉例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
//開(kāi)辟10個(gè)整型空間
int* p = (int*)malloc(40);
if (NULL==p)
{
printf("%s\n",strerror(errno)); //判斷開(kāi)辟失敗的原因
return 0;
}
//使用
//釋放
free(p); //將空間還給系統(tǒng),但是里面的內(nèi)容沒(méi)有改變,還可以通過(guò)p來(lái)找到地址
p = NULL; //因此要將地址置為空指針
return 0;
}2.2 calloc
void* calloc (size_t num, size_t size); //num為元素個(gè)數(shù),size為每個(gè)元素的大小
注:與函數(shù) malloc 的區(qū)別只在于 calloc 會(huì)在返回地址之前把申請(qǐng)的空間的每個(gè)字節(jié)初始化為全0

當(dāng)用calloc來(lái)開(kāi)辟10個(gè)整型空間時(shí)
int* p = (int*)calloc(10,sizeof(int));

2.3 realloc
void* realloc (void* ptr, size_t size); //ptr 是要調(diào)整的內(nèi)存地址 size 調(diào)整之后新大小 //返回值為調(diào)整之后的內(nèi)存起始位置
realloc在調(diào)整內(nèi)存空間的是存在兩種情況:
1.當(dāng)原地址后有足夠的空間時(shí),可以接著原地址連續(xù)開(kāi)辟空間,最后返回起始地址。
2.當(dāng)原地址后空間不足以開(kāi)辟我們所需要的空間時(shí),那么realloc會(huì)自動(dòng)尋找一塊足以存放我們需要的的空間,并將原地址的內(nèi)容復(fù)制到新空間中,釋放掉原地址中的內(nèi)容,返回開(kāi)辟出空間的初始地址。

我們可以先判斷是否開(kāi)辟成功,再將地址賦予p

3. 常見(jiàn)的動(dòng)態(tài)內(nèi)存錯(cuò)誤
3.1 對(duì)NULL指針的解引用操作
開(kāi)辟動(dòng)態(tài)內(nèi)存時(shí),一定要注意對(duì)返回空指針的函數(shù)要進(jìn)行判斷,防止對(duì)空指針進(jìn)行解引用,以免程序出現(xiàn)問(wèn)題。
3.2 對(duì)動(dòng)態(tài)開(kāi)辟空間的越界訪問(wèn)
int *p = (int *)malloc(10*sizeof(int)); //開(kāi)辟內(nèi)存
if(NULL == p) //判斷是否開(kāi)辟成功
{
exit(EXIT_FAILURE);
}
int i=0;
for(i=0; i<=10; i++)
{
*(p+i) = i;//當(dāng)i是10的時(shí)候越界訪問(wèn)
}
free(p);
這塊可以像理解數(shù)組一樣,不能訪問(wèn)下標(biāo)為10的地址,會(huì)造成越界訪問(wèn)。
3.3 對(duì)非動(dòng)態(tài)開(kāi)辟內(nèi)存使用free釋放
void test()
{
int a = 10;
int *p = &a;
free(p);
}
int main()
{
test();
return 0;
}
不是動(dòng)態(tài)內(nèi)存開(kāi)辟的空間內(nèi)存不在堆區(qū),沒(méi)必要用free釋放,在棧區(qū)開(kāi)辟的空間在出了作用域后會(huì)自動(dòng)還給系統(tǒng),沒(méi)有必要,也不允許用free進(jìn)行釋放。
3.4 使用free釋放一塊動(dòng)態(tài)開(kāi)辟內(nèi)存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向動(dòng)態(tài)內(nèi)存的起始位置
}
不支持釋放一部分內(nèi)存,這樣的寫(xiě)法不支持不可取。只能從動(dòng)態(tài)內(nèi)存開(kāi)辟的起始位置來(lái)進(jìn)行釋放。
3.5 對(duì)同一塊動(dòng)態(tài)內(nèi)存多次釋放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重復(fù)釋放
}重復(fù)釋放也會(huì)報(bào)錯(cuò)

當(dāng)p第一次釋放后,將p=NULL,再次釋放的話就不會(huì)有問(wèn)題;寫(xiě)代碼是要避免重復(fù)釋放的情況,同時(shí)要記住每次釋放完之后都要將地址置為空指針。
若忘記釋放開(kāi)辟的空間,就會(huì)造成內(nèi)存泄漏的問(wèn)題(在釋放該段內(nèi)存之前就失去了對(duì)該段內(nèi)存的控制,從而造成了內(nèi)存的浪費(fèi))
到此這篇關(guān)于C語(yǔ)言 動(dòng)態(tài)內(nèi)存管理深入理解的文章就介紹到這了,更多相關(guān)C語(yǔ)言 動(dòng)態(tài)內(nèi)存管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理圖文詳解
- C語(yǔ)言深入細(xì)致講解動(dòng)態(tài)內(nèi)存管理
- 超詳細(xì)分析C語(yǔ)言動(dòng)態(tài)內(nèi)存管理問(wèn)題
- C語(yǔ)言?超詳細(xì)梳理總結(jié)動(dòng)態(tài)內(nèi)存管理
- C語(yǔ)言的動(dòng)態(tài)內(nèi)存管理的深入了解
- 關(guān)于C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理分析總結(jié)
- C語(yǔ)言動(dòng)態(tài)內(nèi)存管理深入探討
相關(guān)文章
C++進(jìn)階練習(xí)刪除鏈表的倒數(shù)第N個(gè)結(jié)點(diǎn)詳解
這篇文章主要給大家介紹了關(guān)于如何利用C++刪除鏈表的倒數(shù)第N個(gè)結(jié)點(diǎn),文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-05-05
Linux下semop等待信號(hào)時(shí)出現(xiàn)Interrupted System Call錯(cuò)誤(EINTR)解決方法
本篇文章是對(duì)在Linux下semop等待信號(hào)時(shí)出現(xiàn)Interrupted System Call錯(cuò)誤(EINTR)的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C語(yǔ)言中如何在結(jié)構(gòu)體內(nèi)定義函數(shù)
這篇文章主要介紹了C語(yǔ)言中如何在結(jié)構(gòu)體內(nèi)定義函數(shù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
C++11運(yùn)算符重載和向量類(lèi)重載實(shí)例詳解(<<,>>,+,-,*等)
這篇文章主要給大家介紹了關(guān)于C++11運(yùn)算符重載和向量類(lèi)重載的相關(guān)資料,主要包括<<,>>,+,-,*等,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-07-07
C++中VTK9.3.0刻度標(biāo)簽重疊的問(wèn)題記錄
這篇文章主要介紹了C++中VTK9.3.0刻度標(biāo)簽重疊的問(wèn)題,本文采用VTK9.3.0版本,其他版本如VKT8.0亦有同樣的問(wèn)題,需要的朋友可以參考下2024-06-06
深入理解c++中char*與wchar_t*與string以及wstring之間的相互轉(zhuǎn)換
本篇文章是對(duì)c++中的char*與wchar_t*與string以及wstring之間的相互轉(zhuǎn)換進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
利用C語(yǔ)言實(shí)現(xiàn)經(jīng)典多級(jí)時(shí)間輪定時(shí)器
C語(yǔ)言是一門(mén)通用計(jì)算機(jī)編程語(yǔ)言,廣泛應(yīng)用于底層開(kāi)發(fā),這篇文章主要給大家介紹了關(guān)于利用C語(yǔ)言實(shí)現(xiàn)經(jīng)典多級(jí)時(shí)間輪定時(shí)器的相關(guān)資料,需要的朋友可以參考下2021-07-07
淺談C++虛重載操作符 virtual operator= 的使用方法
下面小編就為大家?guī)?lái)一篇淺談C++虛重載操作符 virtual operator= 的使用方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

