1. 程式人生 > >C語言之動態分配記憶體

C語言之動態分配記憶體

1. malloc()函式和free()函式

首先,我們應該知道,所有的程式都必須留出足夠的記憶體空間來儲存所使用的資料,所以我們經常會預先給程式開闢好記憶體空間,然後進行操作,但其實還有一種選擇,能夠讓記憶體分配自動進行下去。

對於傳統陣列,會遇到這樣的問題:

int arr[5] ;

對這個陣列我們在定義的時候必須給提前開闢好空間,並且在程式執行的過程中,這個開闢的記憶體空間是一直存在的,除非等到這個函式執行完畢,才會將空間釋放。還有一個問題就是這個陣列在程式中無法被修改。
這些問題給我們造成了一些使用上的不方便,所以,C中提供了malloc()函式。
關於malloc()函式,這個函式它接受一個引數:就是所需的記憶體的位元組數。然後malloc()找到可用記憶體中那一個大小適合的塊。在這個過程中,malloc()可以來返回那塊記憶體第一個位元組的地址。所以,也就意味了我們可以使用指標來操作。malloc()可以用來返回陣列指標、結構指標等等,所以我們需要把返回值的型別指派為適當的型別。當malloc()找不到所需的空間時,它將返回空指標。
例:

double *p;
p=(double*)malloc(30*sizeof(double));

在這個程式中,首先開闢了30個double型別的空間,然後把p指向這個空間的位置。在這裡的指標是指向第一個double值。並不是我們全部開闢的30個double的空間。這就和陣列一樣,指向陣列的指標式指向陣列首元素的地址,並不是整個陣列的元素。所以,在這裡我們的操作也和陣列是一樣的,
p[0]就是第一個元素,p[2]就是第二個元素。
至此,我們就可以掌握到一種宣告動態陣列的方法。

int arr[n];
p=(int *)malloc(n*sizeof(int));
//我們在這裡使用的時候要元素個數乘型別位元組長度,這樣就達到了動態開闢記憶體空間。

當我們使用malloc()開闢完記憶體空間以後,我們所要考慮的就是釋放記憶體空間,在這裡,C給我們提供了free()函式。free()的引數就是malloc()函式所返回的地址,釋放先前malloc()函式所開闢的空間。
例:
對於上面我們所開闢的空間進行釋放,那麼我們就可以這樣

free(p);

程式還呼叫了exit()函式,這個函式是在記憶體分配失敗時結束程式。
程式例子:


#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<malloc.h>//malloc()函式被包含在malloc.h裡面
#include<stdlib.h> int main(void) { char*a = NULL;//宣告一個指向a的char*型別的指標 a = (char*)malloc(100 * sizeof(char));//使用malloc分配記憶體的首地址,然後賦值給a if (!a)//如果malloc失敗,可以得到一些log { perror("malloc"); return-1; } sprintf(a, "%s", "HelloWorld\n");//"HelloWorld\n"寫入a指向的地址 printf("%s\n", a);//輸出使用者輸入的資料 free(a);//釋放掉使用的記憶體地址 system("pause"); return 0;//例2有無記憶體洩露? }

這個程式主要用來檢測malloc返回值條件有誤。
在這裡我們需要注意,在C中,型別指派(char *)是可選的,但是在C++中這個是必須有的,所以使用型別指派將使把C程式移植到C++更容易。

使用動態陣列,主要是為了獲得程式的靈活性。我們嗯可以需要多少個元素就讓陣列開闢多少個,。不需要浪費空間

2.free()的重要性

在我們使用malloc()函式的時候,分配的記憶體是會增加的,當我們使用free()函式時,可以釋放記憶體。
例如:
...

int main()
{
    double glad[2000];
    int i;
    ...
    for(i=0;i<1000;i++)
        gobble(glad,2000);
    ...
}
void gobble(double arr[],int n)
{
    double *temp=(double *)malloc(n*sizeof(double));
    ...
}

在這個程式當中我們使用了malloc()函式,但是我們沒有使用free()函式,在這個程式中,我們首先進入gobble()函式,穿件了指標temp,並且使用了malloc()函式。但是除了gobble()函式之後,指標作為一個變數消失了,但是所開闢的記憶體是依然存在的,我們依然開闢了16000個位元組的記憶體。但是我們卻無法去訪問這些記憶體,因為他們的地址不見了。因為沒有呼叫free()函式,這段記憶體也不能再此使用了。
這樣依次迴圈,總共執行for迴圈1000次,最終導致了程式總共16000000個位元組的記憶體無法使用,這樣,記憶體肯定已經溢位了。這樣就會出現我們所說的程式洩漏問題,而free()函式,正好解決了這種的問題。

3.calloc()函式和realloc()函式

接下來,我們在認識兩個關於記憶體分配的函式。calloc()函式和realloc()函式。
calloc()函式與malloc()函式有相同之處,也有相似之處。
例:

short *p;
newmem=(short *)calloc(1000sizeof(short)); 

通過這個例子,我們可以知道calloc()函式有兩個引數,並且這兩個函式都是size_t型別(unsigned int型別)的數。第一個引數在這裡所說的是所需要開闢的記憶體單元數量,第二個引數是每個單元的位元組的大小。

void *calloc(size_t ,size_t);

calloc()函式還有一個特性,它將塊中的全部位都置為0。這也是calloc()函式和malloc()函式的區別,calloc()函式和malloc()函式的另外一個區別是他們請求記憶體數量的方式不一樣。當然,free()函式也可以來釋放calloc()函式分配的記憶體。

realloc()函式用來修改一個原先已經分配的記憶體的大小。使用這個函式,你可以讓一塊記憶體增大還是縮小。當擴大時,這塊記憶體原先的內容會依然保留,新增加的新增到原先的後面。縮小時,該記憶體的尾部部分記憶體去掉,剩餘保留。

注意:對於realloc()函式,如果原先的記憶體無法修改,這時候realloc()函式再會分配一塊記憶體,並且把原先那塊記憶體的內容複製到上面去。所以,使用了realloc函式以後,你這時候在使用的就該是realloc函式返回的新指標了。當realloc函式的第一個引數是NULL時,這時候我們可以把它當作是malloc()函式。

寫部落格已經半個月了,感覺問題還是很多,希望大家多多指點。