鱼C论坛

 找回密码
 立即注册
查看: 2260|回复: 9

[已解决]请老师指点,递归函数的变量用不用考虑作用域

[复制链接]
发表于 2018-7-10 21:26:52 | 显示全部楼层 |阅读模式
10鱼币
本帖最后由 wow7jiao 于 2018-7-10 21:33 编辑

输入5,打印结果:5 4 3 2 1 0 0 0 1 2 3 4

-------------------------------------------------------------------------   
#include <stdio.h>

    void up_and_down(int n);

    void up_and_down(int n)
    {
            printf("%d ", n);<------;例如这里是5
            if (n > 0)
            {
                    up_and_down(--n);<----------这里的--n是不用考虑局部代码块
            }
            printf("%d ", n);<  到这里这条语句,就是n = n -1 = 5 - 1 =4(如果考虑代码块作用域,这里应该还是5,上一个代码块的--n对这里没有影响)
    }

    int main(void)
    {
            int n;

            printf("请输入一个整数:");
            scanf("%d", &n);

            up_and_down(n);
            putchar('\n');

            return 0;
    }

结论就是递归函数里的变量当静态局部变量
最佳答案
2018-7-10 21:26:53
1.png

只要调用一次函数,就会有一个对象生成
可以看到这些变量n的地址不一样,也就是他们是不同的对象,只是名字相同而已

最佳答案

查看完整内容

只要调用一次函数,就会有一个对象生成 可以看到这些变量n的地址不一样,也就是他们是不同的对象,只是名字相同而已
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2018-7-10 21:26:53 | 显示全部楼层    本楼为最佳答案   
1.png

只要调用一次函数,就会有一个对象生成
可以看到这些变量n的地址不一样,也就是他们是不同的对象,只是名字相同而已
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2018-7-10 22:14:04 | 显示全部楼层
1.png
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-7-10 22:33:27 | 显示全部楼层

老师,我再想想
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-7-10 22:37:28 | 显示全部楼层

老师,32位汇编不用考虑ds寄存器段地址吧,sp,bp直接可以全内存指向
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2018-7-10 22:40:38 | 显示全部楼层
wow7jiao 发表于 2018-7-10 22:37
老师,32位汇编不用考虑ds寄存器段地址吧,sp,bp直接可以全内存指向

一般不需要
你现在就认为不需要就可以了
当你认为需要的时候,相信你已经在一个很高的高度了,那时你会有你自己的见解
^_^
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2018-7-11 02:46:31 | 显示全部楼层
这题目好玩,练习ing
  1. #include <stdio.h>
  2. //5 4 3 2 1 0 0 0 1 2 3 4
  3. void print(int n){
  4.         if(n>0){
  5.                 printf("%d ",n);
  6.                 print(--n);
  7.         }else{
  8.                 printf("%d ",n);
  9.         }
  10.         printf("%d ",n);
  11. }
  12. int main(){   
  13.         print(5);
  14.         return 0;
  15. }
复制代码


n2.gif
搞定了。。
但是看见你一句:结论就是递归函数里的变量当静态局部变量
你这意思是如果咱们写死递归,溢出的原因一定是 push print 的值。或者说溢出的原因一定不是由 int n 引起的
我记得没错的话,静态局部变量 == static int ,就算你循环调用 这个变量也不会进行压栈操作
刚看了8086汇编,推测一下反汇编,用了vs2015也没看明白
1.push ebp
2.mob ebp,esp
3.sub esp,8                               
4.push n
5.push print
....
每次调用函数都会执行以上5步,分配8个字节。

静态的话我想应该是这样
1.push ebp
2.mob ebp,esp
3.sub esp,4                       
4.push print
....
每次调用函数都会执行以上4步,分配4个字节。


QQ拼音截图20180711024041.png
啦啦啦看不懂这个反汇编
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2018-7-11 13:46:38 | 显示全部楼层
本帖最后由 人造人 于 2018-7-11 13:48 编辑

那我也来玩玩汇编语言
  1. #include <stdio.h>

  2. void Test(int n)
  3. {
  4.         if(n)
  5.                 Test(n - 1);

  6.         static int a = 0;
  7.         ++a;
  8.         printf("%p -> %d\n", &a, a);
  9. }

  10. int main(void)
  11. {
  12.         Test(5);
  13.         return 0;
  14. }
复制代码

1.png
地址一样,这次这个a是同一个a
  1. void Test(int n)
  2. {
  3. 00C846F0 55                   push        ebp  
  4. 00C846F1 8B EC                mov         ebp,esp  
  5. 00C846F3 81 EC C0 00 00 00    sub         esp,0C0h  
  6. 00C846F9 53                   push        ebx  
  7. 00C846FA 56                   push        esi  
  8. 00C846FB 57                   push        edi  
  9. 00C846FC 8D BD 40 FF FF FF    lea         edi,[ebp-0C0h]  
  10. 00C84702 B9 30 00 00 00       mov         ecx,30h  
  11. 00C84707 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  12. 00C8470C F3 AB                rep stos    dword ptr es:[edi]  
  13.         if(n)
  14. 00C8470E 83 7D 08 00          cmp         dword ptr [n],0  
  15. 00C84712 74 0F                je          Test+33h (0C84723h)  
  16.                 Test(n - 1);
  17. 00C84714 8B 45 08             mov         eax,dword ptr [n]  
  18. 00C84717 83 E8 01             sub         eax,1  
  19. 00C8471A 50                   push        eax  
  20. 00C8471B E8 73 CC FF FF       call        _Test (0C81393h)  
  21. 00C84720 83 C4 04             add         esp,4  

  22.         static int a = 0;
  23.         ++a;
  24. 00C84723 A1 3C A1 C8 00       mov         eax,dword ptr [a (0C8A13Ch)]  
  25. 00C84728 83 C0 01             add         eax,1  
  26. 00C8472B A3 3C A1 C8 00       mov         dword ptr [a (0C8A13Ch)],eax  
  27.         printf("%p -> %d\n", &a, a);
  28. 00C84730 A1 3C A1 C8 00       mov         eax,dword ptr [a (0C8A13Ch)]  
  29. 00C84735 50                   push        eax  
  30. 00C84736 68 3C A1 C8 00       push        offset a (0C8A13Ch)  
  31. 00C8473B 68 F0 7B C8 00       push        offset string "%p -> %d\n" (0C87BF0h)  
  32. 00C84740 E8 EF CB FF FF       call        _printf (0C81334h)  
  33. 00C84745 83 C4 0C             add         esp,0Ch  
  34. }
  35. 00C84748 5F                   pop         edi  
  36. 00C84749 5E                   pop         esi  
  37. 00C8474A 5B                   pop         ebx  
  38. 00C8474B 81 C4 C0 00 00 00    add         esp,0C0h  
  39. 00C84751 3B EC                cmp         ebp,esp  
  40. 00C84753 E8 D4 C9 FF FF       call        __RTC_CheckEsp (0C8112Ch)  
  41. 00C84758 8B E5                mov         esp,ebp  
  42. 00C8475A 5D                   pop         ebp  
  43. 00C8475B C3                   ret  


  44. int main(void)
  45. {
  46. 00C81790 55                   push        ebp  
  47. 00C81791 8B EC                mov         ebp,esp  
  48. 00C81793 81 EC C0 00 00 00    sub         esp,0C0h  
  49. 00C81799 53                   push        ebx  
  50. 00C8179A 56                   push        esi  
  51. 00C8179B 57                   push        edi  
  52. 00C8179C 8D BD 40 FF FF FF    lea         edi,[ebp-0C0h]  
  53. 00C817A2 B9 30 00 00 00       mov         ecx,30h  
  54. 00C817A7 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  55. 00C817AC F3 AB                rep stos    dword ptr es:[edi]  
  56.         Test(5);
  57. 00C817AE 6A 05                push        5  
  58. 00C817B0 E8 DE FB FF FF       call        _Test (0C81393h)  
  59. 00C817B5 83 C4 04             add         esp,4  
  60.         return 0;
  61. 00C817B8 33 C0                xor         eax,eax  
  62. }
  63. 00C817BA 5F                   pop         edi  
  64. 00C817BB 5E                   pop         esi  
  65. 00C817BC 5B                   pop         ebx  
  66. 00C817BD 81 C4 C0 00 00 00    add         esp,0C0h  
  67. 00C817C3 3B EC                cmp         ebp,esp  
  68. 00C817C5 E8 62 F9 FF FF       call        __RTC_CheckEsp (0C8112Ch)  
  69. 00C817CA 8B E5                mov         esp,ebp  
  70. 00C817CC 5D                   pop         ebp  
  71. 00C817CD C3                   ret  
复制代码


  1. #include <stdio.h>

  2. void Test(int n)
  3. {
  4.         if(n)
  5.                 Test(n - 1);

  6.         int a = 0;
  7.         ++a;
  8.         printf("%p -> %d\n", &a, a);
  9. }

  10. int main(void)
  11. {
  12.         Test(5);
  13.         return 0;
  14. }
复制代码

2.png
地址不一样,这些a都是不同的对象,只是名字相同而已
  1. void Test(int n)
  2. {
  3. 013D46F0 55                   push        ebp  
  4. 013D46F1 8B EC                mov         ebp,esp  
  5. 013D46F3 81 EC CC 00 00 00    sub         esp,0CCh  
  6. 013D46F9 53                   push        ebx  
  7. 013D46FA 56                   push        esi  
  8. 013D46FB 57                   push        edi  
  9. 013D46FC 8D BD 34 FF FF FF    lea         edi,[ebp-0CCh]  
  10. 013D4702 B9 33 00 00 00       mov         ecx,33h  
  11. 013D4707 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  12. 013D470C F3 AB                rep stos    dword ptr es:[edi]  
  13.         if(n)
  14. 013D470E 83 7D 08 00          cmp         dword ptr [n],0  
  15. 013D4712 74 0F                je          Test+33h (013D4723h)  
  16.                 Test(n - 1);
  17. 013D4714 8B 45 08             mov         eax,dword ptr [n]  
  18. 013D4717 83 E8 01             sub         eax,1  
  19. 013D471A 50                   push        eax  
  20. 013D471B E8 73 CC FF FF       call        _Test (013D1393h)  
  21. 013D4720 83 C4 04             add         esp,4  

  22.         int a = 0;
  23. 013D4723 C7 45 F8 00 00 00 00 mov         dword ptr [a],0  
  24.         ++a;
  25. 013D472A 8B 45 F8             mov         eax,dword ptr [a]  
  26. 013D472D 83 C0 01             add         eax,1  
  27. 013D4730 89 45 F8             mov         dword ptr [a],eax  
  28.         printf("%p -> %d\n", &a, a);
  29. 013D4733 8B 45 F8             mov         eax,dword ptr [a]  
  30. 013D4736 50                   push        eax  
  31. 013D4737 8D 4D F8             lea         ecx,[a]  
  32. 013D473A 51                   push        ecx  
  33. 013D473B 68 F0 7B 3D 01       push        offset string "%p -> %d\n" (013D7BF0h)  
  34. 013D4740 E8 EF CB FF FF       call        _printf (013D1334h)  
  35. 013D4745 83 C4 0C             add         esp,0Ch  
  36. }
  37. 013D4748 52                   push        edx  
  38. }
  39. 013D4749 8B CD                mov         ecx,ebp  
  40. 013D474B 50                   push        eax  
  41. 013D474C 8D 15 70 47 3D 01    lea         edx,ds:[13D4770h]  
  42. 013D4752 E8 15 CB FF FF       call        @_RTC_CheckStackVars@8 (013D126Ch)  
  43. 013D4757 58                   pop         eax  
  44. 013D4758 5A                   pop         edx  
  45. 013D4759 5F                   pop         edi  
  46. 013D475A 5E                   pop         esi  
  47. 013D475B 5B                   pop         ebx  
  48. 013D475C 81 C4 CC 00 00 00    add         esp,0CCh  
  49. 013D4762 3B EC                cmp         ebp,esp  
  50. 013D4764 E8 C3 C9 FF FF       call        __RTC_CheckEsp (013D112Ch)  
  51. 013D4769 8B E5                mov         esp,ebp  
  52. 013D476B 5D                   pop         ebp  
  53. 013D476C C3                   ret  


  54. int main(void)
  55. {
  56. 013D1790 55                   push        ebp  
  57. 013D1791 8B EC                mov         ebp,esp  
  58. 013D1793 81 EC C0 00 00 00    sub         esp,0C0h  
  59. 013D1799 53                   push        ebx  
  60. 013D179A 56                   push        esi  
  61. 013D179B 57                   push        edi  
  62. 013D179C 8D BD 40 FF FF FF    lea         edi,[ebp-0C0h]  
  63. 013D17A2 B9 30 00 00 00       mov         ecx,30h  
  64. 013D17A7 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  65. 013D17AC F3 AB                rep stos    dword ptr es:[edi]  
  66.         Test(5);
  67. 013D17AE 6A 05                push        5  
  68. 013D17B0 E8 DE FB FF FF       call        _Test (013D1393h)  
  69. 013D17B5 83 C4 04             add         esp,4  
  70.         return 0;
  71. 013D17B8 33 C0                xor         eax,eax  
  72. }
  73. 013D17BA 5F                   pop         edi  
  74. 013D17BB 5E                   pop         esi  
  75. 013D17BC 5B                   pop         ebx  
  76. 013D17BD 81 C4 C0 00 00 00    add         esp,0C0h  
  77. 013D17C3 3B EC                cmp         ebp,esp  
  78. 013D17C5 E8 62 F9 FF FF       call        __RTC_CheckEsp (013D112Ch)  
  79. 013D17CA 8B E5                mov         esp,ebp  
  80. 013D17CC 5D                   pop         ebp  
  81. 013D17CD C3                   ret  
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2018-7-11 13:50:44 | 显示全部楼层
去掉了"显示符号名"

  1.         int a = 0;
  2. 013D4723 C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0  
  3.         ++a;
  4. 013D472A 8B 45 F8             mov         eax,dword ptr [ebp-8]  
  5. 013D472D 83 C0 01             add         eax,1  
  6. 013D4730 89 45 F8             mov         dword ptr [ebp-8],eax  
  7.         printf("%p -> %d\n", &a, a);
  8. 013D4733 8B 45 F8             mov         eax,dword ptr [ebp-8]  
  9. 013D4736 50                   push        eax  
  10. 013D4737 8D 4D F8             lea         ecx,[ebp-8]  
  11. 013D473A 51                   push        ecx  
  12. 013D473B 68 F0 7B 3D 01       push        13D7BF0h  
  13. 013D4740 E8 EF CB FF FF       call        013D1334  
  14. 013D4745 83 C4 0C             add         esp,0Ch  
复制代码

  1.         static int a = 0;
  2.         ++a;
  3. 000D4723 A1 3C A1 0D 00       mov         eax,dword ptr ds:[000DA13Ch]  
  4. 000D4728 83 C0 01             add         eax,1  
  5. 000D472B A3 3C A1 0D 00       mov         dword ptr ds:[000DA13Ch],eax  
  6.         printf("%p -> %d\n", &a, a);
  7. 000D4730 A1 3C A1 0D 00       mov         eax,dword ptr ds:[000DA13Ch]  
  8. 000D4735 50                   push        eax  
  9. 000D4736 68 3C A1 0D 00       push        0DA13Ch  
  10. 000D473B 68 F0 7B 0D 00       push        0D7BF0h  
  11. 000D4740 E8 EF CB FF FF       call        000D1334  
  12. 000D4745 83 C4 0C             add         esp,0Ch  
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-7-11 15:18:26 | 显示全部楼层
本帖最后由 wow7jiao 于 2018-7-11 15:21 编辑

#include <stdio.h>

//5 4 3 2 1 0 0 0 1 2 3 4

void up_and_down(int n);

void up_and_down(int n)
{
                printf("%p -> %d\n", &n, n);
               
               
                if(n > 0)
                {
                                up_and_down(--n);
                               
                }
                printf("%p -> %d\n", &n, n);
}


int main(void)
{
                int n;
               
                printf("请输入一个整数");
                scanf("%d", &n);
               
                up_and_down(n);
                putchar("\n");
               
                return 0;
}



地址是对称的,值不对称
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-9 18:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表