如果對你有幫助,請不吝惜你的小手給我點個讚支持下作者!關注我不迷路
初識 動態內存分配 [C語言必知必會]
動態內存分配的引入
初學數組的時候,有一個問題經常困擾著我,就是:我們可不可以自己在程序裡定義一個數組的大小而不是在函數開頭先聲明一個很大的數組,然後僅僅使用它的一小部分?
請看下面的程序:我們需要一個大小為 N ( N < 1000)的數組,我們通常這麼寫:
intmain(void){int arr[1000] = { 0 };int N = 0;int i = 0;printf("請輸入數組的大小\n");scanf("%d", &N);printf("請輸入%d個數\n", N);for (i = 0; i < N; i++)scanf("%d", &arr[i]);return0;}
每次這麼寫我都覺得自己在繞遠路,為什麼就不能直接把輸入的變量 N 當作數組的大小直接使用?比如這樣:
arr[N]
,但是很遺憾,每次編譯器都把你扼殺在程序編譯之前!
C99才可以用變量做數組定義的大小並且可以在程序中隨時聲明變量。(C99前我們需要在函數的最前面的區域對所有變量進行聲明)
如果我不想用上面那種笨笨的辦法,又沒有支持C99的編譯器,我該怎麼辦?
可以這麼做:
int* arr = (int*)malloc(sizeof(int) * N)
sizeof(int)
代表數組中每個元素的類型
N
代表數組的元素個數
所以malloc的意義是向 堆區 要了一塊
sizeof(int) * N
這麼大的空間
malloc 與 free ——好哥倆
malloc
頭文件:stdlib原型:void* malloc(size_t size)所以需要根據實際你需要的類型對其強制類型轉換返回值:成功時,返回指向新分配內存的指針。為避免內存洩漏,必須用 free() 或 realloc() 解分配返回的指針。失敗時,返回空指針(NULL)參數:size - 要分配的字節數定義分配 size 字節的未初始化內存。若分配成功,則返回為任何擁有基礎對齊的對象類型對齊的指針。若 size 為零,則 malloc 的行為是實現定義的。例如可返回空指針。亦可返回非空指針;但不應當解引用這種指針,而且應將它傳遞給 free 以避免內存洩漏。更多關於mallochttps://zh.cppreference.com/w/c/memory/malloc
free
頭文件:stdlib原型:void free( void* ptr );參數:指向要解分配的內存的指針返回值:無此函數接收空指針(並對其不處理)以減少特例的數量。不管分配成功與否,分配函數返回的指針都能傳遞給 free()這是什麼意思?意思就是malloc與free成對出現,不要忘記寫free哦。定義:解分配之前由 malloc() 、 calloc() 、 aligned_alloc (C11 起) 或 realloc() 分配的空間。若 ptr 為空指針,則函數不進行操作。[1]若 ptr 的值 不等於之前從 malloc() 、 calloc() 、 realloc() 或 aligned_alloc() (C11 起) 返回的值[2],則行為未定義。若 ptr 所指代的內存區域已經被解分配[3],則行為未定義,即是說已經以ptr 為參數調用 free() 或 realloc() ,而且沒有後繼的 malloc() 、 calloc() 或 realloc() 調用以 ptr 為結果。若在 free() 返回後通過指針 ptr 訪問內存[4],則行為未定義(除非另一個分配函數恰好返回等於 ptr 的值)。更多關於freehttps://zh.cppreference.com/w/c/memory/free
free():將申請來的空間的 首地址還給「系統」,只要申請到了空間就一定要歸還
畢竟有借有還,再借不難嘛
解讀 free
注釋1:釋放空指針有何意義?
我們在聲明一個指針時,一般把它初始化為0,也就是NULL。這樣做的好處是,如果我們在後面的程序中沒有讓這個指針指向一塊具體的空間,這個指針不會是野指針,方便我們用來判斷。比如if(p != NULL)我們還知道,當malloc失敗時返回的是 NULL所以我們一開始寫上free是好習慣,因為我們不知道我們會不會用到我們聲明的指針,也不知道malloc能不能成功這時候,free空指針就是有意義的了
注釋2:molloc申請到的指針 與 free要釋放的指針保持一致
#include<stdio.h>intmain(){int* p;p = (int*)malloc(100 * 1024); p++; //改變了 p 的首地址;free(p);//free 沒有得到 malloc時 分配給p的首地址,程序崩潰return0;}
注釋3:free釋放空間後,被釋放的指針成為野指針,不能直接使用它
#include<stdio.h>intmain(){int* p;p = (int*)malloc(100 * 1024); p++;free(p); p++;//free 釋放後 p 成為了野指針,程序崩潰return0;}
注釋4:不能多次釋放同一次malloc申請的地址
#include<stdio.h>intmain(){int* p;p = (int*)malloc(100 * 1024); p++;free(p);free(p);return0;}
現在我們就可以改進我們上面的程序啦!
#include<stdlib.h>intmain(void){int i = 0;int N = 0;int* arr;printf("請輸入數組的大小\n");scanf("%d", &N);arr = (int*)malloc(sizeof(int) * N);printf("請輸入%d個數\n", N);for (i = 0; i < N; i++)scanf("%d", &arr[i]);free(arr);return0;}
什麼?不是改進嗎?怎麼行數反而變多了?
測測你能給系統分配多大空間?
#include<stdlib.h>intmain(void){void* p;int i = 0;//每次申請100M,失敗返回空指針0,退出循環while ((p = malloc(1024 * 1024 * 100)))i++;printf("最多分配%d00M內存", i);return0;}
如果忘記了free?
我們一次程序中可以申請的內存是有限的。
如果你只是平時寫簡單的程序,寫完就關閉,退出去了,這時忘記了free的話,不會對任何人造成影響,因為作業系統有清除曾使用的內存的機制
但是如果是一個持續運行的伺服器呢?堆區中所有的空間都被你申請了呢?
free的常見問題
申請了沒有free -> 長時間運行內存逐漸下降free 後再free地址變更後,直接去free
小測試:
1.對於以下的代碼段,正確的說法是:
char *p;while(1){p = malloc(1); *p = 0;}
A:最終程序會因為沒有空間了而退出B:最終程序會因為向0地址寫入而退出C:程序會一直運行下去D:程序不能被編譯
2.對於以下代碼段:
int a[] = {1, 2, 3, 4, 5};int *p = a;int *q = &a[5];printf("%d",q-p);
當
sizeof(int) = 4
時,以下說法正確的是:A:因為第三行的錯誤不能編譯B:因為第三行的的錯誤運行時崩潰C:輸出5D:輸出20
3.使用malloc就可以做出運行時可以隨時改變大小的數組A:√B:
後臺回覆:2020 0204查看答案哦
歡迎各位與我交流討論!
如果對你有幫助,請不吝惜你的小手給我點個讚支持下作者!關注我不迷路