【C++学习】指针

一、指针变量的本质

  1. 定义:指针变量是 "存储地址的变量",其类型必须与它所指向的变量类型一致。
  2. 内存占用:指针变量本身占用的内存大小固定(与系统位数相关,32 位系统占 4 字节,64 位系统占 8 字节),与它指向的数据类型无关(无论是 int*、double* 还是 struct*,指针本身大小都一样)。

二、定义与初始化

三种初始化的方式

  1. 指向已存在的变量
bash 复制代码
int a = 10;
int* p = &a;  // p 存储变量 a 的地址(&a 表示取 a 的地址)
  1. 指向动态分配的内存(通过 new)
bash 复制代码
int* p = new int(20);  // p 指向堆中一块存储 20 的 int 内存
  1. 指向空
    指针必须初始化后才能安全使用,否则会成为野指针(指向随机内存,访问可能导致程序崩溃)nullptr 是专门为指针设计的空值,而 NULL 本质是整数 0,这会导致函数重载时的歧义问题; NULL 是历史遗留产物(为兼容 C 语言),在 C++ 中容易引发类型混淆
bash 复制代码
int* p = nullptr;  // 空指针,安全的未指向状态(推荐使用)
int* p = NULL; // 空指针,指向内存编号为0的空间(不推荐使用)

三、空指针与野指针

空指针:p = nullptr(或 p = NULL),明确表示不指向任何有效内存,访问会报错(易于调试)。

野指针:未初始化或指向已释放内存的指针(如 int* p; 或 delete p; 后未置空),访问会导致不可预测的错误(必须避免)

四、指针变量的核心操作

  1. 解运算
bash 复制代码
int a = 10;
int* p = &a;

cout << *p << endl;  // 解引用:输出 p 指向的变量的值(即 a 的值 10)
*p = 30;             // 解引用:修改 p 指向的变量的值(此时 a 的值变为 30)
cout << a << endl;   // 输出 30(a 被间接修改)
  1. 取地址
bash 复制代码
int a = 10;
int* p = &a;

cout << "p 存储的地址(即 a 的地址):" << p << endl;   // 如 0x7ffd...
cout << "p 自身的地址(栈上的地址):" << &p << endl;  // 如 0x7ffd...(与 p 存储的地址不同)
  1. 指针的赋值
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修饰的指针

  1. 指针常量
bash 复制代码
/*指针常量*/
    // 指针常量指向的值可以改,但是指向的地址不能改
    int *const p2 = &a;
    *p2 = 20;
  1. 常量指针
bash 复制代码
/*常量指针*/
    // 指针的指向可以修改,但不能修改指向的值
    int a = 10;
    const int *p1 = &a;
    // *p1 = 20;//报错
  1. 双重常量指针(我自己取的名)
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 元素的位置,并访问该位置的值"

相关推荐
蜗牛沐雨4 小时前
详解C++中的字符串流
c++·1024程序员节
蜗牛沐雨4 小时前
详解C++中的流
c++·1024程序员节
光影少年4 小时前
AIGG人工智能生态及学习路线和应用领域
人工智能·学习
scx201310044 小时前
20251025 分治总结
数据结构·c++·算法
m0_748240254 小时前
C++智能指针使用指南(auto_ptr, unique_ptr, shared_ptr, weak_ptr)
java·开发语言·c++
递归不收敛4 小时前
多模态学习大纲笔记(未完成)
人工智能·笔记·学习·自然语言处理
R-G-B4 小时前
【10】MFC入门到精通——MFC 创建向导对话框、属性页类、属性表类、代码
c++·mfc·创建向导对话框·创建属性页类·创建属性表类
FPGA-李宇航5 小时前
FPGA中,“按键控制LED灯实验”学习中常见问题、解决思路和措施以及经验总结!!!(新手必看)
学习·fpga开发·按键控制led灯
AA陈超5 小时前
虚幻引擎5 GAS开发俯视角RPG游戏 P06-16 属性菜单 - 构建
c++·游戏·ue5·游戏引擎·虚幻