如何用函数实现两个数之间的交换(系统堆栈以及补充的汇编语言的一点知识)

这段程序的两个值并没有交换,但初学者很容易认为是交换了。

#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型的全局变量!