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


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

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

     

  • 相关阅读:
    [论文阅读] Look Closer to Supervise Better: OneShot Font Generation via ComponentBased Discriminator
    Master笔记 22711 @GANs N' Roses@GAN指标
    [vite]使用pnpm创建vite+vue3项目
    set,Map 和 数组的扩展方法
    ES6 中的导包
    ES6 中的类
    Symbol 类型
    ES6 中的迭代器和生成器
    ES6 中的对象
    基础语法
  • 原文地址:https://www.cnblogs.com/youdiaodaxue16/p/8822676.html
Copyright © 2020-2023  润新知