malloc,calloc,realloc及動態開闢記憶體常見錯誤
1.為什麼存在動態記憶體管理?
我們已經掌握的記憶體開闢方式有:
int val = 20;//在棧空間上開闢四個位元組
char arr[10] = {0}; //在棧空間上開闢10個位元組的連續空間
但是這些開闢空間的方式開闢的空間大小是固定的,陣列在宣告的時候,也是必須指定大小。他們所需要的記憶體在編譯時分配
而有些時候我們需要的空間大小在程式執行的時候才能知道,所以就要有一種動態記憶體分配的方式
動態開闢的記憶體都在堆上
2.如何動態的分配記憶體?
c語言提供了一個動態記憶體開闢的方式:
- malloc:向記憶體動態的申請一塊空間
- 函式原型: void * malloc (size_t size);
- 函式說明:
1)這個函式向記憶體申請一塊連續可用的空間,並返回指向這塊空間的指標
2)如果開闢成功,則返回一個指向開闢好空間的指標
3)如果開闢失敗,則返回一個NULL指標,因此malloc的返回值一定要做檢查
4)返回值型別是void* ,所以malloc函式並不知道開闢空間的型別,具體在使用的時候由使用者自己來決定。
5)如果引數size為0,malloc的行為是標準為定義的,取決於編譯器
c語言提供了另一個函式free,專門用來做動態記憶體的釋放和回收的
- free:用來釋放動態開闢的記憶體
- 函式原型: void free(void* prt);
- 函式說明:
1)如果引數ptr指向的空間不是動態開闢的,那free函式的行為是未定義的
2)如果引數ptr是NULL指標,則函式什麼事都不做
malloc和free都宣告在標頭檔案#include<stdlib.h>中
int main()
{
int *ptr = NULL;
ptr = (int*)malloc(10*sizeof(int));
if (ptr != NULL)//一定要檢查是否為空
{
printf("haha\n");
}
free(ptr);//一定要記得釋放
ptr = NULL;
return 0;
}
//使用時要判斷ptr是否為空,動態申請的記憶體一定要使用free()釋放,並且置空,否則可能引起記憶體洩漏的問題
- calloc:用來動態開闢記憶體,不同於malloc的是,它會進行初始化
- 函式原型:void* calloc(size_t num,size_t size);
- 函式說明:
1)calloc函式的功能是為num個大小為size的元素開闢一塊空間,並且把空間的每個位元組都初始化為0
2)與函式malloc的區別在於calloc會在返回地址之前把申請的所有空間的每個位元組都初始化為0
int main()
{
int *ptr = NULL;
ptr = (int*)calloc(10, sizeof(int));
if (NULL != ptr)
{
printf("haha\n");
}
free(ptr);
ptr = NULL;
return 0;
}
- realloc:可以對動態開闢的記憶體大小進行調整,realloc函式的出現使動態記憶體管理更加靈活,有時候我們申請的空間太大,或者太小了,就可以使用realloc對其進行調整
- 函式原型:void* realloc(void* ptr,size_t size);
- 函式說明:
1)ptr是要調整的記憶體地址
2)size是調整之後的新大小
3)返回值為調整直觀的記憶體起始位置
4)這個函式在調整原記憶體空間大小的基礎上,還會將原來記憶體中的資料移動帶新的空間
- realloc函式在調整記憶體空間存的時候在倆種情況
1)原有空間之後有足夠大的空間
2)原有空間之後沒有足夠的空間
int main()
{
int *ptr = (int*)malloc(10 * sizeof(int));
int * newptr = NULL;
newptr = (int*)realloc(ptr, 100);
if (NULL != newptr)
{
printf("haha");
}
free(newptr);
return 0;
}
3.常見的動態記憶體錯誤
- 對NULL指標進行解引用操作
void test() { int * ptr = (int*)malloc(10*sizeof(int)); *ptr = 20; free(ptr); }
//如果開闢記憶體失敗,ptr=NULL,對空指標進行解引用會出錯,所以使用前要先判斷ptr是否為NULL
- 對動態開闢空間的越界訪問
void test()
{
int i = 0;
int *p = (int*)malloc(10 * sizeof(int));
if (NULL == p)
{
exit(EXIT_FAILURE);
}
for (i = 0; i <= 10; i++)
{
*(p + i) = i;//當i=10的時候越界訪問
}
free(p);
}
- 對非動態開闢記憶體的釋放,棧上申請的空間,不需要用free釋放
- 使用free釋放一塊動態開闢記憶體的一部分
void test() { int *p = (int*)malloc(100); p++; free(p); }
//p++後不在指向動態記憶體的起始位置,malloc申請,釋放的空間都是整體的,不能區域性釋放
- 對一塊動態記憶體釋放多次
- 動態開闢的空間忘記釋放(記憶體洩漏),切記動態開闢的空間一定要釋放,並且要正確的釋放
相關文章
- malloc,calloc,realloc等記憶體分配函式區別記憶體函式
- 【C/C++】記憶體分配函式:malloc,calloc,realloc,_allocaC++記憶體函式
- malloc、calloc和realloc區別
- malloc、calloc、realloc的區別
- 實現和除錯 Malloc、Free、Calloc 和 Realloc 的快速教程除錯
- 【日常小記】記憶體分配方式及常見錯誤記憶體
- 5個常見的JavaScript記憶體錯誤JavaScript記憶體
- 關於c語言記憶體分配,malloc,free,和段錯誤,記憶體洩露C語言記憶體洩露
- 開發常見錯誤及解決方案
- C語言malloc()函式:動態分配記憶體空間C語言函式記憶體
- 記憶體動態分配與釋放,malloc和new區別記憶體
- Go 常見錯誤集錦 | 字串底層原理及常見錯誤Go字串
- Go常見錯誤集錦 | 字串底層原理及常見錯誤Go字串
- Linux記憶體管理:MallocLinux記憶體
- 常見的授權錯誤及原因
- Github使用方法及常見錯誤Github
- Elasticsearch 叢集和索引健康狀態及常見錯誤說明Elasticsearch索引
- 關於記憶體錯誤記憶體
- Hadoop常見錯誤及解決方案Hadoop
- hadoop常見錯誤及處理方法Hadoop
- MySQL 常見錯誤MySql
- oracle 常見錯誤Oracle
- Web開發常見性的錯誤Web
- Java記憶體模型常見問題Java記憶體模型
- 動態記憶體管理記憶體
- 動態記憶體分配記憶體
- Flume記憶體溢位錯誤記憶體溢位
- struct和malloc記憶體互轉例子Struct記憶體
- Android記憶體溢位、記憶體洩漏常見案例分析及最佳實踐總結Android記憶體溢位
- 9種常見的Android開發錯誤及解決方案Android
- 常見的web錯誤Web
- mysql replication常見錯誤MySql
- Golang開發常見的57個錯誤Golang
- 10 大常見的web開發錯誤Web
- 蘋果開發幾個常見的錯誤蘋果
- python中的變數怎樣開闢記憶體Python變數記憶體
- php安全配置記錄和常見錯誤梳理PHP
- c和指標中關於動態分配記憶體malloc和qsort的一個例子指標記憶體