C/C++学习之路_七: 内存管理
C/C++學(xué)習(xí)之路_七: 內(nèi)存管理
目錄
1. 作用域
1. 局部變量
2. 靜態(tài)局部變量
3. 全局變量
4. 靜態(tài)全局變量
5. extern全局變量聲明
6. 全局函數(shù)和靜態(tài)函數(shù)
7. 總結(jié)
| auto變量 | 一對(duì){}內(nèi) | 當(dāng)前函數(shù) |
| static局部變量 | 一對(duì){}內(nèi) | 整個(gè)程序運(yùn)行期 |
| extern變量 | 整個(gè)程序 | 整個(gè)程序運(yùn)行期 |
| static全局變量 | 當(dāng)前文件 | 整個(gè)程序運(yùn)行期 |
| extern函數(shù) | 整個(gè)程序 | 整個(gè)程序運(yùn)行期 |
| static函數(shù) | 當(dāng)前文件 | 整個(gè)程序運(yùn)行期 |
| register變量 | 一對(duì){}內(nèi) | 當(dāng)前函數(shù) |
| 全局變量 | 整個(gè)程序 | 整個(gè)程序運(yùn)行期 |
2. 內(nèi)存布局
1. 內(nèi)存分區(qū)
1. 代碼區(qū)
2. 已初始化數(shù)據(jù)段(data段)
3. 未初始化數(shù)據(jù)區(qū)(又叫 bss 區(qū))
4. 堆(heap)
5. 棧(stack)
棧是一個(gè)由內(nèi)核動(dòng)態(tài)調(diào)整的內(nèi)存段落,由棧幀(Stack Frames)組成,進(jìn)程每調(diào)用一個(gè)函數(shù),都將為該函數(shù)分配一個(gè)棧幀,棧幀中保存了該函數(shù)的局部變量、參數(shù)值和返回值,棧幀會(huì)在函數(shù)返回時(shí)清理掉。
在程序運(yùn)行過程中實(shí)時(shí)的加載和釋放,因此,局部變量的生存周期為申請(qǐng)到釋放該段棧空間。
4. 棧存儲(chǔ)著自動(dòng)變量以及每次函數(shù)調(diào)用時(shí)保存的信息,每當(dāng)函數(shù)被調(diào)用時(shí),返回地址以及調(diào)用者的上下文環(huán)境例如一些機(jī)器寄存器都存儲(chǔ)在棧中,新的被調(diào)用函數(shù)此時(shí)會(huì)在棧上重新分配自動(dòng)或者臨時(shí)變量,這就是遞歸函數(shù)的工作原理。
5. 每當(dāng)函數(shù)遞歸調(diào)用自己時(shí),都會(huì)使用新的棧幀,因此當(dāng)前函數(shù)實(shí)體內(nèi)的棧幀內(nèi)的變量不會(huì)影響另外一個(gè)函數(shù)實(shí)體內(nèi)的變量。
棧主要有三個(gè)用途:
為函數(shù)內(nèi)部聲明的非靜態(tài)局部變量(局部變量)提供存儲(chǔ)空間。
記錄函數(shù)調(diào)用過程相關(guān)的維護(hù)性信息,稱為棧幀或過程活動(dòng)記錄
臨時(shí)存儲(chǔ)區(qū),用于臨時(shí)存放長(zhǎng)算術(shù)表達(dá)式部分計(jì)算結(jié)果或alloca()函數(shù)分配的棧內(nèi)內(nèi)存。
2. 存儲(chǔ)類型總結(jié)
| auto變量 | 一對(duì){}內(nèi) | 當(dāng)前函數(shù) | 棧區(qū) |
| static局部變量 | 一對(duì){}內(nèi) | 整個(gè)程序運(yùn)行期 | 初始化在data段,未初始化在BSS段 |
| extern變量 | 整個(gè)程序 | 整個(gè)程序運(yùn)行期 | 初始化在data段,未初始化在BSS段 |
| static全局變量 | 當(dāng)前文件 | 整個(gè)程序運(yùn)行期 | 初始化在data段,未初始化在BSS段 |
| extern函數(shù) | 整個(gè)程序 | 整個(gè)程序運(yùn)行期 | 代碼區(qū) |
| static函數(shù) | 當(dāng)前文件 | 整個(gè)程序運(yùn)行期 | 代碼區(qū) |
| register變量 | 一對(duì){}內(nèi) | 當(dāng)前函數(shù) | 運(yùn)行時(shí)存儲(chǔ)在CPU寄存器 |
| 字符串常量 | 當(dāng)前文件 | 整個(gè)程序運(yùn)行期 | data段 |
3. 內(nèi)存操作函數(shù)
1. memset()
#include <string.h> void *memset(void *s, int c, size_t n); 功能:將s的內(nèi)存區(qū)域的前n個(gè)字節(jié)以參數(shù)c填入 參數(shù):s:需要操作內(nèi)存s的首地址c:填充的字符,c雖然參數(shù)為int,但必須是unsigned char , 范圍為0~255n:指定需要設(shè)置的大小 返回值:s的首地址int a[10];memset(a, 0, sizeof(a));memset(a, 97, sizeof(a));int i = 0;for (i = 0; i < 10; i++){printf("%c\n", a[i]);}2. memcpy()
#include <string.h> void *memcpy(void *dest, const void *src, size_t n); 功能:拷貝src所指的內(nèi)存內(nèi)容的前n個(gè)字節(jié)到dest所指的內(nèi)存地址上。 參數(shù):dest:目的內(nèi)存首地址src:源內(nèi)存首地址,注意:dest和src所指的內(nèi)存空間不可重疊,可能會(huì)導(dǎo)致程序報(bào)錯(cuò)n:需要拷貝的字節(jié)數(shù) 返回值:dest的首地址int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int b[10];memcpy(b, a, sizeof(a));int i = 0;for (i = 0; i < 10; i++){printf("%d, ", b[i]);}printf("\n");//memcpy(&a[3], a, 5 * sizeof(int)); //err, 內(nèi)存重疊3. memmove()
4. memcmp()
#include <string.h> int memcmp(const void *s1, const void *s2, size_t n); 功能:比較s1和s2所指向內(nèi)存區(qū)域的前n個(gè)字節(jié) 參數(shù):s1:內(nèi)存首地址1s2:內(nèi)存首地址2n:需比較的前n個(gè)字節(jié) 返回值:相等:=0大于:>0小于:<0int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int b[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int flag = memcmp(a, b, sizeof(a));printf("flag = %d\n", flag);4. 堆區(qū)內(nèi)存分配和釋放
1. malloc()
#include <stdlib.h> void *malloc(size_t size); 功能:在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū)(堆區(qū))中分配一塊長(zhǎng)度為size字節(jié)的連續(xù)區(qū)域,用來存放類型說明符指定的類型。分配的內(nèi)存空間內(nèi)容不確定,一般使用memset初始化。 參數(shù):size:需要分配內(nèi)存大小(單位:字節(jié)) 返回值: 成功:分配空間的起始地址 失敗:NULL#include <stdlib.h> #include <stdio.h> #include <string.h>int main(){int count, *array, n;printf("請(qǐng)輸入要申請(qǐng)數(shù)組的個(gè)數(shù):\n");scanf("%d", &n);array = (int *) malloc(n * sizeof(int));if (array == NULL) {printf("申請(qǐng)空間失敗!\n");return -1;}//將申請(qǐng)到空間清0memset(array, 0, sizeof(int) * n);for (count = 0; count < n; count++) /*給數(shù)組賦值*/array[count] = count;for (count = 0; count < n; count++) /*打印數(shù)組元素*/printf("%2d", array[count]);free(array);return 0; }2. free()
#include <stdlib.h> void free(void *ptr); 功能:釋放ptr所指向的一塊內(nèi)存空間,ptr是一個(gè)任意類型的指針變量,指向被釋放區(qū)域的首地址。對(duì)同一內(nèi)存空間多次釋放會(huì)出錯(cuò)。 參數(shù): ptr:需要釋放空間的首地址,被釋放區(qū)應(yīng)是由malloc函數(shù)所分配的區(qū)域。 返回值:無3. 內(nèi)存分區(qū)代碼分析
1. 返回棧區(qū)地址
#include <stdio.h> int *fun() {int a = 10;return &a;//函數(shù)調(diào)用完畢,a釋放 }int main(int argc, char *argv[]) {int *p = NULL;p = fun();*p = 100; //操作野指針指向的內(nèi)存,errreturn 0; }2. 返回data區(qū)地址
#include <stdio.h>int *fun() {static int a = 10;return &a; //函數(shù)調(diào)用完畢,a不釋放 }int main(int argc, char *argv[]) {int *p = NULL;p = fun();*p = 100; //okprintf("*p = %d\n", *p);return 0; }3. 值傳遞1
#include <stdio.h> #include <stdlib.h>void fun(int *tmp) {tmp = (int *) malloc(sizeof(int));*tmp = 100; }int main(int argc, char *argv[]) {int *p = NULL;fun(p); //值傳遞,形參修改不會(huì)影響實(shí)參printf("*p = %d\n", *p);//err,操作空指針指向的內(nèi)存return 0; }4. 值傳遞2
#include <stdio.h> #include <stdlib.h>void fun(int *tmp) {*tmp = 100; }int main(int argc, char *argv[]) {int *p = NULL;p = (int *) malloc(sizeof(int));fun(p); //值傳遞printf("*p = %d\n", *p); //ok,*p為100return 0; }5. 返回堆區(qū)地址
#include <stdio.h> #include <stdlib.h>int *fun() {int *tmp = NULL;tmp = (int *) malloc(sizeof(int));*tmp = 100;return tmp;//返回堆區(qū)地址,函數(shù)調(diào)用完畢,不釋放 }int main(int argc, char *argv[]) {int *p = NULL;p = fun();printf("*p = %d\n", *p);//ok//堆區(qū)空間,使用完畢,手動(dòng)釋放if (p != NULL) {free(p);p = NULL;}return 0; } 超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的C/C++学习之路_七: 内存管理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C/C++学习之路_六: 指针
- 下一篇: C/C++学习之路_八: 复合类型