在 C++程序中内存分为 5 个区,分别是栈、堆、自由存储区、全局/静态存储区和常量存储区。程序中的各种数据都存储在这些内存区域中。
栈区由编译器自动分配和释放,存放函数的参数以及局部变量。其分配运算内置于处理器的指令集中,效率很高。但是可使用的总量有限,一般不会超过 1M 字节。
堆区中内存的分配和释放由开发者负责。一般用运算符 new 分配内存,并用运算符 delete 释放内存。一个 new 要对应一个 delete,否则会导致内存泄露。如果开发没有释放,在程序结束的时候操作系统会自动回收。在堆上可分配的内存比栈上大了很多,且使用非常灵活。
自由存储区和堆类似,但是其内存管理是通过库函数 malloc 和 free 等进行的。在 C 程序中经常使用,虽然在 C++程序中仍然可以使用,但不如用堆方便。
全局/静态存储区中存放的是全局变量和静态变量。该存储区分配的内存在整个程序运行期间一直有效,直到程序结束由系统回收。常量存储区中存储的是常量,通常不允许修改。在程序中定义的常量以及指针字符串都存储在
这里。
#include <iostream>
using namespace std;
int a; // 全局变量,存储在全局/静态存储区
int main()
{
int b; //局部变量,存储在栈上
int* p = new int();//由运算符 new 分配的,存储在堆上
static int d; //静态变量,存储在全局/静态存储区
const int e = 0; //常量,存储在常量存储区
delete p; //释放堆中的内存
return0;
}
C++程序中的内存都要从上面的 5 个区中分配。不过栈、全局/静态存储区以及常量存储区中的分配是由编译器来进行的,并且在程序运行之前已经分配,因此称之为静态分配;堆以及自由存储区上内存的分配,是在程序运行的过程中进行的,称之为动态内存分配。下节中主要介绍通过new 进行的动态内存分配。只 有 在 堆 上 和自 由 存 储 区 中分 配 的 内 存 需要 开 发 者 管 理。 其他 存 储 区中 的 变 量 只要定义即可,其内存的分配和释放由编译器负责
在堆上分配内存
在堆上分配内存,要使用 new 关键字,后面跟一个数据类型。如果需要对分配出的内存进行初始化,则在类型后面加上一个括号,并带有初始值。为了保存分配出内存的地址,应当使用一个Int *p=new int (3); //p指向这块内存 3的意思是初始化 表示分配成功后*p为3,当然也可以不用初始值 eg:Int *p=new int ;//这种无初始值的情况下 若new的类型是类则会调用该类的默认构造函数
用new 为数组分配内存
Int *str =new int[10]// 10表示数组的长度 注意两种的括号的不一样; 好消息 好消息 用运算符 new 为数组分配内存空间时,其长度可以是变量,而不必是常量。因为动态内存分配在程序运行的时候才分配空间,所以当用 new 在堆上定义数组的时候,其长度可以是一个变量 不过嘛 缺点也是有的 那就是不能够对数组初始化
指向 const 的指针 他有两种写法(const int * p 或 int const *p)
指向 const 的指针,指的是一个指针指向的数据是常量,不可以被修改,但指针变量本身可以被修改
Eg:
Int a=0;
Const int *p;
P=&a;
*p=1;//错误 因为不能通过该const 指针修改其值
用 const 修饰的变量,只能用指向 const 的指针来指向,而不能用普通的指针
指向 const 的指针,只限制了指向变量不可以被修改,但是指针本身的指向是可以修改的:
int a ;
int b;
const int * p = &a
p = &b // 修改指针的指向
const 指针 (它就只有一种写法 int * const p)
const 指针,指的是指针变量本身是一个常量,只能指向定义时所给的那个数据,而不能指向别处,而对被指向的数据是没有影响的
int a;
int * const p=&a;
如果不要int a 则错误因为不能修改 const 指针的指向,所以在定义的时候必须给一个初始值
指向 const 的 const 指针
Const int *p(int const *p); Int * const p; Const int *const p;
三种 const 指针的定义很相似,很难以区分,这里有一个简单的技巧:从标识符的开始处读它,
并从里向外读,const 指定那个“最靠近”的。因此根据这个理解:第一个定义表示 int 不可以被
改变,第二个表示 p 不可以被改变,第三个表示 int 和 p 都不可以被改变。
引用
引用也是一种数据类型。不过,引用不能独立存在,而只能依附于一个变量。所以定义一个引用,必须要指明是哪个变量的引用。定义一个引用包括目标变量的数据类型、引用修饰符“&”、引用的标识符以及目标变量的标识符,其语法如下:
类型标识符 &引用名 = 目标变量名
Eg:
int a; //定义一个变量
Int & b=a; // 定义一个上述变量的引用 &可不是取地址符呀
引用一旦定义,则始终跟其目标变量绑定,而不能改变为其他变量的引用
另外,引用在其生命周期内完全可以替代其目标变量。也就是说,所有施加于引用上的操作,其效果都等同于直接对引用的目标变量进行操作。而且一旦目标变量的值发生了改变,引用的值也会发生同样的改变。
注意:
指针可以指向数组的地址来替代数组使用,而引用不可以替代数组,引用只能指向数组中的某一个元素
函 数 模 板
<typenameT1, typename T2, int num, double value>
上述模板参数列表中声明了两个类型参数 T1 和 T2,代表两种数据类型,可以是内置的类型,也可以是自定义类型。同时,该模板参数列表还声明了两个非类型参数 num 和 value,表示该模在定义过程中可以将 num 和 value 当做常量使用
函数模板中使用非类型参数,其目的就是为函数引入一个常量,以供定义函数时使用。当然这
个常量也可以作为函数参数的默认值使用
C++标准规定模板参数必须在程序编译时确定。因此非类型的模板参数的值必须
是一个常量,而且是编译时就能确认的常量,包括字面常量、符号常量(const 常
量)。
函数模板不是真正的函数,不能直接使用,必须先实例化
取函数模板的地址时也会导致函数模板的实例化。因为函数模板并不是真正的函数,所以其本
身也没有地址。但是 C++并不把“&函数模板名”(取地址符号‘&’也可以省略)这样的用法当做
一个错误,而是先对该函数模板进行实例化,然后取实例化所生成函数的地址
函数模板在程序运行时并不
存在,存在的只是其实例。函数模板实例化发生在编译期,而取地址则发生在程序运行期
shmily_h