一、核心原则:C语言的参数传递方式
C语言中函数参数传递始终是值传递——即调用函数时,实参的值会被复制一份份给形参。
- 若修改的是形参本身,不会影响实参(因为操作的是副本)。
- 若通过形参间接操作了实参的内存,则会影响实参(因为操作的是原数据的地址)。
二、不同类型参数的修改效果
数据类型/形式 | 传递本质 | 函数内修改是否影响原数据? | 原理说明 |
---|---|---|---|
基本类型(int、char、float等) | 传递值的副本 | ❌ 不影响 | 形参是实参的“拷贝”,修改形参仅改变副本,与原数据的内存无关。 |
数组(如int[]) | 传递数组首元素的地址(本质是指针) | ✅ 影响 | 形参接收的是原数组的首地址,通过数组下标(如b[0])操作的是原数组的内存单元。 |
指针变量(如int* p) | 传递指针变量存储的地址副本 | ✅ 影响(通过解引用) | 若修改*p (解引用操作),会通过地址修改原数据;若仅修改p 本身(如p++),不影响原指针。 |
结构体(如struct S) | 传递结构体的副本 | ❌ 不影响(除非用指针) | 形参是原结构体的完整拷贝,修改形参不影响原结构体(但拷贝开销大)。 |
结构体指针(如struct S*) | 传递指针存储的地址副本 | ✅ 影响(通过解引用) | 与普通指针类似,(*p).member 或 p->member 会直接修改原结构体。 |
三、关键结论:判断是否影响原数据的依据
是否通过形参直接操作了原数据的内存地址:
若传递的是“数据本身”(如基本类型、结构体):
- 形参是副本,修改形参不影响原数据。
若传递的是“地址”(如数组首地址、指针):
- 通过地址间接访问并修改数据(如
b[0] = 5
、*p = 10
),会影响原数据。 - 仅修改地址变量本身(如
p = &x
、b++
),不影响原数据(因为修改的是地址的副本)。
- 通过地址间接访问并修改数据(如
四、典型示例对比
场景 | 代码示例(函数内操作) | 原数据是否被修改? |
---|---|---|
基本类型修改形参 | void f(int a) { a = 10; } |
❌ 不修改 |
数组修改元素 | void f(int b[]) { b[0] = 10; } |
✅ 修改 |
指针修改解引用值 | void f(int* p) { *p = 10; } |
✅ 修改 |
指针仅修改自身 | void f(int* p) { p++; } |
❌ 不修改 |
结构体修改副本 | void f(Struct s) { s.x = 10; } |
❌ 不修改 |
结构体指针修改成员 | void f(Struct* s) { s->x = 10; } |
✅ 修改 |
总结
- 不影响原数据:传递基本类型、结构体等“数据本身”,仅修改形参副本。
- 影响原数据:传递地址(数组、指针),并通过地址间接修改数据内容。
记住:C语言中“值传递”是根本,“地址”也是一种值,通过地址操作才能触达原数据的内存——这是判断的核心依据。