wow7jiao 发表于 2018-7-10 21:26:52

请老师指点,递归函数的变量用不用考虑作用域

本帖最后由 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



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

人造人 发表于 2018-7-10 22:14:04

wow7jiao 发表于 2018-7-10 22:33:27

人造人 发表于 2018-7-10 22:14


老师,我再想想

wow7jiao 发表于 2018-7-10 22:37:28

人造人 发表于 2018-7-10 22:14


老师,32位汇编不用考虑ds寄存器段地址吧,sp,bp直接可以全内存指向

人造人 发表于 2018-7-10 22:40:38

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

一般不需要
你现在就认为不需要就可以了
当你认为需要的时候,相信你已经在一个很高的高度了,那时你会有你自己的见解
^_^

关键是感觉 发表于 2018-7-11 02:46:31

这题目好玩,练习ing
#include <stdio.h>
//5 4 3 2 1 0 0 0 1 2 3 4
void print(int n){
        if(n>0){
                printf("%d ",n);
                print(--n);
        }else{
                printf("%d ",n);
        }
        printf("%d ",n);
}
int main(){   
        print(5);
        return 0;
}


搞定了。。
但是看见你一句:结论就是递归函数里的变量当静态局部变量
你这意思是如果咱们写死递归,溢出的原因一定是 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个字节。



啦啦啦看不懂这个反汇编

人造人 发表于 2018-7-11 13:46:38

本帖最后由 人造人 于 2018-7-11 13:48 编辑

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

void Test(int n)
{
        if(n)
                Test(n - 1);

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

int main(void)
{
        Test(5);
        return 0;
}


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

        static int a = 0;
        ++a;
00C84723 A1 3C A1 C8 00       mov         eax,dword ptr
00C84728 83 C0 01             add         eax,1
00C8472B A3 3C A1 C8 00       mov         dword ptr ,eax
        printf("%p -> %d\n", &a, a);
00C84730 A1 3C A1 C8 00       mov         eax,dword ptr
00C84735 50                   push      eax
00C84736 68 3C A1 C8 00       push      offset a (0C8A13Ch)
00C8473B 68 F0 7B C8 00       push      offset string "%p -> %d\n" (0C87BF0h)
00C84740 E8 EF CB FF FF       call      _printf (0C81334h)
00C84745 83 C4 0C             add         esp,0Ch
}
00C84748 5F                   pop         edi
00C84749 5E                   pop         esi
00C8474A 5B                   pop         ebx
00C8474B 81 C4 C0 00 00 00    add         esp,0C0h
00C84751 3B EC                cmp         ebp,esp
00C84753 E8 D4 C9 FF FF       call      __RTC_CheckEsp (0C8112Ch)
00C84758 8B E5                mov         esp,ebp
00C8475A 5D                   pop         ebp
00C8475B C3                   ret


int main(void)
{
00C81790 55                   push      ebp
00C81791 8B EC                mov         ebp,esp
00C81793 81 EC C0 00 00 00    sub         esp,0C0h
00C81799 53                   push      ebx
00C8179A 56                   push      esi
00C8179B 57                   push      edi
00C8179C 8D BD 40 FF FF FF    lea         edi,
00C817A2 B9 30 00 00 00       mov         ecx,30h
00C817A7 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
00C817AC F3 AB                rep stos    dword ptr es:
        Test(5);
00C817AE 6A 05                push      5
00C817B0 E8 DE FB FF FF       call      _Test (0C81393h)
00C817B5 83 C4 04             add         esp,4
        return 0;
00C817B8 33 C0                xor         eax,eax
}
00C817BA 5F                   pop         edi
00C817BB 5E                   pop         esi
00C817BC 5B                   pop         ebx
00C817BD 81 C4 C0 00 00 00    add         esp,0C0h
00C817C3 3B EC                cmp         ebp,esp
00C817C5 E8 62 F9 FF FF       call      __RTC_CheckEsp (0C8112Ch)
00C817CA 8B E5                mov         esp,ebp
00C817CC 5D                   pop         ebp
00C817CD C3                   ret



#include <stdio.h>

void Test(int n)
{
        if(n)
                Test(n - 1);

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

int main(void)
{
        Test(5);
        return 0;
}


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

        int a = 0;
013D4723 C7 45 F8 00 00 00 00 mov         dword ptr ,0
        ++a;
013D472A 8B 45 F8             mov         eax,dword ptr
013D472D 83 C0 01             add         eax,1
013D4730 89 45 F8             mov         dword ptr ,eax
        printf("%p -> %d\n", &a, a);
013D4733 8B 45 F8             mov         eax,dword ptr
013D4736 50                   push      eax
013D4737 8D 4D F8             lea         ecx,
013D473A 51                   push      ecx
013D473B 68 F0 7B 3D 01       push      offset string "%p -> %d\n" (013D7BF0h)
013D4740 E8 EF CB FF FF       call      _printf (013D1334h)
013D4745 83 C4 0C             add         esp,0Ch
}
013D4748 52                   push      edx
}
013D4749 8B CD                mov         ecx,ebp
013D474B 50                   push      eax
013D474C 8D 15 70 47 3D 01    lea         edx,ds:
013D4752 E8 15 CB FF FF       call      @_RTC_CheckStackVars@8 (013D126Ch)
013D4757 58                   pop         eax
013D4758 5A                   pop         edx
013D4759 5F                   pop         edi
013D475A 5E                   pop         esi
013D475B 5B                   pop         ebx
013D475C 81 C4 CC 00 00 00    add         esp,0CCh
013D4762 3B EC                cmp         ebp,esp
013D4764 E8 C3 C9 FF FF       call      __RTC_CheckEsp (013D112Ch)
013D4769 8B E5                mov         esp,ebp
013D476B 5D                   pop         ebp
013D476C C3                   ret


int main(void)
{
013D1790 55                   push      ebp
013D1791 8B EC                mov         ebp,esp
013D1793 81 EC C0 00 00 00    sub         esp,0C0h
013D1799 53                   push      ebx
013D179A 56                   push      esi
013D179B 57                   push      edi
013D179C 8D BD 40 FF FF FF    lea         edi,
013D17A2 B9 30 00 00 00       mov         ecx,30h
013D17A7 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
013D17AC F3 AB                rep stos    dword ptr es:
        Test(5);
013D17AE 6A 05                push      5
013D17B0 E8 DE FB FF FF       call      _Test (013D1393h)
013D17B5 83 C4 04             add         esp,4
        return 0;
013D17B8 33 C0                xor         eax,eax
}
013D17BA 5F                   pop         edi
013D17BB 5E                   pop         esi
013D17BC 5B                   pop         ebx
013D17BD 81 C4 C0 00 00 00    add         esp,0C0h
013D17C3 3B EC                cmp         ebp,esp
013D17C5 E8 62 F9 FF FF       call      __RTC_CheckEsp (013D112Ch)
013D17CA 8B E5                mov         esp,ebp
013D17CC 5D                   pop         ebp
013D17CD C3                   ret

人造人 发表于 2018-7-11 13:50:44

去掉了"显示符号名"

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

        static int a = 0;
        ++a;
000D4723 A1 3C A1 0D 00       mov         eax,dword ptr ds:
000D4728 83 C0 01             add         eax,1
000D472B A3 3C A1 0D 00       mov         dword ptr ds:,eax
        printf("%p -> %d\n", &a, a);
000D4730 A1 3C A1 0D 00       mov         eax,dword ptr ds:
000D4735 50                   push      eax
000D4736 68 3C A1 0D 00       push      0DA13Ch
000D473B 68 F0 7B 0D 00       push      0D7BF0h
000D4740 E8 EF CB FF FF       call      000D1334
000D4745 83 C4 0C             add         esp,0Ch

wow7jiao 发表于 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;
}



地址是对称的,值不对称
页: [1]
查看完整版本: 请老师指点,递归函数的变量用不用考虑作用域