一、指针变量的本质
- 定义:指针变量是 "存储地址的变量",其类型必须与它所指向的变量类型一致。
- 内存占用:指针变量本身占用的内存大小固定(与系统位数相关,32 位系统占 4 字节,64 位系统占 8 字节),与它指向的数据类型无关(无论是 int*、double* 还是 struct*,指针本身大小都一样)。
二、定义与初始化
三种初始化的方式
- 指向已存在的变量
bash
int a = 10;
int* p = &a; // p 存储变量 a 的地址(&a 表示取 a 的地址)
- 指向动态分配的内存(通过 new)
bash
int* p = new int(20); // p 指向堆中一块存储 20 的 int 内存
- 指向空
指针必须初始化后才能安全使用,否则会成为野指针(指向随机内存,访问可能导致程序崩溃)nullptr 是专门为指针设计的空值,而 NULL 本质是整数 0,这会导致函数重载时的歧义问题; NULL 是历史遗留产物(为兼容 C 语言),在 C++ 中容易引发类型混淆
bash
int* p = nullptr; // 空指针,安全的未指向状态(推荐使用)
int* p = NULL; // 空指针,指向内存编号为0的空间(不推荐使用)
三、空指针与野指针
空指针:p = nullptr(或 p = NULL),明确表示不指向任何有效内存,访问会报错(易于调试)。
野指针:未初始化或指向已释放内存的指针(如 int* p; 或 delete p; 后未置空),访问会导致不可预测的错误(必须避免)
四、指针变量的核心操作
- 解运算
bash
int a = 10;
int* p = &a;
cout << *p << endl; // 解引用:输出 p 指向的变量的值(即 a 的值 10)
*p = 30; // 解引用:修改 p 指向的变量的值(此时 a 的值变为 30)
cout << a << endl; // 输出 30(a 被间接修改)
- 取地址
bash
int a = 10;
int* p = &a;
cout << "p 存储的地址(即 a 的地址):" << p << endl; // 如 0x7ffd...
cout << "p 自身的地址(栈上的地址):" << &p << endl; // 如 0x7ffd...(与 p 存储的地址不同)
- 指针的赋值
bash
int a = 10, b = 20;
int* p = &a; // p 先指向 a
p = &b; // p 改为指向 b(此时 *p 是 20)
五、指针变量做函数形参实现值传递
bash
/*
指针的学习
指针用于记录内存地址,间接访问数据
0-255之间的内存编号是系统占用不可访问
*/
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;
void changeNum(int *p1, int *p2)
{
int x = *p1;
*p1 = *p2;
*p2 = x;
}
void changeArr(int * arr ,int len){
for (int i = 0; i < len; i++)
{
cout << "循环打印" << arr[i] << endl;
}
}
int main()
{
system("chcp 65001 >nul"); // 汉化
/*指针遍历数组*/
int arr[] = {1, 2, 3, 4, 5};
const int *pointer = arr;
for (int i = 0; i < (sizeof(arr) / sizeof(arr[0])); i++)
{
cout << "指针指向数组的第" << i << "个元素值为:" << *pointer << endl;
pointer++;
}
/*指针与函数*/
// 值传递中,如果传递的是地址,那么实参会被修改
int num1 = 10;
int num2 = 20;
changeNum(&num1, &num2);
cout << "转换之后的值:" << num1 << num2 << endl;
changeArr(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
六、补充
(一)、const修饰的指针
- 指针常量
bash
/*指针常量*/
// 指针常量指向的值可以改,但是指向的地址不能改
int *const p2 = &a;
*p2 = 20;
- 常量指针
bash
/*常量指针*/
// 指针的指向可以修改,但不能修改指向的值
int a = 10;
const int *p1 = &a;
// *p1 = 20;//报错
- 双重常量指针(我自己取的名)
bash
// 指向的地址和值都不能修改
const int *const p3 = &a;
(二)、指向数组的指针
代码示例:
bash
#include <iostream> //标准输入输出控件
#include <iomanip>
#include <string> //使用string声明字符串时必须包含
#include <cstdlib> //汉化
using namespace std;
int *deleteArr()
{
int *arr = new int[10]; // 在堆中开辟一个连续的空间
for (int i = 0; i < 10; i++)
{
arr[i] = 100 + i;
}
cout << "arr[0]:" << &arr[0] << endl;
delete[] arr; // 删除数组
cout << "arr:" << arr << endl;
// 将野指针返回给调用者,调用者若使用该指针(如访问 *arr 或 arr[0]),会触发未定义行为(程序崩溃、数据错乱、运行异常等)
return arr;
}
int main()
{
system("chcp 65001 >nul"); // 汉化
int *arr = deleteArr();
cout << "arr:" << arr << endl;
return 0;
}
new int[10] 在堆区分配了一块连续的内存,用于存储 10 个 int 元素(共 40 字节,每个 int 占 4 字节)。 这个动态数组的首元素的地址(即数组的首地址)会被返回,并赋值给 arr。因此,arr 中存储的是堆区数组的首地址。arr[i] 等价于 *(arr + i),即 "从 arr 指向的首地址向后偏移 i 个 int 元素的位置,并访问该位置的值"