文章目录
1. 第一个指针程序
1.1 指针的概念
指针是 C++ 中的一种变量,其存储的是内存的地址。它指向的内存位置、大小和类型取决于指针的声明。指针可以申请新的内存,也可以指向已有的内存。
1.2 申请和指向内存
你可以使用 new
运算符为指针申请新的内存,或者让它指向一个已经存在的变量。使用 &
运算符可以获取变量的地址,此处的 &
读作 “取地址”。
int *p1 = new int; // 申请新的内存,并将其地址赋给 p1
*p1 = 101; // 将 101 存储到 p1 所指向的内存中
int i = 102;
int* p2 = &i; // 让 p2 指向变量 i 的内存
*p2 = 103; // 通过 p2 修改 i 的值
1.3 释放内存
你可以使用 delete
运算符释放指针所申请的内存。在释放之后,指针变量依然存在,但是其指向的内存已经被回收,不再可用。
delete p1; // 释放 p1 所指向的内存
1.4 指针的大小
无论指针的类型如何,它本身的大小是固定的。这是因为指针变量存储的是内存地址,而不是实际的数据。在 32 位系统中,指针的大小通常是 4 字节,在 64 位系统中,指针的大小通常是 8 字节。
cout << "sizeof(p1): " << sizeof(p1) << endl; // 输出指针 p1 的大小
cout << "sizeof(*p1): " << sizeof(*p1) << endl; // 输出 p1 所指向的数据的大小
2. 程序的内存地址划分
C++ 程序的内存通常被划分为以下几个区域:
- 保留区:这个区域是为了防止程序访问空指针导致的错误而设立的,通常位于 0 地址。
- 代码区:也被称为 .text 区,存储程序的机器指令。
- 全局/静态存储区:包含了 .data(已初始化的全局变量和静态变量)和 .bss(未初始化的全局变量和静态变量)。
- 堆区:程序在运行时可以从堆区动态分配内存和释放内存。
- 栈区:用于存储函数的局部变量、函数参数以及返回地址等。
- 内核区:存储系统级别的指令和数据。
3. 进程的内存与指针代码关系
指针代码直接操作内存,对应进程的内存布局。对全局、局部变量的访问,实质上是对静态存储区和栈区的访问。动态内存分配的new、delete操作,实质上是对堆区的操作。这就构成了进程内存与指针代码的直接关系。
4. 堆栈空间的初始化
4.1 栈空间
栈空间是程序自动分配和释放的,用于存放函数的局部变量、参数等。对于栈空间的数组,我们可以使用 memset
函数将其全部初始化为 0。
int arr1[10];
memset(arr1, 0, sizeof(arr1)); // 使用 sizeof 获取数组的大小
你也可以在定义数组时直接初始化数组的元素:
int arr2[5] = {
1, 2, 3, 4, 5 }; // 初始化一个大小为 5 的数组
4.2 堆空间
堆空间是由程序员负责管理的,我们可以使用 new
和 delete
在堆上分配和释放内存。堆空间的数组同样可以使用 memset
进行初始化,需要注意的是,对于非字符类型的数组,我们需要将 memset
的第三个参数乘以元素的大小。
int *parr1 = new int[1024]; // 在堆上分配一块能存放1024个int的内存
memset(parr1, 0, 1024 * sizeof(int)); // 将内存全部初始化为 0
在完成对堆空间的操作后,记得使用 delete[]
释放内存,并将指针设置为 nullptr
,以防止野指针的产生。
delete[] parr1;
parr1 = nullptr;
5. C++11中的for遍历
C++11 引入了新的 for 循环语法,使得遍历数组和容器变得更加简单。以下是使用新的 for 循环语法遍历数组的例子:
int arr[] = {
1, 2,