1. 程式人生 > 其它 >使用了未初始化的記憶體_記憶體的申請與釋放

使用了未初始化的記憶體_記憶體的申請與釋放

技術標籤:使用了未初始化的記憶體使用了未初始化的記憶體a使用未初始化記憶體使用未初始化的記憶體未使用初始化記憶體的

編寫 C/C++程式時,經常需要申請記憶體,記憶體的申請與釋放也是在編寫程式中最需要注意的地方。和 Python 等程式不同的是,C/C++將記憶體的申請與釋放的許可權交給了程式設計師,如果程式設計師忘記了釋放已經申請的記憶體,那麼在程式執行結束前它會一直佔據這個空間。隨著程式的執行,有可能會佔據的記憶體越來越多,最終導致系統崩潰。因此每次申請記憶體的時候,都不要忘記在合適的地方釋放掉。本文主要介紹申請記憶體的幾種方法,這些不同的方法各有其適用的場景,讀者可以根據自己的實際情況進行選擇。

  1. 首先是 malloc 函式,該函式的原型是 void *malloc(size_t size);功能是分配 size 位元組的未初始化記憶體塊,如果成功分配,則返回陣列的地址,否則返回 NULL。這個函式對於大部分程式設計師來說都是比較熟悉的,需要特別注意的有兩點:第一點是該函式的返回值是 void *型別,因此對於特定的資料型別,需要進行強制型別轉換;第二點是這個函式只負責分配記憶體,並不會進行初始化操作,因此不可以直接引用記憶體塊的值。

  2. 然後是 realloc 函式,該函式的原型是 void *realloc(void *ptr, size_t size);函式功能是將 ptr 指向的記憶體塊大小改為 size 位元組,但是記憶體塊內原來的資料都不會發生變化,新增加的記憶體塊仍然是未被初始化的。

  3. 還有 calloc 函式,該函式的原型是 void *calloc(size_t nmem, size_t size);函式的功能是為含有 nmem 個成員的陣列分配空間,每個元素佔 size 位元組大。和前面兩個函式不同的是,該函式可以將每個記憶體塊初始化為0。

  4. 最後是 new 運算子,它在 C++程式中經常被使用。相比於前面幾種申請記憶體的方法,使用 new 運算子不需要進行強制型別轉換。在使用完這段記憶體空間之後,需要使用 delete 運算子將其釋放掉。

下面通過一段程式來看一下它們的具體使用方法:

#include#include#includeusing namespace std;int main(){  int *a,*b;  int i;  a=(int *)malloc(sizeof(int)*4);  assert(a);  for (i=0;i<4;i++)    a[i]=i+1;  a=(int *)realloc(a,sizeof(int)*6);  a[4]=5;  a[5]=6;  for (i=0;i<6;i++)    cout<<"a["<"]="
< cout<<endl; free(a); a=(int *)calloc(4,sizeof(int)); assert(a); for (i=0;i<4;i++) cout<<"a["<"]="< cout<<endl; free(a); b=new int[4]; for (i=0;i<4;i++) b[i]=(i+1)*(i+1); for (i=0;i<4;i++) cout<<"b["<"]="< cout<<endl; delete []b;}

下面是這段程式碼的執行結果:

4344dc6a61e802aaf5ce8f1083804048.png

可以看到,在使用 calloc 函式申請記憶體之後,每個陣列成員的值都被設定為了0。因此為了避免引用未初始化的記憶體塊,建議使用 calloc 函式。

有時候,需要對一個數組進行清零操作,常規的方法是使用迴圈,然後在迴圈內部進行賦值。但是當迴圈次數過多的時候,效率就比較低了。可以使用 memset 函式實現這一操作,該函式的原型是 void *memset(void *s, int ch, size_t n); ch 即是要初始化的值,n 是這段記憶體空間的大小。由於該函式存在於 string.h 標頭檔案中,因此只有包含了這個標頭檔案才可以使用這個函式。通過下面的程式瞭解下它的用法:

#include#include#includeusing namespace std;int main(){  int *a;  int i;  a=new int[4];  for (i=0;i<4;i++)    a[i]=i+1;  for (i=0;i<4;i++)    cout<<"a["<"]="<  cout<<endl;    memset(a,0,sizeof(int)*4);  for (i=0;i<4;i++)    cout<<"a["<"]="<  cout<<endl;  delete []a;}

下面是這段程式的執行結果:

db2f928f5bf755b3cebc1a10994026c1.png

memset 函式不僅可以進行清零操作,還可以用來為新申請的記憶體進行初始化。它是對較大的結構體或陣列進行清零操作的一種最快方法。

以上介紹的各種申請記憶體空間的函式都有其適用的場景,請讀者根據合適的情況進行選擇,不必要一定使用 malloc 函式。無論是什麼時候,都不要忘記釋放掉申請的記憶體哦,即便是程式非常短,申請的空間很小,也要養成一個好習慣。俗話說,“好借好還,再借不難。”如果一直賴著不還的話,系統就會崩潰了hhh。