关于在函数内实现互换值的问题解析

对于初学者来说,对指针的理解有些困难,呵呵,那么就以群中一个初学者提出的问题进行解答,希望对大家有所帮助。

说起指针,就不得不提内存,把指针与内存结合起来,才可以真正理解指针的本质。

代码就不在这里贴了,我用VC6建了一个工程,把相关的代码贴在工程中,大家可以从后面的网址中下载这个附件(http://d.1tpan.com/tp1297298259
),看看代码。

讲个概念,指针其实就是一个内存地址,指针也是一个变量,他里面存的数值就是内存地址。

我们可以简单的理解,所有我们的程序,包括程序(函数),变量都是放在内存中的,那么,所有的程序(函数),变量在内存中就有一个地址,如果大家用心可以用到函数指针,这个函数指针指的就是函数的地址。

如果我们定义一个变量,静态变量,全局变量,局部变量,不讲那么细,只概要的说,如下

int a = 10;  

那么在这个变量所在的程序被运行时,变量 a 就会有一个对应的内存地址,在现在我们使用的系统中(windows,linux),因为大部分还是32位的系统,所以我们可以用一个32位的二进制数来表示地址,因为4个二进制数可能用一个16进制数来表达,所以一般我们用8个16进制数来表示内存地址,如 0x12345678。

仅以说明问题为标准,我们抛弃windows,linux系统对内存管理的不同,我们举简单的例子。

因为变量a占用的内存地址是 4 个字节,那么假设存放变量 a 的开始内存地址是 0x10000000,那么a所占的内存地址是

0x10000000

0x10000001

0x10000002

0x10000003

同时,首地址0x10000000就是变量a的地址。这块内存中的内容是值 10。

我们定义指针变量

int *p = &a;

变量p是一个指针变量,他也是一个变量,呵呵,他也要在内存中占据一定的位置,我们假设他所占的内存地址是

0x10000004

0x10000005

0x10000006

0x10000007

同时,首地址0x10000004也是变量p的地址。那么以0x10000004 开头的内存中存放的什么内容呢,就是变量a的地址值 0x10000000,

再往下类推下去,

int **q = &p;

这个我就不推了,反正知道q也是变量,他也要占据一块内存,他里面的内容是变量p的地址值0x10000004

好了,上面讲了那么多,我们试着用这种方法来解答程序中的问题。

//不能完成互换功能
void huhuan_1(int a, int b)
{
 int t;

 t = a;
 a = b;
 b = t;

 return;
}

为什么这个函数不能完成a,b值的互换功能。

我们一般是用下面的方式调用的

 int a1 = 3;
 int b1 = 5;
 
 huhuan_1(a1, b1);

从内存的角度来分析,假设变量a1占的内存地址是

0x10000000

0x10000001

0x10000002

0x10000003

这块内存中存放的值是数字3,

假设变量b1占的内存地址是

0x10000004

0x10000005

0x10000006

0x10000007

这块内存中存放的值是数字5,

同时我们还要知道,函数huhuan_1在调用时,系统会给函数的两个参数a,b分配临时的内存,这块内存会在函数huhuan_1调用完成后由系统回收(内存是在栈上分配的,有兴趣的可以查查)。

假设两个参数a,b分配的临时内存地址为

a的临时内存地址为:

0x20000000

0x20000001

0x20000002

0x20000003

因为我们调用时,把a1的值赋给了a,所以这块内存中的内容就是3。

同时,b的临时内存地址为

0x20000004

0x20000005

0x20000006

0x20000007

因为我们调用时,把b1的值赋给了b,所以这块内存中的内容就是5。

函数中完成了a,b内容的互换,也就是说把0x20000000至0x20000003中的内容换成了5,0x20000004 至 0x20000007中的内容换成了3。然后函数huhuan_1执行完成,a,b的内存被系统回收,此时我们再看变量a1,b1的内容被互换了吗,也就是说0x20000000 至 0x20000003的内容与0x20000004至0x20000007的内容被互换了吗,显然没有。

所以,函数huhuan_1不可能完成值的互换。

用此方法再分析函数huhuan_2

//不能完成互换功能
void huhuan_2(int * p, int * q)
{
 int *t;//如果要互换p和q的值,则t必须是int *,不能是int,否则会出错

 t = p;
 p = q;
 q = t;
}

我们用下面的方式调用

 int a1 = 3;
 int b1 = 5;

huhuan_2(&a1, &b1);

a1,b1分配的内存地址参考函数huhuan_1中的说明。

同函数huhuan_2在调用时,系统会给函数的两个指针参数p,q分配临时的内存,这块内存会在函数huhuan_2调用完成后由系统回收(内存是在栈上分配的,有兴趣的可以查查)。

假设两个参数p,q分配的临时内存地址为

p的临时内存地址为:

0x20000000

0x20000001

0x20000002

0x20000003

因为我们调用时,把a1的地址赋给了p,所以这块内存中的内容就是a1的地址 0x1000000。

同时,q的临时内存地址为

0x20000004

0x20000005

0x20000006

0x20000007

因为我们调用时,把b1的地址赋给了q,所以这块内存中的内容就是b1的地址 0x1000004。

函数中完成了p,q内容的互换,也就是说把0x20000000至0x20000003中的内容换成了b1的地址0x1000004,0x20000004 至 0x20000007中的内容换成了a1的地址0x1000000。然后函数huhuan_2执行完成,p,q的内存被系统回收,此时我们再看变量a1,b1的内容被互换了吗,也就是说0x20000000 至 0x20000003的内容与0x20000004至0x20000007的内容被互换了吗,显然没有。

所以,函数huhuan_2不可能完成值的互换。

 

用此方法再分析函数huhuan_3

//可以完成互换功能
void huhuan_3(int * p, int * q)
{
 int t; //如果要互换*p和*q的值, 则t必须定义成int,不能定义成int *, 否则语法出错

 t = *p;  //p是int *,  *p是int
 *p = *q;
 *q = t;
}

我们用下面的方式调用

 int a1 = 3;
 int b1 = 5;

huhuan_3(&a1, &b1);

a1,b1分配的内存地址参考函数huhuan_1中的说明。

同函数huhuan_1在调用时,系统会给函数的两个指针参数p,q分配临时的内存,这块内存会在函数huhuan_3调用完成后由系统回收(内存是在栈上分配的,有兴趣的可以查查)。

假设两个参数p,q分配的临时内存地址为

p的临时内存地址为:

0x20000000

0x20000001

0x20000002

0x20000003

因为我们调用时,把a1的地址赋给了p,所以这块内存中的内容就是a1的地址 0x1000000。

同时,q的临时内存地址为

0x20000004

0x20000005

0x20000006

0x20000007

因为我们调用时,把b1的地址赋给了q,所以这块内存中的内容就是b1的地址 0x1000004。

需要特别说明下,*p的意义是取p内存中的内容也就是首地址0x20000000中的内容 0x10000000,

p 是一个指针,它是一个指针变量,他的内存地址是0x20000000,

而内存地址0x20000000中放的内容是一个地址值,这个值是0x10000000,也就是变量a1的地址。

所以*p取的是地址0x10000000中的值,也就是变量a1的地址中的值,也就是3。

 

函数中完成了p,q所指向的地址中的值的互换,也就是说把0x10000000至0x10000003中的内容与0x10000004至0x10000007中的内容互换了。

就是说0x10000000至0x10000003中的内容变成了5,0x10000004至0x10000007中的内容变成了3.

然后函数huhuan_3执行完成,p,q的内存被系统回收,此时我们再看变量a1,b1的内容被互换了吗,也就是说0x20000000 至 0x20000003的内容与0x20000004至0x20000007的内容被互换了吗,显然完成了互换。

所以,函数huhuan_3完成了值的互换。

如果细心看完,呵呵,再仔细结合内存分析,就好理解了。

mail:sulongvc@163.com

QQ:361541630

有什么问题可以问我。

本来想弄个图出来的,因为时间晚了,所以,以后再整理吧。

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值