函数调用参数为指针时,实参跟形参的问题

本文通过代码示例探讨了在C语言中,当函数调用参数为指针时,实参和形参之间的关系。实验证明,形参对指针变量值的修改不会影响实参,但对指针所指向的变量的值的修改会反映到实参。当形参为`const int *`时,禁止修改所指向的变量值,但仍然可以改变指针本身的指向。
#include<stdio.h>

void change(int *p){
    int val = 5;
    printf("%p\n", p);
    *p = val;
    printf("%p\n", p);
    p = &val;
    printf("%p\n", p);
}

int main(){
    int val = 4;
    int *p = &val;
    change(p);
    printf("%d\n", *p);
    printf("%p\n", p);
    return 0;
}

运行结果:
0x7fffdb8192a4
0x7fffdb8192a4
0x7fffdb81928c
5
0x7fffdb8192a4

可以看出,实参跟形参是两个不同的指针,只不过进入函数时,实参跟形参都指向main函数中的val地址,
当改变形参指向的变量的值时,*p = val; main函数中的val被改变;
但是改变形参的指向地址时,p = &val; 只是改变了形参的指向,并没有改变实参的指向;

当加上const之后:
void change(const int *p){
    int val = 5;
    printf("%p\n", p);
    /**p = val;
    printf("%p\n", p);*/  //去掉注释将发生read-only错误
    p = &val;
    printf("%p\n", p);
}

运行结果:
0x7fff85402a94
0x7fff85402a7c
4
0x7fff85402a94

可以看出加上const之后,不能改变形参所指向的变量的值,但是可以改变形参的指向;
其实加上const就是说实参所指向的变量的值是只读的,形参不能改变;
<think>嗯,用户想了解函数调用实参形参的赋值关系,以及实参如何赋值给形参。那我得先回忆一下相关知识,并结合提供的引用内容来组织答案。 首先,根据引用[1],形参是函数声明的变量,实参是调用传递的实际值。关键点在于数量必须匹配,否则会出错。然后引用[2]提到,当形参实参不是指针类型形参实参的副本,位于不同内存位置,修改形参影响实参。这解释了传值调用的机制。 接下来,引用[3]的例子展示了传值和传地址的区别。当传递变量地址,通过指针可以修改实参的值,而传值则不行。这涉及到按引用传递或按指针传递的概念。 所以,我需要分步骤解释赋值关系:首先说明形参实参的基本概念,然后讨论不同的传递方式(传值、传指针、传引用),并比较它们的区别。还需要提到不同编程语言中的差异,比如C语言中的指针和C++中的引用,或者Python中的可变与不可变对象的影响。 另外,用户可能对底层机制感兴趣,比如栈内存的操作和拷贝过程。需要解释为什么传值形参的改变不影响实参,而传地址影响。同,可能需要提到性能问题,比如大对象传值会导致栈溢出,这候应该用指针或引用。 还要注意用户提到的“赋值关系”可能是指参数传递的具体过程,比如是复制值还是传递地址。需要明确不同传递方式下的赋值机制。 最后,生成的相关问题需要围绕参数传递方式、语言差异、内存影响等方面展开,帮助用户深入理解。</think>### 函数调用实参形参的赋值关系分析 #### 1. 基本概念 - **形参**(形式参数):函数声明定义的变量,如$f(int\ x)$中的$x$[^1] - **实参**(实际参数):函数调用传递的具体数值或变量,如$f(5)$中的$5$[^1] #### 2. 赋值过程解析 1. **传值调用(值传递)** - 形参接收实参值的副本 - 内存中创建新的独立变量 - 示例: ```c void modify(int a) { a = 10; } int main() { int x = 5; modify(x); // x仍保持5 } ``` - 特点:修改形参影响实参[^2] 2. **传地址调用(指针传递)** - 形参接收变量的内存地址 - 通过指针间接操作实参 - 示例: ```c void swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } ``` 3. **引用传递(C++等语言特有)** - 形参作为实参的别名存在 - 修改形参直接影响实参 - 示例: ```cpp void increment(int& x) { x++; } ``` #### 3. 不同编程语言对比 | 语言 | 默认传递方式 | 特点说明 | |--------|--------------|------------------------------| | C | 值传递 | 需显式使用指针修改实参 | | C++ | 值传递 | 支持引用类型参数 | | Python | 对象引用 | 可变/不可变对象行为不同 | | Java | 值传递 | 对象传递的是引用的拷贝 | #### 4. 内存模型示意图 $$ \begin{array}{|c|c|} \hline \text{调用前内存} & \text{调用内存} \\ \hline \text{实参}0x1000 & \text{形参}0x2000 \\ \text{值:5} & \text{值:5(副本)} \\ \hline \end{array} $$ #### 5. 参数传递陷阱 - **数组退化**:C语言中数组参数退化为指针 ```c void func(int arr[10]) { // arr实际是指针类型 } ``` - **结构体拷贝**:大结构体传值可能导致性能问题 - **const限定**:保护数据不被意外修改[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值