C語言中堆內存的開辟和釋放與內存處理函數


C語言動態分配內存,malloc的出現就是來彌補靜態內存分配的缺點

比如說我們在定義數組的時候,數組的長度必須是一個常量,不能改變的值,假如我事先定義了數組,一旦業務需求發生改變,那么這個數組就不能再使用了。

傳統的數組定義也就是靜態分配,是不能夠手動釋放的,只能等待系統釋放,靜態分配的內存,是分配在棧中的,C語言中的函數調用也是通過棧來實現的,棧有一個特點就是先進后出,在調用函數的時候,是先壓入棧,然后從最上面的函數開始執行

我們先來看看內存四區,分別為堆區,棧區,數據區,代碼區,對於這四個區,做了以下總結

代碼區:
  程序執行二進制碼(程序指令)
  共享,只讀
數據區 :
  初始化數據區(data)
  未初始化數據區(bss)
  常量區
棧區 :
  系統為每一個程序分配一個臨時的空間,
  局部變量,函數信息,函數參數,數組
  棧區大小為:1M
  在windows中可以擴展到10M
  在linux中可以擴展到16M
堆區 :
  存儲大數據,圖片,音樂,視頻
  手動開辟 malloc
  手動釋放           free

棧區大小為:1M,我們來驗證一下

int zhan[8200000] = { 0 };

在C語言中,我們定義了一個數組,長度為820000,那么我們知道,在棧中我們最多可分配1M的內存,我們可以計算一下,這八百二十萬的長度占了多大的內存,

定義的是int類型,所以8200000*4=32800000(字節)

得到的結果再除以1024,32800000/1024=32031.25(KB)

得到的結果再除以1024,32031.25/1024=31.280517578125(M)

大約是31M,最終運行起來,這個程序是會報錯的。

接下來我們就開辟堆內存存儲數據,這就用到了函數malloc

動態分配內存函數

               malloc

使用函數之前我們要引用頭文件stdlib.h

#include<stdlib.h>

 malloc函數語法示例

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

返回值類型為void* 類型,也就是指針類型,int* p1代表一個以int類型地址為內容的指針變量

int類型在內存中占用的大小為 4字節。

malloc括號中就是你要開辟的空間大小,單位是字節,分配一塊連續的區域

假如我要開辟一個空間,里面存儲5個數字,那么代碼如下

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

這樣的格式可以更容易的理解,當然你也可以像下面這么寫

int* p1 = (int*)malloc(20);

如果地址開辟成功,返回一個內存地址,否則返回NULL,需要注意的是,如果開辟失敗了,那么在后邊的程序中調用,程序就會報錯,所以有時候還要加一個判斷條件,這點要注意

if (p1 == NULL) {
        printf("程序異常");
        return -1;
    }

成功以后,我們可以使用這個內存空間,對它進行賦值。

在使用完之后,也可以調用free函數釋放,代碼如下

free(p1);

那么,當我們釋放這個p1之后,這個內存空間還能調用嗎?其實還可以調用的。在釋放之后,這個內存地址就變成了一個野指針,還可以進行賦值

為了避免野指針,在free(p1)后在加上一段代碼

p1 = NULL;

賦值為NULL,這個是可有可無的。

我們再來看一個函數,叫做內存操作函數

      memset(),memcpy(),memmove(),

引用 string.h

#include<string.h>

 

1.memset()參數,  void *memset(void *s, intc, size_tn);

我們來看看它的示例

int* p = (int*)malloc(sizeof(int) * 10);
memset(p, 0, 40);

傳入p這個內存地址,重置為0,字節為40字節

它在重置為0時有效,並不是真正意義上的重置

這個函數作用通常是一串連續的內存一起操作,不會單獨對變量進行操作。

 

2.memcpy(),參數,void *memcpy(void *dest, constvoid *src, size_tn);

示例:

   int arr[] = { 1,2,3,4,5,6,7,8,9 };
    int* p = (int*)malloc(sizeof(int) * 9);
    memcpy(p, arr, sizeof(int) * 9);

arr存在棧內存中,p存在堆內存中,我們現在要把arr中的數復制到p中,這就用到了  memcpy()函數

用法:

        memcpy(新數據,源數據,內存大小(字節))

它不同於strcpy()這個函數,strcpy()是字符串拷貝遇到\0會停止,而memcpy()拷貝的是內存,拷貝的內容和字節有關。

如果參數1和參數2的內存地址重疊,可能會導致程序報錯,應盡量避免

 

3.memmove()

memmove()功能用法和memcpy()一樣,區別在於:dest和src所指的內存空間重疊時,memmove()仍然能處理,不過執行效率比memcpy()低些。

 

4.memcmp(),參數,int memcmp(constvoid *s1, constvoid *s2, size_tn);

    int arr[] = { 1,2,3,4,5,6,7,8,9 };
    int arry[] = { 1,2,3,4,5 };
    int value = memcmp(arr, arry, 20);

第一個參數和第二個參數進行比較,比較前20個字節,也就是前5個數,如果相等返回0,否則返回-1;

 同樣可以比較字符串,代碼如下:

    char arr[] = "hello\0 word";
    char arry[] = "hello\0 word";
    int value = memcmp(arr, arry, 11);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM