C/C++ 传递指针给函数完整教程

C/C++ 传递指针给函数完整教程

一、核心概念

  1. 普通传值:函数接收变量副本,函数内修改不影响外部原变量。
  2. 传指针(地址传递) :函数接收变量内存地址,通过地址可以修改外部原始变量,也能高效传递数组/大结构体(不用拷贝大量数据)。

二、语法规则

1. 函数形参声明指针

c 复制代码
// 形参是int指针
void func(int *p);

2. 调用时传入变量地址 &变量

c 复制代码
int a = 10;
func(&a); // &a 取出a的地址,传给指针形参p

3. 函数内部解引用 *p 操作原变量

*p 代表指针指向的内存数据(原变量)。


三、示例1:传指针修改外部变量(最常用)

C 代码

c 复制代码
#include <stdio.h>

// 接收int指针
void change(int *num) {
    // *num 等价于外部变量a
    *num = 100; 
}

int main() {
    int a = 10;
    printf("修改前:%d\n", a);
    
    // 传递a的地址
    change(&a);
    
    printf("修改后:%d\n", a);
    return 0;
}

输出:

复制代码
修改前:10
修改后:100

对比:如果不传指针、只传值,外部 a 不会变。


四、示例2:传递数组(数组名本质是首元素指针)

数组传给函数会自动退化为指针,无需加 &

c 复制代码
#include <stdio.h>

// 数组等价于 int arr[] = int *arr
void printArr(int *arr, int len) {
    for(int i = 0; i < len; i++) {
        printf("%d ", arr[i]); // arr[i] 等价于 *(arr+i)
    }
}

int main() {
    int nums[] = {1,2,3,4,5};
    int n = sizeof(nums)/sizeof(nums[0]);
    printArr(nums, n); // 直接传数组名,就是首地址
    return 0;
}

五、示例3:传递指针变量(指针本身作为实参)

如果已有指针变量,调用时直接传指针变量,不用再加 &

c 复制代码
#include <stdio.h>

void setVal(int *p) {
    *p = 666;
}

int main() {
    int x = 10;
    int *p = &x; // p是指针,存x地址
    
    setVal(p); // 直接传指针p,不用&p
    printf("%d", x); // 666
    return 0;
}

区分易错点

  • &x:变量x的地址(int* 类型)
  • p:指针变量本身,值就是 &x
  • &p:指针变量p自己的地址(int** 二级指针)

六、二级指针:传递指针,修改指针本身

需求:函数内让外部指针指向新变量,需要传指针的指针 int**

c 复制代码
#include <stdio.h>

// 二级指针:修改外部一级指针p
void pointNew(int **pp) {
    static int b = 999;
    *pp = &b; // 修改外部指针的指向
}

int main() {
    int a = 10;
    int *p = &a;
    printf("原指向:%d\n", *p); // 10
    
    pointNew(&p); // 传指针p的地址,二级指针
    printf("新指向:%d\n", *p); // 999
    return 0;
}

七、C++ 引用 vs 指针传参(对比)

  1. 指针传参:void f(int *p) f(&a)
  2. 引用传参(C++专属):void f(int &r) f(a),底层仍是地址,语法更简洁。
cpp 复制代码
#include <iostream>
using namespace std;

void f(int &r) {
    r = 200;
}

int main() {
    int a = 10;
    f(a); // 不用取地址
    cout << a;
    return 0;
}

八、常见坑

  1. 野指针 :函数接收指针前判断是否为 NULL

    c 复制代码
    void func(int *p) {
        if(p == NULL) return; // 空指针保护
        *p = 10;
    }
  2. 不要返回局部变量地址(局部变量函数结束销毁)

  3. 数组传指针后丢失长度,必须额外传长度参数

九、总结

  1. 普通变量传指针:实参写 &变量,形参 类型 *p*p 修改原值;
  2. 数组传参:直接传数组名,自动转为首元素指针;
  3. 要修改外部指针本身:使用二级指针 类型 **pp,实参传 &指针变量
  4. 优势:避免大数据拷贝、跨函数修改变量。