问题描述:使用指针通过函数改变函数调用处本地局部变量的值。
解题思路:
1.在main()函数内部定义一个局部变量并赋给其初值;
2.输出该局部变量的值,便于与后面的输出进行比较;
3.定义一个函数func()用于实现更改局部变量的值,为了能够在func()函数中改变局部变量的值,应该告诉函数该局部变量的地址,于是用 “&局部变量名” 作为函数的实参;
4.输出更改之后的结果,自行比较。
完整代码:
/*问题:使用指针通过函数改变函数调用处本地局部变量的值
Written by : Jimmy Tung
Date :2020.04.08
*/
#include <stdio.h>
#include <stdlib.h>
void func( int * ); //改变本地局部变量的值
int main(void)
{
int i;
i = 520;
printf("更改前i = %d\n", i); //输出更改之前的值
func( &i );
printf("更改后i = %d\n", i); //输出更改之后的值
system("PAUSE");
return 0;
}
void func( int *ptr_i)
{
*ptr_i = 3344;
}
结果如下:
更改前i = 520
更改后i = 3344
请按任意键继续. . .
Process returned 0 (0x0) execution time : 7.259 s
Press any key to continue.
要点复盘:
- 一元运算符“&”的作用:
由代码可以知道,&i 这个表达式是一个指针类型的量,因为在func()函数中,形参的类型是“int *”型,C中要求实参与形参的类型要一致,故 &i 是一个 int *类型的指针。从这里可以看出,一元运算符“&”的作用是求一个指向i这个内存区域(i的左值含义)的指针。
这里自然而然要提到一个问题,那么既然&i是一个指针类型的量,那它是变量还是常量呢?
它是一个常量,准确来说,它是一个int *类型的指针常量。这是因为&i既不能通过代码赋值,也不能通过代码而被改变,在编译器编译之前,我们不可能知道编译器会把哪一部分内存区域分配给局部变量i,因而是一个常量(可以测试一下)。
2.func()函数的实现
func()函数从主函数中获得指向了局部变量i的指针常量&i,因而只要对&i进行求内存运算就可以找到局部变量i的内存地址,对其进行更改操作。对这个函数进行分析,大致可以知道其主要完成了三件事情:
(1)从主调函数那里接收了指针变量&i并存储起来;
(2)根据&i求出局部变量i的内存地址;
(3)修改局部变量的值。
我们仔细对(1)这件事情进行剖析,即对下面这个语句(函数调用语句)进行分析:
func( &i );
首先计算&i的值。这一步是由机器完成的,以下用我的机器显示一下实参的值为,可以看出这是一个内存单元的编号,也就是说&i这个指针常量的值是一个内存单元编号。
&i = 0028FF1C
请按任意键继续. . .
把计算得到的实参的值赋给形参作为初值,也就是以下操作:
ptr_i = &i;
此时,ptr_i这个指针的含义是指向局部变量i(左值)的指针,这块内存区域的大小为sizeof(int)。这个指针的值(右值)就是0x0028FF1C,即局部变量i占有的的第一个内存单元的编号。到此,第(1)件事情做完了。
第(2)件事情是本函数的关键,因为其用实参和形参类型提供的信息求出了局部变量的内存地址,这样才能对局部变量进行修改。这件事情是由一元运算符“ * ”实现的,这个运算符的运算对象是指针,运算结果是指针所指向的那块内存(左值)或者是那块内存中所存放的值(右值)。故 *ptr_i有两个含义,这是C中的一大特点——一词多义。
从本例题可以总结出,&运算符是用左值表达式(内存)计算出指针,而 *运算符是用指针计算出内存。两个运算符互为逆运算符(referencing and dereferencing operator)。
第(3)件事就非常简单了,用以下语句就可以实现。
*ptr_i = 3344;
从对第(2)件事的分析和代码,ptr_i其实就是(&i),而*和&互逆,于是我们很容易得到 *(&i)就是局部变量i。