一、指针到底是什么?(通俗理解)

先抛开专业术语,用生活中的例子帮你理解:

  • 假设你有一个变量 int a = 10;,这个变量就像一个储物柜a 是储物柜的名字,10 是储物柜里的东西,而这个储物柜在内存中有一个唯一的地址(比如0x0065FDF0)。
  • 指针就是一个专门用来存放“储物柜地址”的变量,它不存具体数值(比如10),只存地址。

专业定义:指针是一种特殊的变量类型,它存储的不是普通数据(如整数、字符串),而是另一个变量在内存中的内存地址

核心符号

  • &:取地址符,作用是“获取变量的内存地址”(比如&a就是拿变量a的地址)。
  • *:解引用符,作用是“根据地址找到对应的变量/值”(比如指针p存了a的地址,*p就等价于a)。

二、指针的基本语法(从声明到使用)

1. 指针变量的声明

语法:数据类型 *指针变量名;

  • 注意:* 表示这是一个指针变量,数据类型必须和它指向的变量类型一致

示例(声明指向int类型的指针):

#include <iostream>
using namespace std;

int main() {
    // 1. 普通变量
    int a = 10;  // 定义int型变量a,值为10
    cout << "变量a的值:" << a << endl;
    cout << "变量a的地址:" << &a << endl;  // &a 获取a的地址,输出类似0x0065FDF0

    // 2. 声明指针变量(指向int类型)
    int *p;  // p是指针变量,专门存int类型变量的地址
    p = &a;  // 把a的地址赋值给指针p,此时p指向a

    // 3. 输出指针本身的值(就是a的地址)
    cout << "指针p的值(a的地址):" << p << endl;  // 和&a输出结果一样
    // 4. 解引用:通过指针p访问a的值
    cout << "通过*p访问a的值:" << *p << endl;  // 输出10,等价于a

    return 0;
}

运行结果示例:

变量a的值:10
变量a的地址:0x7ffeefbff5ac
指针p的值(a的地址):0x7ffeefbff5ac
通过*p访问a的值:10

2. 指针的核心应用1:通过指针修改变量值

指针的一大作用是“间接操作变量”,哪怕你拿不到变量名,只要有地址就能改值:

#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int *p = &a;  // 声明指针的同时赋值(常用写法)

    cout << "修改前,a的值:" << a << endl;  // 10
    *p = 20;  // 解引用p,等价于修改a的值
    cout << "修改后,a的值:" << a << endl;  // 20

    return 0;
}

解释:*p = 20 相当于“找到p存的地址对应的变量,把它的值改成20”,本质就是改a的值。

3. 指针的核心应用2:函数参数传指针(实现“传址调用”)

C++函数默认是“传值调用”(把变量值复制一份传给函数,函数内修改不影响原变量),而指针可以实现“传址调用”(传变量地址,函数内直接修改原变量)。

对比示例:

#include <iostream>
using namespace std;

// 传值调用:修改的是副本,原变量不变
void changeValue1(int x) {
    x = 100;
}

// 传址调用:传指针,修改原变量
void changeValue2(int *x) {
    *x = 100;  // 解引用,修改地址对应的原变量
}

int main() {
    int num = 10;

    changeValue1(num);
    cout << "传值调用后num:" << num << endl;  // 还是10

    changeValue2(&num);  // 传num的地址
    cout << "传址调用后num:" << num << endl;  // 变成100

    return 0;
}

运行结果:

传值调用后num:10
传址调用后num:100

这是指针最常用的场景之一(比如函数要修改多个外部变量时,用指针比返回值更方便)。

4. 指针的核心应用3:指向数组(简化数组操作)

数组名本质上就是数组第一个元素的地址,所以指针可以直接操作数组:

#include <iostream>
using namespace std;

int main() {
    int arr[5] = {1,2,3,4,5};
    int *p = arr;  // 数组名arr等价于&arr[0],直接赋值给指针

    // 用指针遍历数组
    for (int i = 0; i < 5; i++) {
        cout << *p << " ";  // 解引用p,取当前指向的数组元素
        p++;  // 指针自增,指向数组的下一个元素(自动按类型大小偏移)
    }
    // 输出:1 2 3 4 5

    return 0;
}

解释:p++ 不是简单加1,而是根据指针类型(int占4字节)偏移4个字节,刚好指向数组的下一个元素。

三、新手必避的坑

  1. 空指针:不要操作未赋值的指针(野指针),如果指针暂时不用,赋值为nullptr(C++11后推荐):
    int *p = nullptr;  // 空指针,指向“空地址”
    // 注意:不能解引用空指针(*p = 10; 会崩溃)
    
  2. 类型匹配:指针类型必须和指向的变量类型一致(比如int指针不能指向char变量),除非强制类型转换(新手暂时别用)。
  3. 数组越界:指针遍历数组时,别超出数组范围(比如数组只有5个元素,指针别指向第6个),否则会访问非法内存。

总结

  1. 指针是存内存地址的变量,核心符号:&(取地址)、*(解引用)。
  2. 指针的核心价值:间接修改变量函数传址调用(修改外部变量)高效操作数组
  3. 新手避坑:别用未赋值的野指针,指针类型要匹配,避免数组越界。

指针是C++的核心,先掌握这些基础应用,后续学习动态内存分配(new/delete)、结构体指针、函数指针时会更轻松。

0 条评论

目前还没有评论...