• 【0007】函数


    函数的结构

    #include <stdio.h>
    
    // 函数的别称是方法,函数是完成某一特定功能的模块
    void print()        // 自定义函数
    {
        printf("锄禾日当午 
    ");        // printf是系统函数
        /*
            函数名            printf
            函数的参数        "锄禾日当午 
    "
            ()                紧挨着函数名之后,包含参数
        */
    
        getchar();        // 等待输入一个字符
    }
    
    void printadd(int a, int b)
    {
        printf("a+b=%d", a+b);    // 将a+b的值转换为字符串,映射到字符串“a+b=%d”
    }
    
    // 函数就是加工厂,给你输入,你给我输出;但是函数的输入与输出可以为空
    
    void main1()        //C程序的入口,有且仅有一个main函数
    {
        //print();                    // 自定义函数
        //printf("锄禾日当午 
    ");        // printf是系统函数
        printadd(4, 8);
        getchar();
    }
    自定义函数的结构

    函数名与函数表

    #include <stdlib.h>    
    #include <stdio.h>
    
    // int getmax中的int是函数的返回值类型
    // getmax即函数名,是一个指向常量的指针,指向代码区的函数表某个地址;记录了函数名对应的函数体的入口地址(每一个应用程序都有一个函数表,该表存储了该程序所有函数的入口地址——即函数名对应的地址,改变函数入口地址可以改变函数的行为)
    // int a, int b函数的形式参数
    // {...} 块语句,不允许省略
    // return a > b ? a : b; 返回值
    // int getmax(int a, int b) 函数声明,别称函数头
    
    int getmax(int a, int b)
    {
        /*int a;    */    // error C2082 : redefinition of formal parameter 'a'  , 函数体内的变量和函数参数是同级别的同属函数体
        return a > b ? a : b;
    }
    
    void main02()
    {
    
        printf("%p", getmax);
    
        getchar();
    }
    
    /*
        在下面语句的下方打一断点:
        printf("%p", getmax);    0017133E
        查找反汇编:地址栏输入0x0017133E
        跳转到该程序的函数表对应的:
            _getmax:
            0017133E  jmp         getmax (01717A0h)                    在函数表中
        即函数名getmax映射到getmax()函数体的位置0x01717A0
        地址栏输入0x01717A0
        跳转到了函数体的内存位置:                                        函数实体
        int getmax(int a, int b)
        {
        001717A0  push        ebp
        001717A1  mov         ebp,esp
        001717A3  sub         esp,0C4h
        ...
    */
    函数名与函数表

    函数的定义与声明

    #include <stdlib.h>    // std标准库,C语言标准库是跨平台的
    #include <stdio.h>        
    #include <Windows.h> // 仅适用于Windows系统(第三方库函数)
    
    // C++属于严格的编程语言,函数的声明必须在调用之前
    int getres(int a, int b, int c);    // 函数的声明
    
    /*
        调用一个函数,首先必须知道这个函数是存在的C语言自上而下编译
        被调函数没有定义或者其在主调函数之后时,编译会出错
        故解决的方法有:
            首先要定义这个被调函数
            其次被调函数如果在主调函数之后,则需要在主调函数之前对被调函数加以声明;如果被调函数在主调函数之前则不需另加声明
    */
    
    // 函数的声明
    void msg();        // 函数的声明,只是说明函数的存在,因此也可出现重复(傻子才这么干)
    void msg();
    void msg();
    void msg();
    int cheng(int a, int b);
    
    void main123()
    {
        msg();
        printf("%d 
    ", cheng(12, 3));
    
        system("pause");
    }
    
    // 函数的定义
    void msg()
    {
        MessageBoxA(0, "锄禾日当午", "学Cztm刺激", 0);
    }
    
    //void msg()     error C2084: function 'void msg()' already has a body; note: see previous definition of 'msg'
    //{
    //     函数的定义则只能出现一次
    //}
    
    
    int cheng(int a, int b)
    {
        return a + b;
    }
    
    
    void main124()
    {
        // 代码重用
        int x = 3, y = 6, z = 9;
        x = x*x*x;
        y = y*y*y;
        z = z*z*z;
        int res = x + y + z;
        res = getres(x, y, z);
        /*
            getres(x, y, z);调用在定义之前时
            C程序:
            warning C4013: 'getres' undefined; assuming extern returning int
            1>LINK : fatal error LNK1561: entry point must be defined       (C中能编译——仅是警告,但是链接不行——严重错误:实例处必须定义)
            CPP程序:
            1>LINK : fatal error LNK1561: entry point must be defined
            2>error C3861: 'getres': identifier not found
        */
    
    
        int a = 10, b = 13, c = 14;
        a = a*a*a;
        b = b*b*b;
        c = c*c*c;
        int res1 = a + b + c;
        res1 = getres(a, b, c);
    
        system("pause");
    }
    
    int getres(int a, int b, int c)
    {
        return a*a*a + b*b*b + c*c*c;
    }
    
    
    void run(char *path)    // 外部函数,C语言功能的实现(代码重用)主要靠函数
    {
        ShellExecuteA(0, "open", path, 0, 0, 1);
    }
    
    void main01()
    {
        run("E:\Thunder Network\Thunder\Program\Thunder.exe");
    
    
        getchar();    
        /*
            库函数:
                由C语言系统提供,用户无需定义,也不必在程序中做类型说明,只需在程序前包含有该函数定义的头文件即可
        */
    }
    函数的调用与声明
    #include <stdlib.h>    
    #include <stdio.h>    
    
    int add05(int, int);        // 函数声明
    /*
        声明时,变量名可省略,可以多次声明
        函数的类型声明应该和定义的函数的类型保持一致,否则编译器会报错
        当被调函数定义在主调函数之前,声明就没必要了
    */
    
    void main005()
    {
        add05(3, 2);
    
        system("pause");
    }
    
    int add05(int a, int b)
    {
        return a + b;
    }
    声明时,形参变量名可省略,可以多次声明

    函数的参数

    #include <stdio.h>
    #include <stdlib.h>
    
    /*
        形参(形式参数)与实参(实际参数)的总结:
            形参:
            1、函数调用之前,形参即函数定义时()里的参数,值是不确定的;
            2、不确定的值,不会分配内存,只有调用的时候,才会分配内存并新建一个变量,新建的这个变量(形参)会接收实参(实际参数)的值,当函数调用结束之后,形参所占据的内存会被回收
            
            实参:
            1、函数调用时,主调函数传递给被调函数的确切值就是实际参数,实参可以是常量、变量或者表达式
    
            形参与实参内存地址不一样,占用的是不同的内存空间
    */
    
    
    // 地址不一样,说明change(int num)与main()函数中的num是2个不同的变量
    // 函数定义的时候是形参
    void change(int num)    // 此处的int num,是int类型的变量,是形参,只有在函数change被调用的时候才会分配内存,change运行完毕,num的内存即被回收;函数调用的时候,形参分配内存,新建一个num的变量,用于存储传递过来的实际参数的值
    {
        
        printf("change=%x, num=%d 
    ", &num, num);    // change = 17824956, num=10
    
        num = 100;
    
        printf("change=%x, num=%d 
    ", &num, num);    // change = 17824956, num=100
    }
    
    void main11()
    {
        int num = 10;
    
        printf("main=%x, num=%d 
    ", &num, num);    // main = 17825168, num=10
        
        change(num);        // 此处的num是一个实参,函数调用的时候传递的是实参;实参可以是变量、常量或表达式
        
        printf("%d 
    ", num);        // 10
        
        system("pause");
    }
    形参与实参
    #include <stdlib.h>
    #include <stdio.h>
    
    /*
    函数调用的时候,形参分配内存
    新建一个变量,存储传递过来的实参的值,等价于实参给形参赋值,赋值会自动完成数据类型转换
    */
    void print_1(int num)
    {
        printf("num=%d 
    ", num);
    }
    
    int adddata(int a, int b)
    {
        return a + b;
    }
    
    void main12()
    {
        // 调用函数的时候,尽量做到类型匹配,否则可能导致误差或错误
        //print_1(10.8);
        double db = adddata(10.9, 9.8);
        printf("%lf 
    ", db);        // 19.000000
    
        double db2 = adddata("Ahg", "fgB");    // Warning    C4047    'function': 'int' differs in levels of indirection from 'char [4]'    ----> C
        // Warning    C4024    'adddata': different types for formal and actual parameter 1    ----> CPP
    
        printf("%lf 
    ", db2);        // 11990992.000000 意想不到的结果
        
        system("pause");
    }
    对应的形参与实参类型应一致

    函数的可变参数

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdarg.h>
    #include <string.h>
    
    void myprintf(char *ptstr, ...)        // 可变参数
    {
        va_list ap;                    // 定义起始点    (char *类型的指针)
        va_start(ap, ptstr);        
        /*
            固定参数pstr,是函数myprintf()的第一个参数,存储于栈中,位于栈底
    
            typedef char * va_list;
    
            把 n 圆整到 sizeof(int) 的倍数
            #define _INTSIZEOF(n)       ( (sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1) )
    
            初始化 ap 指针,使其指向第一个可变参数。v 是变参列表的前一个参数    即 此处的ptstr
            #define va_start(ap,v)      ( ap = (va_list)&v + _INTSIZEOF(v) )
    
            该宏返回当前变参值,并使 ap 指向列表中的下个变参(ap指向的数据以type类型的方式加以解析)
            #define va_arg(ap, type)    ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) )
    
            将指针 ap 置为无效,结束变参的获取
            #define va_end(ap)             ( ap = (va_list)0 )
    
            原文链接:https://blog.csdn.net/u013490896/java/article/details/85490103
            参考链接:https://www.cnblogs.com/clover-toeic/p/3736748.html
        */
    
    
        char flag;
        while (*ptstr)
        {
    
            flag = *ptstr;
            if (flag != '%')
            {
                putchar(flag);
                ptstr++;
            }
            else
            {
                flag = *++ptstr;
                switch (flag)
                {
                case 'd':
                    printf("%d", va_arg(ap, int));
                    ptstr++;
                    break;
                case 's':
                    printf("%s", va_arg(ap, char *));
                    ptstr++;
                    break;
                case 'c':
                    //printf("%c", va_arg(ap, char));
                    putchar(va_arg(ap, char));
                    ptstr++;
                    break;
                case 'f':
                    printf("%f", va_arg(ap, double));
                    ptstr++;
                    break;
                default:
                    break;
                }
            }
        }
    
        va_end(ap);        // 结束读取
    }
    
    void main003()
    {
        myprintf("niha
    ");
        myprintf("niha%d
    ", 10);
        myprintf("niha%d%s
    ", 10, "Hello");
        myprintf("niha%d%s%c
    ", 10, "Hello", 'A');
        myprintf("niha%d%s%f%c
    ", 10, "Hello", 3.1415926, 'A');
    
        puts("
    ");
    
        system("pause");
    }
    函数可变参数宏的结构
    #define _CRT_SECURE_NO_WARNINGS
    #include <stdlib.h>    
    #include <stdio.h>
    #include <stdarg.h>        // stand argument
    
    // 已知参数的个数为num
    int add3(int num, ...)    // ...代表可变参数,num代表参数个数
    {
        int res = 0;         //结果
        va_list  argp;        // 存储参数开始的地址(参数列表首地址)
        va_start(argp, num);// 从首地址开始,读入num后面的数据到地址
        for (int i = 0; i < num; ++i)
        {
            res += va_arg(argp, int); // 按照int类型读取一个数据单元
        }
        va_end(argp);
    
        return res;
    }
    void go(int num, ...)
    {
        va_list argp;
        va_start(argp, num);
        for (int i = 0; i < num; ++i)
        {
            /*char str[50];
            sprintf(str, "%s", va_arg(argp, char *));
            system(str);*/
            system(va_arg(argp, char *));
        }
        va_end(argp);
    }
    
    void showint(int start, ...)
    {
        va_list argp;
        va_start(argp, start);
        int argvalue = start;    // 第一步初始化
        do
        {
            printf("%d ", argvalue);
            argvalue = va_arg(argp, int);
        } while (argvalue != -1);
        va_end(argp);
    }
    
    void main08()
    {
        //printf("%d 
    ", add3(3, 1, 2, 3));         //6    
        //printf("%d 
    ", add3(4,3, 1, 2, 3));    // 9
        //printf("%d 
    ", add3(5, 4, 7, 1, 2, 3)); // 17
    
        //go(3, "notepad", "calc", "tasklist&pause");
    
        showint(1, 2, 3, 4, 5, -1);
    
        getchar();
    }
    函数可变参数的应用
    #include <stdio.h>
    #include <stdlib.h>
    
    
    // void main(void)            返回空类型,参数为空
    // main()                    默认的返回值类型为int类型,参数为空
    
    
    main(int argc, char *args[])
    {
        for (int i = 0; i < argc; i++)
        {
            puts(args[i]);
        }
    
        // argc是参数的个数
        // args[]是一个指针数组,存储的是常量字符串的地址,args[0]第一个参数是主程序的路径,第二个是附加参数
    
        system("pause");
    }
    
    
    void main020(int argc, char *args[], char *envr[])    // 第三个参数:环境变量字符串的地址
    {
        char **pp = envr;
        while (*pp != NULL)
        {
            puts(*pp);
            pp++;
        }
    
        system("pause");
    }
    main函数的参数列表

    函数参数的运算与入栈顺序

    #include <stdlib.h>    
    #include <stdio.h>
    
    void add2(int a, int b)
    {
        printf("a=%d, b=%d 
    ", a, b);
    }
    
    void main07()
    {
        int a = 5;
        int b = 5;
        int c = 5;
        int d = 5;
        int e = 5;
        int f = 5;
    
        /*
            函数参数与函数一样,遵循栈先进后出的原则,即先执行的代码后入栈,后执行的代码先入栈
        */
        add2(a, a++);        // a=6, b=5            
        /*
            入栈:
                1、a++是一个表达式,保存在栈中的结果为5,a自增1等于6
                2、a是一个变量,保存在栈中的结果为a
            出栈:
                2、a        ---> 6
                1、a++    ---> 5 ----> 5
        */
    
        add2(b, b += 1);    // a=6, b=6            
        /*
            入栈:
                1、b+=1是一个赋值表达式,保存在栈中的结果为b,b自增1等于6
                2、b是一个变量,保存在栈中的结果为b
            出栈:
                2、b        ---> 6
                1、b+=1    ---> b ---> 6
        */
    
        add2(c++, c = c + 2);    // a=7, b=8
        add2(d++, d += 2);    // a=7, b=8
        /*
            入栈:
                1、d+=2是一个赋值表达式,保存在栈中的结果为d,d自增2等于7
                2、d++是一个表达式,保存在栈中的结果为7,d自增1等于8
            出栈:
                2、d++    ---> 7
                1、d+=2    ---> d ---> 8
        */
    
        add2(e, e++, e += 2);    // a=8, b=7
        /*
            入栈:
                1、e += 2是一个赋值表达式,保存在栈中的结果为e,e自增2等于7
                2、e++是一个表达式,保存在栈中的结果为7,f自增1等于8
                3、e是一个变量,保存在栈中的结果为e
            出栈:
                3、e        ---> 8
                2、e++    ---> 7
            因为add2()函数定义中只有2个形参,因此1、e += 2不会作为函数的参数出栈
        */
    
        add2(f += 2, f++, f += 2);    // a=10, b=7
        /*
            入栈:
                1、f += 2是一个赋值表达式,保存在栈中的结果为f,f自增2等于7
                2、f++是一个表达式,保存在栈中的结果为7,f自增1等于8
                3、f += 2是一个赋值表达式,保存在栈中的结果为f,f自增2等于10
            出栈:
                3、f += 2   ---> f ---> 10
                2、f++    ---> 7
            因为add2()函数定义中只有2个形参,因此1、f+= 2不会作为函数的参数出栈
        */
    
        getchar();
    }
    函数的参数的入栈顺序

    函数的执行过程

    #include <stdlib.h>    
    #include <stdio.h>
    
    // C语言通过栈来控制程序的执行顺序,后执行的语句或函数先进栈,最后压栈的语句或函数先出栈执行
    
    void main06()
    {
        printf("main 上 
    ");
        //void print1();    // C语言理论上是要加声明的
        //print1();        没有声明时,该函数无参数,会到系统中去找匹配的函数,结果没有,就发生链接错误
        add1(3, 4);                // 而此时add1函数未加声明,C编译器却编译并链接成功,还能正确执行,只能说C编译器太宽泛了,此处编译器根据add1(3,4);有参数,而且返回值是整数,因此找到了被调函数
    
        printf("%d 
    ", add1(3));    // 15274067(执行第二次结果就不一样了)  参数多了或少了,结果不可预测(居然编译并成功执行了,C编译器真是大条了!)
        printf("main 下 
    ");
    
        system("pause");
    }
    
    /*
        被调函数的定义在主调函数之后,C语言编译器可能找到了,则会通过编译并链接成功;如果没找到则会出现以下错误:
    (10): warning C4013: 'print1' undefined; assuming extern returning int
    (17): error C2371: 'print1': redefinition; different basic types
        但是在被调之前加以声明,则一定能找到已定义的被调函数
    */
    void print1()
    {
        printf("main 上 
    ");
    
        printf("main 下 
    ");
    }
    
    int add1(int a, int b)
    {
        return a + b;
    }
    函数的调用执行过程注意事项

    函数调用的注意事项

    #include <stdio.h>
    
    void main09()
    {
        //printf("Hello China. 
    ");
        printf;        // 引用函数名必须声明
            // warning C4550: expression evaluates to a function which is missing an argument list   加入#include <stdio.h>时
    }
    
    /*
        C语言函数可以自动定位,没有头文件,没有函数声明,自动寻找,参数多了、少了都能执行;如果不是函数调用,无法自动定位
    */
    
    void main001()
    {
        //printf("%d 
    ", add4(2, 3));
        //add4;        
        /*
            当上面一句没有被注释时:[compile] warning C4013: 'add4' undefined; assuming extern returning int,而且能够链接并且程序能够运行
    
            当上面一句被注释时:[compile]error C2065: 'add4': undeclared identifier
    
            说明C编译器查找add4(2, 3); 时,因为有函数调用而且是有参调用,能够精确定位到本程序内部的函数定义,接着下面的add4就在上一步的基础上找到了。   可见C语言的编译器太灵活了。
        */
        print11();
        system("pause");
    }
    
    int print11()
    {
    
    }
    
    int add4(int a, int b)
    {
        return a + b;
    }
    函数调用的错误示范

    函数的返回值

    #include <stdlib.h>
    #include <stdio.h>
    
    int go()    
    {
    
    }
    /*
        Warning C4716 'go': must return a value
        非main函数如果函数类型不是void,编译时会出现一个警告,如果是CPP文件,则会是一个错误
            函数的返回值类型必须与函数名前的类型保持一致,当函数的类型为void时,可以没有return语句
        void main(void)            返回空类型,参数为空
        main()                    默认的返回值类型为int类型,参数为空
    */
    
    int main6()    // 无论main函数是否是void类型,还是其他类型的函数,main函数可以没有返回值
    {
        //printf("
    1");
        //printf("
    2");
        //return 1;        // return 之后的语句不会接着执行,main函数中的return意味着整个程序的退出和结束
        //printf("
    3");
        //printf("
    4");
        //printf("
    5");
    
    
        godata();
    
        getchar();
    
        // main函数或其他函数中没有return语句,执行完所有的语句后,函数会自动退出
    }
    
    /*
        函数内部定义的变量或参数(局部变量),在函数调用结束之后(函数返回后),变量即刻被销毁,内存被回收
        函数返回值有副本机制,返回的时候,另外再存一份
    
        如果返回值是全局变量,则该变量一直存在,直到程序运行结束,全局变量才会被销毁,内存这时才被回收
    */
    int addpp(int a, int b)
    {
    
        int z = a + b;
    
        printf("%p", &z);
    
        return z;
    }
    
    int addbb(int a, int b)
    {
        int z = 0;
    
        z = a + 1;
    
        z = a + 2;
    
        z = a + b;
    
        return a + b;
        // a+b是临时变量,在寄存器中保存其计算结果
        // 返回临时变量时,临时变量会从寄存器中即刻销毁
    }
    
    void main()
    {
        // 此处打印的是副本,原来内存中的数据已被销毁
        //printf("%d 
    ", addpp(3, 7));
    
        printf("%d 
    ", addbb(3, 7));
    
        printf("
    
    ");
    
        getchar();
    }
    函数的返回值

    局部变量与全局变量

    #include <stdio.h>
    #include <stdlib.h>
    
    /*
        总结:
            块语句内部的变量,其作用域是变量所在块语句定义的起始处至该块语句的结束,也可作用于内部包含的块语句(前提是没有定义与该变量的名称相同的变量——存在内层变量屏蔽外层变量的情况)
            同一个块语句不能重复定义一个变量
            
            局部变量调用完成以后会被回收,该局部变量的位置出现垃圾数据
            局部变量是为块语句服务的,块语句执行结束,局部变量就被回收
            函数内部定义的变量以及函数的参数均是局部变量
    */
    
    int a = 100;    // 变量名相同的全局变量和局部变量,是两个(内存地址)不同的变量,因此可以重复定义
    
    void main16()
    {
        int a = 10;    // 在同一块语句内,变量不能重复定义
        //int a = 11;    // Error    C2374    'a':redefinition
        int b = 99;
        printf("%x, %x, %d, %d 
    ", &a, &b, a, b);        // 5bfd44, 5bfd38, 10, 99
        {
            int a = 11;                    // 不同的块语句,不同的作用域
            printf("%x, %x, %d, %d 
    ", &a, &b, a, b);    // 5bfd2c, 5bfd38, 11, 99   块语句中可以包含块语句,局部变量b的作用范围包括子块,而在子块中定义的变量a屏蔽了母块中的变量a(其效果与块语句中的变量a屏蔽全局变量a一样)
        }
            
        system("pause");
    }
    块语句与局部变量
    #include <stdlib.h>
    #include <stdio.h>
    
    // 全局变量不属于任何一个函数,可以被任何一个函数调用
    // 创建的全局变量比main函数还早,全局变量的生存期是整个程序的生存期
    // 全局变量在程序生命周期内一直存储于内存,而局部变量在所属的函数调用完毕之后生命周期结束,同时其所占据的内存也将被回收
    // 需要任意函数调用的场合就需要全局变量,全局变量可用于函数间的通信
    int num = 4298;        // 全局变量  -- 整个公司的RMB
    int data = 10;
    
    void 事业部A()
    {
        num = num - 800;    // 支出800
        num = num + 900;    // 营收900
    }
    
    void 事业部B()
    {
        num = num - 1800;    // 支出1800
        num = num + 900;    // 营收900
    }
    
    void printdata()
    {
        printf("%d 
    ", data);
    }
    
    void main14()
    {
        data = 100;
        printdata();        // 100
    
        //num += 1000;        // 科技创新基金
        //事业部A();
        //事业部B();
    
        //printf("num=%d 
    ", num);
    
        system("pause");
    }
    全局变量
    #include <stdio.h>
    #include <stdlib.h>
    
    /*
        全局变量特点/缺点:
            生存周期一直持续到程序退出
            内存也在程序退出之后才释放
            容易与局部变量重名,容易被屏蔽失效
            值容易被修改——例如游戏,遇到外挂一类的程序、注入的黑客技术等技术,值容易被修改
    */ 
    
    /*
        全局变量可以被本文件中所有的函数所共享
        使用全局变量要做到:
            1、变量名要容易理解,尽可能不与局部变量重名
            2、避免占内存较大的变量作为全局变量
            3、避免全局变量被错误的修改(正规的软件工程,写一个函数需要修改全局变量时,一定要注释为什么修改,修改的目的是什么,修改值是多少)
    */
    
    int RMB = 3000;        
    
    void addRMB(int num)
    {
        RMB += num;
    }
    
    void mulRMB(int num)
    {
        RMB -= num;
    }
    
    void printRMB()
    {
        printf("你的RMB还有%d 
    ", RMB);
    }
    
    void main17()
    {
        addRMB(1000);
        mulRMB(5);
        mulRMB(500);
        mulRMB(5);
        printRMB();
    
        system("pause");
    }
    全局变量的特点
    #include <stdio.h>
    #include <stdlib.h>
    
    int x = 1000;
    
    void main15()
    {
        int x = 8;    // 变量名称相同的时候,在局部变量的作用域中,局部变量会屏蔽全局变量(不是改变)
        printf("%d 
    ", x);        // 8
        //printf("%d 
    ", ::x);    // C++可以用::x来访问全局变量x, C则不可以
    
        system("pause");
    }
    
    /*
        全局变量很容易被内部变量屏蔽,很容易被引用或修改
    */
    
    int a;
    
    void maina()
    {
        printf("%d 
    ", a);        
        /*
            本文件未声明变量a时:int a
            error C2065: 'a': undeclared identifier
    
            声明a时:int a;
            输出结果为9,int a =9;是在同工程中的“全局变量和局部变量.c”文件中声明的——说明全局变量是可跨文件调用的
        */
    
        getchar();
    }
    
    void main006()    // 这里说的屏蔽是指变量名相同的变量
    {
        int a = 10;
        printf("%d 
    ", a);        // 局部变量会屏蔽全局变量
        {
            printf("%d 
    ", a);    // 10 此处是引用的上一层局部变量
            char a = 'B';
            //int  a = 66;    // error C2371: 'a': redefinition; different basic types
            printf("%d,%c 
    ", a, a);    // 内部块语句局部变量会屏蔽内部块语句以外的变量
        }
        printf("%d 
    ", a);        // 10
    
        getchar();
    }
    全局变量与局部变量之间的冲突
    #include <stdlib.h>    
    #include <stdio.h>
    
    /*
        局部变量只有定义和初始化的概念,不存在声明
        全局变量可以多次声明,定义的时候相当于声明+初始化
    */
    
    //int a = 10;            // 全局变量
    
    int a;    // 全局变量被当成声明来看待
    int a;    // 全局变量未定义默认为ASCII为0,字符为空
    int a;
    int a = 9;    // 全局变量的定义
    //int a = 3;    // error C2374: 'a': redefinition; multiple initialization
    
    
    void main004()
    {
        printf("%d,%c 
    ", a, a);        // 0,' '
        int b;
        //printf("%d 
    ", b);        // error C4700: uninitialized local variable 'b' used
    
        printf("%c,%d 
    ", c, c);        // ' ',0
    
        system("pause");
    }
    
    void main003()
    {
    
        int a;        // 局部变量
        int a=13;            // error C2086: 'int a': redefinition
    }
    
    void go001()
    {
        a = 13;            //(无全局变量时) error C2065: 'a': undeclared identifier
    }
    全局变量与局部变量的定义及全局变量的声明问题

    函数与递归

    #include <stdio.h>
    #include <stdlib.h>
    
    //void main()
    //{
    //    main();        // 死循环
    //}
    
    
    // f(n)=f(n+1)+1
    // f(5) return
    void go_3(int num)
    {
        if (num >= 5)
            return;
        else
        {
            system("notepad");
            go_3(num + 1);
        }
    }
    
    /*
        1+2+3+...+100    f(100)
        1+2+3+...+99    f(99)
        f(100)=f(99)+100
        f(n)=f(n-1)+n
    */
    int goadd_1(int num)
    {
        if (num == 0)
            return 0;
        else
            return num + goadd_1(num - 1);
    }
    
    /*
        10 % 2  0
        5  % 2  1
        2  % 2  0
        1  % 2  1
        (10)10=(1010)2
    */
    void to2(int num)
    {
        if (num == 0)
            return;
        else
        {
            //printf("%d", num % 2);    // 0101    调用之前顺序
            to2(num / 2);
            printf("%d", num % 2);        // 1010    调用之后逆序
        }
    }
    
    void main009()
    {
        //go_3(0);
        //printf("%d 
    ", goadd_1(100));
        to2(10);
    
        getchar();
    }
    线性递归
    #include <stdio.h>
    #include <stdlib.h>
    
    /*
        斐波那契数列:
        有一对兔子,每个月可以生育一对兔子,刚出生的兔子2个月后可以生育一对兔子,问N个月之后又多少对兔子
        1    
        1
        1   1
        1   1   1
        1   1   1   1    1
    
        g(n)=g(n-1)+g(n-2)
    */
    
    int getRabbitTreeRecursive(int num)
    {
        if (num == 1 || num == 2)
            return 1;
        else
            return getRabbitTreeRecursive(num - 1) + getRabbitTreeRecursive(num - 2);
    }
    
    int getRabitForCycle(int num)
    {
        int f1 = 1, f2 = 1;
        int f3;
        for (int i = 3; i <= num; ++i)
        {
            f3 = f2 + f1;
            f1 = f2;
            f2 = f3;            // 轮替注意值的覆盖顺序
        }
        return f2;
    }
    
    void main()
    {
        printf("%d 
    ", getRabitForCycle(40));
        printf("%d 
    ", getRabbitTreeRecursive(40));
        printf("%d 
    ", getRabitForCycle(40));
    
        /*
            树状递归速度较慢,函数的循环调用需要消耗时间,但是算法简单;
    
            树状递归可以分解为:循环+栈
        */
    
        getchar();
    }
    树状递归_斐波那契数列
  • 相关阅读:
    iOS 微信支付SDK与微信友盟分享两者同时集成时,出现的问题与解决之路。
    Object-C语言Block的实现方式
    使用Mac命令别名,提升工作效率
    利用OC对象的消息重定向forwardingTargetForSelector方法构建高扩展性的滤镜功能
    渐变色进度条的两种绘制方案
    设计模式应用场景之Model设计中可以用到的设计模式
    有趣的赫夫曼树
    技术团队管理者的问题视角
    SSH安全登陆原理:密码登陆与公钥登陆
    为什么HashMap继承了AbstractMap还要实现Map?
  • 原文地址:https://www.cnblogs.com/ant-colonies/p/13398766.html
Copyright © 2020-2023  润新知