網(wǎng)站首頁 編程語言 正文
1.C 內(nèi)存管理函數(shù)
C 語言為內(nèi)存的分配和管理提供了幾個函數(shù)。這些函數(shù)可以在 <stdlib.h>
頭文件中找到。
序號 | 函數(shù)和描述 |
---|---|
1 | void calloc(int num, int size); 在內(nèi)存中動態(tài)地分配 num 個長度為 size 的連續(xù)空間,并將每一個字節(jié)都初始化為 0。所以它的結(jié)果是分配了 numsize 個字節(jié)長度的內(nèi)存空間,并且每個字節(jié)的值都是0。 |
2 | void free(void *address); 該函數(shù)釋放 address 所指向的內(nèi)存塊,釋放的是動態(tài)分配的內(nèi)存空間。 |
3 | void *malloc(int num); 在堆區(qū)分配一塊指定大小的內(nèi)存空間,用來存放數(shù)據(jù)。這塊內(nèi)存空間在函數(shù)執(zhí)行完成后不會被初始化,它們的值是未知的。 |
4 | void *realloc(void *address, int newsize); 該函數(shù)重新分配內(nèi)存,把內(nèi)存擴展到 newsize。 |
2.C語音里面的內(nèi)存劃分
- 棧區(qū)(棧內(nèi)存,存放局部變量,自動分配和釋放,里面函數(shù)的參數(shù),方法里面的臨時變量)
- 堆區(qū)(動態(tài)內(nèi)存分配,C語音里面由程序員手動分配),最大值為操作系統(tǒng)的80%
- 全局區(qū)或靜態(tài)區(qū)
- 常量區(qū)(字符串)
- 程序代碼區(qū)
3.靜態(tài)與動態(tài)內(nèi)存分配
在程序運行過程中,動態(tài)指定需要使用的內(nèi)存大小,手動釋放,釋放之后這些內(nèi)存還可以被重新使用。
靜態(tài)內(nèi)存分配,分配內(nèi)存大小的是固定,產(chǎn)生的問題:
- 1.很容易超出棧內(nèi)存的最大值
- 2.為了防止內(nèi)存不夠用會開辟更多的內(nèi)存,容易浪費內(nèi)存。
動態(tài)內(nèi)存分配,在程序運行過程中,動態(tài)指定需要使用的內(nèi)存大小,手動釋放,釋放之后這些內(nèi)存還可以被重新使用
4.棧溢出
下面的代碼會導(dǎo)致棧溢出:
void main(){ //屬于靜態(tài)內(nèi)存分配,分配到棧里面,Window里面每一個應(yīng)用棧大概是2M,大小確定。與操作系統(tǒng)有關(guān)。 int a [1024 * 1024 * 10 * 4]; }
該靜態(tài)內(nèi)存定義為40M,而Window
里面每一個應(yīng)用棧大概是2M,超出了范圍, 會報stack overflow
錯誤 。
5.動態(tài)內(nèi)存分配與釋放
//堆存分配,40M //參數(shù):字節(jié) KB M 10M 40M //開辟 int* p1 = (int*)malloc(1024*1024*10*sizeof(int)); //釋放 free(p1);
通過動態(tài)內(nèi)存分配來動態(tài)指定數(shù)組的大小:
在程序運行過長中,可以隨意的開辟指定大小的內(nèi)存,以供使用,相當于Java
中的集合
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <Windows.h> //創(chuàng)建一個數(shù)組,動態(tài)指定數(shù)組的大小 void main() { //靜態(tài)內(nèi)存分配創(chuàng)建數(shù)組,數(shù)組的大小是固定的 //int i = 10; //int a[i]; int len; printf("輸入數(shù)組的長度:"); scanf("%d", &len); //開辟內(nèi)存,大小內(nèi)存len * 4 字節(jié) int* p = (int*)malloc(len * sizeof(int));//p:數(shù)組的首地址 int i = 0; for (; i < len; i++) { p[i] = rand() % 100; printf("%d,%#x\n", p[i], &p[i]); } //手動釋放內(nèi)存 free(p); getchar(); }
結(jié)果輸出:
41,0x513f48
67,0x513f4c
34,0x513f50
0,0x513f54
69,0x513f58
24,0x513f5c
6.重新分配realloc
重新分配內(nèi)存的兩種情況:
縮小內(nèi)存,縮小的那一部分數(shù)據(jù)會丟失
擴大內(nèi)存,(連續(xù)的)
1.如果當前內(nèi)存段后面有需要的內(nèi)存空間,直接擴展這段內(nèi)存空間,realloc
返回原指針
2.如果當前內(nèi)存段后面的空閑字節(jié)不夠,那么就使用堆中的第一個能夠滿足這一要求的內(nèi)存塊,將目前的數(shù)據(jù)復(fù)制到新的位置,并將原來的數(shù)據(jù)庫釋放掉,返回新的內(nèi)存地址
3.如果申請失敗,返回NULL,原來的指針仍然有效
void main() { int len; printf("第一次輸入數(shù)組的長度:"); scanf("%d", &len); //開辟內(nèi)存,大小內(nèi)存len * 4 字節(jié) int* p = (int*)malloc(len * sizeof(int));//p:數(shù)組的首地址 int i = 0; for (; i < len; i++) { p[i] = rand() % 100; printf("%d,%#x\n", p[i], &p[i]); } int addLen; printf("輸入數(shù)組增加的長度:"); scanf("%d", &addLen); int* p2 = (int*)realloc(p, sizeof(int) * (len + addLen)); if (p2 == NULL) { printf("重新分配失敗......"); } printf("------------新數(shù)組-------------------\n"); //重新賦值 i = 0; for (; i < len + addLen; i++) { p2[i] = rand() % 200; printf("%d,%#x\n", p2[i], &p2[i]); } //手動釋放內(nèi)存 p2釋放內(nèi)存 p也會釋放,因為給p2分配內(nèi)存的時候要么p已經(jīng)釋放,要么p2、p指向統(tǒng)一地址區(qū)域 if (p2 != NULL) { free(p2); p2 = NULL; } getchar(); }
結(jié)果輸出:
第一次輸入數(shù)組的長度:5
41,0x5e4ad8
67,0x5e4adc
34,0x5e4ae0
0,0x5e4ae4
69,0x5e4ae8
輸入數(shù)組增加的長度:5
------------新數(shù)組-------------------
124,0x5e4ad8
78,0x5e4adc
158,0x5e4ae0
162,0x5e4ae4
64,0x5e4ae8
105,0x5e4aec
145,0x5e4af0
81,0x5e4af4
27,0x5e4af8
161,0x5e4afc
內(nèi)存分配的幾個注意細節(jié):
- 1.不能多次釋放
- 2.釋放完之后(指針仍然有值),給指針置NULL,標志釋放完成
- 3.內(nèi)存泄露(p重新賦值之后,再free,并沒有真正釋放內(nèi)存)
避免內(nèi)存泄漏:
p重新賦值之前先free
內(nèi)存泄漏寫法:
void main(){ //40M int* p1 = malloc(1024 * 1024 * 10 * sizeof(int)); //free(p1); //p1 = NULL; //錯誤,沒有立即釋放內(nèi)存 printf("%#x\n",p1); //80M p1 = malloc(1024 * 1024 * 10 * sizeof(int) * 2); free(p1); p1 = NULL; getchar(); }
打開任務(wù)管理器,看到有40M內(nèi)存泄漏。
正確寫法:
void main(){ //40M int* p1 = malloc(1024 * 1024 * 10 * sizeof(int)); free(p1); p1 = NULL; printf("%#x\n",p1); //80M p1 = malloc(1024 * 1024 * 10 * sizeof(int) * 2); free(p1); p1 = NULL; getchar(); }
打開任務(wù)管理器,看到內(nèi)存只有0.3M,正常。
原文鏈接:https://juejin.cn/post/7037828693879701518
相關(guān)推薦
- 2023-10-14 C/C++--跨平臺--預(yù)定義宏 WIN32、_WIN32、_WIN64
- 2022-09-26 使用JDBC連接數(shù)據(jù)庫執(zhí)行sql語句,創(chuàng)建數(shù)據(jù)庫連接池
- 2022-10-22 BroadcastReceiver靜態(tài)注冊案例詳解_Android
- 2022-07-21 SQL查詢出的兩列合并成一列顯示
- 2023-01-11 pytorch中如何設(shè)置隨機種子_python
- 2022-04-28 C語言動態(tài)開辟內(nèi)存詳解_C 語言
- 2022-03-14 Token跨域問題Response to preflight request doesn‘t pas
- 2023-05-06 Python正則表達式中g(shù)roup與groups的用法詳解_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支