C語言?超詳細梳理總結動態(tài)內存管理
一.為什么存在動態(tài)內存分配
我們已經掌握的內存開辟方式有:
int a = 10;//在??臻g開辟4個字節(jié)的連續(xù)空間
int b[20] = { 0 };//在棧空間開辟20個字節(jié)的連續(xù)空間這種開辟空間的方式有以下特點:
1.開辟空間的大小是固定的
2.開辟數(shù)組時必須指定大小
初學數(shù)組時,我寫過下面的錯誤代碼。
int N;
scanf("%d",&N);
int a[N]={ 0 };可N是變量,不能用于數(shù)組元素個數(shù)的初始化。
如果我們需要的空間大小在程序運行時才能知道,那就只能試試動態(tài)內存開辟了。
二.動態(tài)內存函數(shù)的介紹
1.malloc和free
void* malloc (size_t size);
void free (void* ptr);
malloc函數(shù)用于向內存申請一塊連續(xù)可用的空間,并且返回指向這塊空間的指針。
若開辟成功,返回指向這塊空間的指針
若開辟失敗,返回NULL指針,因此malloc的返回值一定要做檢查
使用完malloc函數(shù)要用free釋放申請的內存空間
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)malloc(40);//開辟40個字節(jié)的??臻g
if (p == NULL) //檢查是否為空指針
{
perror("malloc");
return 1;
}
for (int i = 0; i < 10; i++)
{
*(p + i)=i;
}
free(p); //用完后釋放空間,注意參數(shù)為首地址
p = NULL; //置為空指針
} 2.calloc
void* calloc (size_t num, size_t size)
calloc的兩個參數(shù)分別為申請元素的個數(shù)和每個元素的大小,
使用和malloc差不多,但是申請的空間會被初始化為0,
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
perror("calloc");
return 1;
}
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p + i)); //輸出為 10個0
}
free(p);
p = NULL;
}3.realloc
void* realloc (void* ptr, size_t size)
realloc用于重新設置要開辟內存空間的大小,可以是增大或減小
指針ptr是指向先前使用 malloc、calloc 或 realloc 分配的內存塊的指針。
size 是新開辟內存空間的大小
若原空間后面未開辟的空間足夠使用,則返回原先的起始地址

若原空間后面未開辟的空間不足以填滿新開辟內存空間,
則會在某個地址開辟所需要的空間,free掉原空間的地址,
并且返回新的地址的起始地址
真 · 一條龍服務

若擴容失敗,會返回空指針,因此也要檢查是否是空指針
三.常見的動態(tài)內存錯誤
1.對NULL指針的解引用操作
void test()
{
int *p = (int*)malloc(INT_MAX/4);
*p = 20;
free(p);
}若p為空指針,則程序錯誤。
解決方案:檢查是否為空指針
2.對動態(tài)開辟空間的越界訪問
int main()
{
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
perror("calloc");
return 1;
}
for (int i = 0; i <= 10; i++) //當i為10時,形成越界訪問,程序出錯
{
printf("%d ", *(p + i));
}
free(p);
p = NULL;
}使用這塊空間時要注意是否已經越界訪問
3.對非動態(tài)開辟的空間使用free釋放
int a = 10; int* p = &a; free(p);
一執(zhí)行,程序崩潰了

4.使用free釋放一塊動態(tài)開辟空間的一部分
void test()
{
int* p = (int*)malloc(100);
p++;
free(p);
}同樣會崩潰

5.對同一塊開辟的空間多次釋放
void test()
{
int* p = (int*)malloc(100);
free(p);
free(p);
}沒錯,又又又崩潰了,就不上圖了
6.動態(tài)內存開辟忘記釋放(內存泄漏)
如果使用空間后不釋放,會導致內存泄漏。
內存泄漏的堆積,這會最終消耗盡系統(tǒng)所有的內存。
四.幾個經典的筆試題
第一個
void GetMemory(char* p) //對空指針解引用
{
p = (char*)malloc(100); //內存泄露
}
void test()
{
char* str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
int main()
{
test();
}p是str的一份臨時拷貝,指向malloc申請的起始地址,
出了函數(shù)之后,內存還給系統(tǒng),str仍為空指針,strcpy把“hello world”放進空指針
第二個
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void test()
{
char* str = NULL;
str=GetMemory(); //野指針str
printf(str);
}
int main()
{
test();
}定義字符串p,并返回p的地址
但是當出了這個函數(shù),內存還給系統(tǒng),沒有使用權限
指針變?yōu)?/p>
第三個
void GetMemory(char** p,int num) //傳址調用
{
*p = (char*)malloc(num);
}
void test()
{
char* str = NULL;
GetMemory(&str,100);
strcpy(str, "hello world");
printf(str);
//沒有free
}
int main()
{
test();
}打印hello world
沒有釋放空間
第四個
void GetMemory(char** p,int num)
{
*p = (char*)malloc(num);
}
void test()
{
char* str = (char*)malloc(100);
strcpy(str, "hello world");
free(str); //還給你,我還要用,哼~
if (str != NULL)
{
strcpy(str, "!!!");
printf(str);
}
}
int main()
{
test();
}開辟100個字節(jié)的空間后,又把這塊空間還給操作系統(tǒng)。
再次把“!??!”放進這塊空間,非法修改
tips:動態(tài)內存管理是在堆區(qū)上進行的。
到此這篇關于C語言 超詳細梳理總結動態(tài)內存管理的文章就介紹到這了,更多相關C語言 動態(tài)內存管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C/C++?Qt?Tree與Tab組件實現(xiàn)分頁菜單功能
這篇文章主要介紹了C/C++?Qt?Tree與Tab組件實現(xiàn)分頁菜單功能,實現(xiàn)一個類似于樹形菜單欄的功能,當用戶點擊菜單欄中的選項時則會跳轉到不同的頁面上,本文簡單給大家分享實現(xiàn)代碼,感興趣的朋友跟隨小編一起看看吧2021-11-11
詳解C語言中free()函數(shù)與getpagesize()函數(shù)的使用
這篇文章主要介紹了詳解C語言中free()函數(shù)與getpagesize()函數(shù)的使用,是C語言入門學習中的基礎知識,需要的朋友可以參考下2015-08-08
VC自定義消息響應函數(shù)postmessage用法示例
這篇文章主要介紹了VC自定義消息響應函數(shù)postmessage用法示例,并對比說明了postmessage與sendmessage的用法區(qū)別,需要的朋友可以參考下2014-10-10
關于c++編譯protobuf時提示LNK2001 無法解析的外部符號的問題
這篇文章主要介紹了關于c++編譯protobuf時提示LNK2001 無法解析的外部符號的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12

