前言
本篇文章主要介绍了C/C++程序的内存分区
1.C/C++程序的内存分布
1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量值等。
2、堆区(heap):一般由程序员分配释放,或者在程序结束后被OS回收。
3、全局/静态区(static):全局变量和静态变量的存储是放在一起的,在程序编译时分配。
4、文字常量区:存放常量字符串。
5、程序代码区:存放函数体(包括类的成员函数、全局函数)的二进制代码
2.动态内存分配
2.1 动态内存的分配和释放
- C语言:
void *malloc(size_t size);
void free(void *);
malloc 在内存的动态存储区中分配一块长度为 size 字节的连续区域返回该区域的首地址 - C++:
new 和 delete 运算符使用的一般格式为:
new 运算符 动态分配堆内存
使用方法:
指针变量 = new 类型(常量);
指针变量 = new 类型[表达式]; //数组
指针变量 = new 类型[表达式][表达式] //二维数组
作用:从堆上分配一块“类型”指定大小的存储空间,返回首地址
其中:“常量”是初始化值,可缺省
创建数组对象时,不能为对象指定初始值 delete 运算符 释放已分配的内存空间
使用方式:
普通类型(非数组)使用: delete 指针变量;
数组 使用: delete[] 指针变量;
其中“指针变量” 必须时一个 new 返回的指针
注意: new 和 delete 是运算符,不是函数,因此执行效率高。
2.2 为什么要使用动态内存分配
(1)被调用函数之外需要使用被调用函数内部的指针对应的地址空间;
//(1)通过返回指针来访问函数内动态内存
int *demo(int count) {
int *ap = NULL;
ap = (int*)malloc(sizeof(int) * count);
return ap;
}
//(2)通过二级指针访问函数内动态内存
void demo2(int count, int **p) {
*p = new int[count];
}
(2)内存按需分配,避免浪费
(3)给程序分配更多的内存空间(在不同的系统中,栈空间限制通常以MB为单位,堆空间限制通常以GB为单位)(动态内存分配,是分配在堆空间的)
2.3 内存泄漏
内存泄露: 是指程序中己动态分配的堆内存由于某种原因程序未释放或 无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果所以在使用完动态分配的内存后, 要用free()或者delete释放掉该部分内存。
3.变量的四种存储类型
3.1 四种存储类型
- auto(自动变量):函数中所有的非静态局部变量(一般我们不必在意)
//auto 定义的变量必须进行初始化操作
//c中可以这样写
auto int a = 10;
//C++中的auto经过了优化,可以自动识别变量的数据类型
auto b = 'a';
printf("%s",typeid(b).name());
- static(静态变量):在变量前加上 static 关键字的变量。 静态变量与全局变量都存储在全局静态区
void static_test() {
static int a = 10;//静态变量a的值会随调用次数而增加
int b = 10;
printf("a:%d,b:%d\n", a, b);
a++;
}
- extern(外部变量):把全局变量在其他源文件中声明成 extern 变量,可以扩展该全局变量的作用域至声明的那个文件,其本质作用就是对全局变量作用域的扩展。
test.cpp
int a = 10;
test2.cpp
#include<stdio.h>
#include<stdlib.h>
int main(void){
extern int a;
printf("%d",a);
system("pause");
return 0;
}
- register(寄存器变量):
一般经常被使用的的变量(如某一变量需要计算几千次)可以设置成寄存器变量, register 变量会被存储在寄存器中,计算速度远快于存在内存中的非 register
寄存器变量本身是没有地址的,但在C++中做了优化,如果我们打印它的地址,就变成了普通的auto变量
void register_test() {
register int reg = 10;
printf("®:0x%p\n", ®);
}