这段程序的两个值并没有交换,但初学者很容易认为是交换了。
#include<stdio.h> void exchange(int ,int ); void exchange(int one,int another){ int tmp; tmp = one; one = another; another = tmp; } int main(){ int num1; int num2; exchange(num1,num2); printf(“交换后 : %d %d”,num1,num2); return 0; }
从main()函数开始,4字节整型变量num1先进入“堆栈系统”中申请4字节的空间,然后4字节整型变量num2也申请了4字节的空间在num1的上面。
操作系统为了保护主函数的信息,申请了4字节的空间用来保护主函数的”现场信息”。
系统堆栈是由os和计算机指令体系和用户程序共同管理的。
系统堆栈最重要的功能;保证函数的调用与返回的顺序!同时保证了,当函数返回到其主调函数时,能够让主调函数正常被打断的过程,继续执行下去!
当调用exchange()函数时,从左往右,先进入4字节整型形参another,栈顶指针往上移4个字节,然后,4字节整型形参one进入栈中,最后局部变
量tmp进入栈指针向上移4字节。代码只是将num1空间的值和num2空间的值复制一份给one的空间和another的空间,然后将one空间的值,赋值给tmp空间
再将another空间的值,赋值给one空间,最后将tmp空间的值赋值another的空间,但是,实参num1与num2的值根本没有交换!!!
下面代码才是真正实现两个值的交换的代码:
#include <stdio.h> void realExchange(int*,int*); void realExchange(int * one,int *another){ int tmp; tmp = *one; *one = *another; *another = tmp; } int main(){ int num1; int num2; scanf("%d %d",&num1,&num2); exchange(&num1,&num2); printf(“交换后: %d %d”,num1,num2); return 0; }
以上这段代码才是真正的交换num1和num2的值!!!
从main()函数开始,4字节整型变量num1先进入“堆栈系统”中申请4字节的空间,然后4字节整型变量num2也申请了4字节的空间在num1的上面。
操作系统为了保护主函数的信息,申请了4字节的空间用来保护主函数的现场信息。
进入realexchange()函数时,将one所指向的空间也就是num1空间的值,赋值給tmp空间,再将another所指向空间也就是num2空间的值,赋值給one所指向的
空间(num1),最后将tmp空间的值赋值给another所指向的空间(num2),此时,num1的值才与num2的值交换了!
重点是:上面实参表达式计算出来的值,在系统堆栈中所占用的空间,就是与之对应的形参变量的空间!!!!
补充从汇编语言的一点知识:
现场信息: 这是在多线程.多线程环境下才会产生的问题,对于函数调用这样的简单问题,不涉及现场信息。
esp就是系统堆栈栈顶指针;
ebp就是系统堆栈当前栈底指针;
系统堆栈向低端增长,就是说,push(入栈)会--esp; pop(出栈)会++esp;
将ebp值入栈;esp会-4;
将esp的值,赋值给ebp,使得esp和ebp都指向同一个空间(mov ebp,esp);
也就是说,每一个函数都会有自己的一个临时的空栈!
call指令内部会执行push eip操作!!!!保护eip的值,以便返回时能继续执行主调函数的下一条指令!
接着call会执行mov eip,函数名(被调用的),就是子函数的首地址常量。
栈底和第一个局部变量之间存在着一个4B!
就是主函数刚进入的一个int型的全局变量!