CC++ & Algorithm

C++指针传递

较难29
语言版本:C++Python
概述:指针传递就像你把自己家的钥匙给朋友,朋友可以通过钥匙进你家搬东西。

指针传递:用地址“遥控”修改数据

想象一下,你有一盒乐高积木放在家里,朋友想帮你整理。如果你直接把整盒积木复印一份(值传递),朋友只能玩复印件,原件纹丝不动。如果你把家门钥匙(指针)给朋友,他就能直接进去,随意调整积木位置。在C++里,指针传递就是“给函数一个地址,函数顺着地址找到原变量,直接修改它”。

指针是一个变量,里面存的是另一个变量的内存地址(就像门牌号)。写函数时,参数写成 int *a,表示“a是一个指针,指向一个整数”。在函数内部,要通过 *a 才能访问那个整数本身(这叫“解引用”)。看起来有点绕,但用习惯后非常灵活。


1. 指针传递的基本写法

  • 定义指针int *ptr; —— 声明一个能存整数地址的指针。
  • 取地址&x —— 拿到变量x的地址。
  • 解引用*ptr —— 通过地址得到那个变量的值。

看一个简单例子——用指针修改一个人的成绩:

#include <iostream>
using namespace std;

// 通过指针把考试成绩+10分
void addBonus(int *score) {
    *score = *score + 10;   // 解引用,直接修改原变量
    cout << "加完分后分数是:" << *score << endl;
}

int main() {
    int myScore = 75;                    // 我的考试成绩75分
    cout << "原始分数:" << myScore << endl;
    addBonus(&myScore);                  // 传入myScore的地址
    cout << "主函数里现在分数:" << myScore << endl;  // 85分,真的变了
    return 0;
}

运行结果:

原始分数:75
加完分后分数:85
主函数里现在分数:85

你会发现,myScore 在函数外部也被修改了,因为函数通过地址找到了原件。


2. 用指针交换两个变量(经典案例)

值传递做不到交换,因为交换的是副本。指针传递可以。下面这个例子就像你和小明交换零食:你手里的薯片盒(变量)和小明手里的饼干盒,你们互相交换地址,就能直接换货。

#include <iostream>
using namespace std;

// 指针传递:通过地址交换两个变量的值
void swap(int *a, int *b) {
    int temp = *a;   // *a 就是 a 地址里存的值,即第一个数的原件
    *a = *b;         // 把第二个数的原件放到第一个位置
    *b = temp;       // 把原来第一个数的原件放到第二个位置
    cout << "函数内部:*a = " << *a << ", *b = " << *b << endl;
}

int main() {
    int x = 5, y = 10;                         // x有5块零花钱,y有10块
    cout << "调用前:x = " << x << ", y = " << y << endl;
    swap(&x, &y);   // 把x和y的地址传给函数,就像告诉函数“x在房间101,y在房间102”
    cout << "调用后:x = " << x << ", y = " << y << endl;  // 确实交换了
    return 0;
}

运行结果:

调用前:x = 5, y = 10
函数内部:*a = 10, *b = 5
调用后:x = 10, y = 5

注意:调用时要写成 swap(&x, &y),函数参数声明为 int *a, int *b,函数体内用 *a*b 访问原值。


3. 指针传递 vs 引用传递 vs 值传递

传递方式比喻能否改原变量代码写法
值传递复印一份文件,你改的是复印件不能void func(int a),调用 func(x)
引用传递给文件贴上“共用标签”,你直接改原件void func(int &a),调用 func(x)
指针传递给你文件柜的钥匙,你用钥匙打开柜子改原件void func(int *a),调用 func(&x)

引用传递更直观,但指针更灵活:指针可以指向“空”(用 nullptr 表示不指向任何东西),可以指向数组,还可以通过指针运算访问连续内存(比如数组遍历)。比如你想让一个函数既可能修改原变量,也可能什么都不做(传空指针),引用就做不到,而指针可以:

void maybeModify(int *p) {
    if (p != nullptr) {
        *p = 100;   // 只有在指针有效时才修改
    }
}

4. 新手容易犯的错误

① 忘记解引用

void swap(int *a, int *b) {
    int temp = a;   // 错误!a是指针本身(地址),不是值
    a = b;          // 这只会交换指针的副本,原变量纹丝不动
    b = temp;
}

正确写法必须用 *a 拿到值。

② 使用未初始化的指针(野指针)

int *p;          // p没有指向任何有效地址,里面是垃圾值
*p = 10;        // 危险!可能写坏其他内存,导致程序崩溃

正确做法:要么让它指向一个变量,要么初始化为 nullptr

③ 访问空指针(解引用 nullptr)

int *p = nullptr;
*p = 5;        // 错误!不能对空指针解引用,程序会崩溃

调用函数前一定要检查指针是否为空,例如 if (p != nullptr) { ... }

④ 传入错误的地址类型

double pi = 3.14;
int *p = &pi;    // 错误!int* 不能指向 double 变量

指针类型必须匹配所指向变量的类型。


5. 完整可运行的示例:用指针计算数组元素和

指针另一个大用途是操作数组。数组名本身就是一个指针(指向第一个元素)。下面例子展示了如何用指针遍历数组求和,就像你有一排抽屉,钥匙(指针)从第一个抽屉开始,每开一个抽屉就累加里面的硬币。

#include <iostream>
using namespace std;

// 计算整型数组中所有元素的和,参数:数组指针 和 元素个数
int arraySum(int *arr, int size) {
    int total = 0;          // 总和初始0
    for (int i = 0; i < size; i++) {
        total += *(arr + i);  // arr+i 是第i个元素的地址,*解引用得到值
    }
    return total;
}

int main() {
    int scores[5] = {85, 92, 78, 88, 95};    // 5个同学的考试分数
    int len = 5;                              // 数组长度

    int sum = arraySum(scores, len);          // 数组名scores就是首地址
    cout << "这组分数的总和是:" << sum << endl;
    cout << "平均分是:" << sum / len << endl;
    return 0;
}

运行结果:

这组分数的总和是:438
平均分是:87

注意:scores 作为参数传给 arraySum 时,会自动退化为指向第一个元素的指针,所以 int *arr 接收它。这里 *(arr + i) 等价于 arr[i],两种写法都行。


6. 总结与相关指引

  • 指针传递 就像给了函数一把“万能钥匙”,函数能直接钻进内存改数据,非常强大。
  • 使用时牢记三点:声明 int *p、取地址 &x、解引用 *p
  • 小心空指针和野指针,使用前一定要检查是否为 nullptr
  • 指针也常用于动态内存分配(new / delete)、函数指针、链表等高级话题。

想进一步学习,可以看看:

  • 指针与数组:如何用指针遍历数组,指针的加减运算。
  • 动态内存分配:用 new 在堆上申请内存,用 delete 释放。
  • 引用传递:另一种修改原变量的方式,写法更简洁,但不如指针灵活。
  • const 指针:防止指针意外修改数据,例如 const int *pint * const p

掌握了指针,你就拿到了C++内存世界的钥匙,可以玩出更多花样!

例题精讲

1单选题

下列哪个选项正确描述了C++中指针传递的作用?

A允许函数修改实参的值
B允许函数修改形参的地址
C允许函数修改函数内部的局部变量
D允许函数修改常量
2判断题

在C++中,使用指针作为函数参数时,函数内部对指针本身进行修改(如改变指针指向的地址)不会影响实参指针的值。

3单选题

有如下函数定义:void func(int *p) { *p = 20; p = nullptr; } 执行以下代码后,a的值是多少?int a = 10; int *ptr = &a; func(ptr); cout << a;

A10
B20
C0
D不确定
4填空题
请补全以下函数,使用指针传递交换两个整数的值。
void swap(int *a, int *b) {
    ___ 
}
5判断题

在C++中,如果将指针作为参数传递给函数,并在函数内部使用new为该指针分配动态内存,则函数返回后,实参指针将指向新分配的内存。