07 C函数

1、why函数?

#include <stdio.h>
int moveToLeft(){
    printf("打左转向灯\n");
    printf("看左边后视镜\n");
    printf("向左打方向盘\n");
    printf("踩油门加速\n");
}

int moveToRight(){
    printf("打右转向灯\n");
    printf("看右边后视镜\n");
    printf("向右打方向盘\n");
    printf("踩油门加速\n");
}

int main()
{
    /*
     * 为什么要定义函数
     *
     * 如果不定义函数:
     * 1.重复代码冗余代码过多, 又臭又长
     * 2.需求发生变更时需要修改很多代码, 不利于维护
     *
     * 如果定义函数:
     * 1.提高了代码的复用性, 代码变得更简洁
     * 2.需求发生变更时只需要修改很少的代码, 有利于维护
     *
     * 函数的作用:
     * 将某些代码封装起来
     */

    /*
    // 像左边变道
    printf("打左转向灯\n");
    printf("看左边后视镜\n");
    printf("向左打方向盘\n");
//    printf("踩油门加速\n");

    // 像右边变道
    printf("打右转向灯\n");
    printf("看右边后视镜\n");
    printf("向右打方向盘\n");
    printf("踩油门加速\n");

    // 像左边变道
    printf("打左转向灯\n");
    printf("看左边后视镜\n");
    printf("向左打方向盘\n");
//    printf("踩油门加速\n");
    */

    // 向左变道
    moveToLeft();
    printf("-----------------\n");
    // 向右变道
    moveToRight();
    printf("-----------------\n");
    // 向左变道
    moveToLeft();
    return 0;
}
#include <stdio.h>

int getMax(int num1, int num2){
    int max = num1 > num2 ? num1 : num2;
    return max;
}
int main()
{
    /*
     * 函数定义的格式
     * 返回值类型 函数名称(形参列表){
     *      被封装到函数中的代码;
     * }
     *
     * 初学者如何定义函数
     * 1.确定函数的名称(给函数起一个有意义的名称, 让调用者见名知意)
     * 注意点: 函数名称也是标识符的一种, 所以也需要遵守标识符的命名规则 字母 数字 下划线 驼峰命名
     * 2.确定形参列表(告诉调用者调用时是否需要传递一些辅助的数据)
     * 注意点: 形参列表的格式     (数据类型 变量名称, 数据类型 变量名称, ....)
     *        数据类型 变量名称  可以有零个或多个
     * 3.确定返回值和返回值类型
     * 注意点: 返回的数据是什么类型, 返回值类型就写什么类型
     * return的作用之一就是将后面的数据返回给函数的调用者
     *
     */


    int a = 10;
    int b = 20;
//    int max = a > b ? a : b;
    int max = getMax(a, b);
    printf("max = %i\n", max);

//    int c = 55;
//    int d = 60;
//    int max2 = c > d ? c : d;
    int max2 = getMax(55, 60);
    printf("max2 = %i\n", max2);
    return 0;
}

#include <stdio.h>
int getAverage(int num1, int num2){
    int avg = (num1 + num2) / 2;
    return avg;
}
int main()
{
    int a = 10;
    int b = 20;
//    int res = (a + b) / 2;
    int res = getAverage(a, b);
    printf("average = %i\n", res);
    return 0;
}

#include <stdio.h>

// 没有参数的函数
void test(){
    printf("test\n");
}
// 有参数的函数
int sum(int a, int b){
    return a + b;
}
void say(int age){
    printf("age = %i\n", age);
}
char test2(){
    return 'a';
}
float test3(){
    return 3.14;
}
int main()
{
    // 1.函数可以有参数, 也可以没有参数
    // 2.函数的参数可以是零个或多个
    test();
    int res = sum(1, 1);
    printf("res = %i\n", res);
    say(18);
    // 3.函数可以有返回值, 也可以没有返回值
    // 如果函数没有返回值, 那么返回值类型写void就可以了
    // 4.函数的返回值类型可以是所有C语言类型
    printf("test2 = %c\n", test2());
    printf("test3 = %f\n", test3());
    return 0;
}

#include <stdio.h>

void test(){
    printf("test 1111");
}
//void test(){ // 会报重复定义的错误
//    printf("test 22222");
//}
//int test(){ // 会报重复定义的错误
//    printf("test 33333");
//}
//int test(int a, int b){// 会报重复定义的错误
//    printf("test 1111");
//}

//int test1(){
//    int say(){ // 会报错
//        printf("say 321\n");
//    }
//    printf("test1\n");
//}


//void change(int num){ // 这里的num,我们称之为形参
//    num = 666;
//}

//void test(int num){
//    int num = 666;
//    printf("num = %i\n", num);
//}

int main()
{
    /*
    // 1.函数的名称不能相同
    // 1.2.哪怕返回值类型不同, 函数名称也不能相同
    // 1.3.哪怕形参列表不同, 函数名称也不能相同

    // 2.函数不能嵌套定义, 哪怕编译器允许, 也不建议这么干
//    void say(){
//        printf("say 123");
//    }
//    say();

    test1();
//    say();
    */

//    // 3.如果是基本类型的数据作为函数的参数, 那么在函数内修改形参, 不会影响外面实参的值
//    // int char float double
//    int a = 10; // 这里的a我们称之为实参
//    printf("调用change函数前:a = %i\n", a); // 10
//    change(a);
//    printf("调用change函数后:a = %i\n", a); // 10

      // 4.在函数内部不能定义和形参同名的变量

    // 变量之间的赋值都是拷贝
    int a = 10;
    int b = a;
    b = 666;
    printf("a = %i\n", a);
    printf("b = %i\n", b);
    return 0;
}

2、函数进阶

#include <stdio.h>

//void test(){
//    printf("test\n");
//}
// 函数的声明
//void test();
//void test();
//void test();
//void test();
//void test();
int sum(int, int);

int main()
{
    /*
     * C语言规定:
     * 如果将函数的定义写在了函数调用之后, 那么必须在调用之前编写函数的声明
     *
     * 什么是函数的定义:
     * 函数的定义就是函数具体的实现代码, 真正实现了函数功能的代码
     *
     * 什么是函数的声明:
     * 函数的声明就是在调用之前告诉编译器, 我们一定有一个名称叫什么, 接收什么类型参数, 返回值是什么类型的一个函数
     * 函数的什么只需将函数定义{前面的代码拷贝即可
     *
     * 注意点:
     * 1.如果不按照C语言的规定在函数调用之前编写函数的什么, 那么在不同编译器下会有不同的运行结果
     * GCC编译器可以编译通过, 但是在其它的编译器可能就会报错
     * 2.由于函数的声明仅仅是为了告诉编译器, 我们有一个什么函数, 所以函数的声明可以声明多次, 但是函数的实现只能实现一次
     * 3.由于函数的声明仅仅是为了告诉编译器, 我们有一个什么函数, 所有函数的什么只要在调用之前声明即可
     * 4.由于函数的声明仅仅是为了告诉编译器, 我们有一个什么函数, 所以声明时不用指定形参的名称
     * 5.如果函数的返回值类型是int类型, 那么可以不用编写函数的声明(仅仅作为了解)
     */
//    void test();
    test();
//    int sum(int , int);
    int res = sum(10, 20);
    printf("res = %i\n", res);
    return 0;
}
// 函数的定义
void test()
{
    printf("test\n");
}
//void test()
//{
//    printf("test\n");
//}

int sum(int a, int b){
    return a +b;
}

#include <stdio.h>

/*
 * 1.main函数是系统自动调用的函数, 我们不能手动调用
 * 2.系统在调用main函数的时, 默认会传递两个参数
 * argc: 第二个数组保存数据的个数
 * argv: 默认保存了一个数据, 这个数据就是当前文件的地址
 * 3.argv中保存的元素是可以动态添加的
 *
 * 4.main函数的return 0 的含义
 * 告诉系统当前程序是正常结束的, 如果return返回的不是0, 就代表告诉系统程序不是正常结束的
 *
 * 暂时只需要知道一点:
 * 在企业开发中, 我们是可以通过控制台(CMD)在运行程序的时候给main函数传递参数的就可以了
 */
int main(int argc, const char *argv[])
{
    // ["lisi", "zs"]
    // 代表数组中有一个元素
    // 代表数组中有两个元素
    // 默认情况下, 系统在调用main函数的时候, 会给argv这个数组中存放一个元素
    // ["C:\Users\Jonathan_Lee\Desktop\C_Lessons\Code\build-76-lesson-Desktop_Qt_5_11_0_MinGW_32bit-Debug\debug\76-lesson.exe"]
    printf("argc = %i\n", argc);
    printf("argv[0] = %s\n", argv[0]);
    printf("argv[1] = %s\n", argv[1]);
    printf("argv[2] = %s\n", argv[2]);
    return 0;
}

#include <stdio.h>

//// 没有返回值, 没有形参的函数
//void test1(){
//    printf("test1\n");
//}
//// 没有返回值, 有形参的函数
//void test2(int age){
//    printf("age = %i\n", age);
//}
//// 有返回值, 没有形参的函数
//int test3(){
//    return 998;
//}
//// 有返回值, 有形参的函数
//int sum(int a, int b){
//    return a + b;
//}

//test4(){
//    return 6;
//}
//// 如果没有编写返回值类型, 默认就是int
//test5(){
//    return 6.6; // double
//}

int test6(){
    return 3.14;
}
int main()
{
    /*
     * 函数分类:
     * 没有返回值, 没有形参的函数
     * 没有返回值, 有形参的函数
     * 有返回值, 没有形参的函数
     * 有返回值, 有形参的函数
     *
     * 注意点:
     * 1.如果没有写函数的返回值类型, 默认就是int类型
     * 2.如果函数的返回值类型和实际返回的类型不同, 那么会隐式(自动)转换为返回值类型
     */
//    test1();
//    test2(666);
//    int res = test3();
//    printf("res = %i\n", res);
//    int res2 = sum(10, 20);
//    printf("res2 = %i\n", res2);

//    int res = test4();
//    printf("res = %i\n", res);

//    int res2 = test5();
//    printf("res2 = %i\n", res2);
//    printf("res2 = %lf\n", res2);



    int res = test6();
    printf("res = %i\n", res);
    printf("res = %lf\n", res);
    return 0;
}

3、递归函数

#include <stdio.h>
int test();
int main()
{
    /*
     * 递归函数:
     * 自己搞自己
     * 递归可以实现循环的功能, 但是递归的性能比循环差很多
     */
    /*
//    // 1.定义变量保存用户输入的数据
//    int num = -1;
//    do{
//        // 2.提醒用户如何输入数据
//        printf("请输入一个正整数, 以回车结束\n");
//        // 3.接收用户输入的数据
//        scanf("%i", &num);
//    }while(num < 0);
    */

    int res = test();
    printf("res = %i\n", res);
    return 0;
}
// 1.定义一个函数, 用于用户校验
int test(){
    // 1.定义变量保存用户输入的数据
    int num = -1;
    // 2.提醒用户如何输入数据
    printf("请输入一个正整数, 以回车结束\n");
    // 3.接收用户输入的数据
    scanf("%i", &num);
    // 4.判断用户输入的时候是合法数据
    if(num < 0){
        // 用户输入的数据不合法
         return test();
    }
    return num;
}

#include <stdio.h>
int pow(int, int);
int main()
{
    /*
     * 编写一个函数实现求 B的n次方
     * b(n)
     * 假设我们要求b(3)次方
     * b(0) = 1
     * b(1) = b
     * b(2) = b * b
     * b(3) = b * b * b
     *
     * b(0) = 1
     * b(1) = b(0) * b // 1 * b
     * b(2) = b(1) * b // b * b
     * b(3) = b(2) * b // b * b * b
     *
     * 规律: b(n) = b(n-1) * b;
     *      b(3) = b(3-1) * b;
     *      b(3) = b(2) * b;
     *
     * 3(3) = 3 * 3 * 3 = 27
     */

    int res = pow(3, 3);
    printf("res = %i\n", res);
    return 0;
}
// base就代表是b
int pow(int base, int n){
    if(n == 0){
        return 1;
    }else{
        return pow(base, n-1) * base;
    }
}


#include <stdio.h>
int test(int n);
int main()
{
    /*
     * 利用递归实现N的阶乘
     * 3! = 3 * 2 * 1
     * 2! = 2 * 1
     * 1! = 1
     *
     * 和刚才b的n次方同一个世界同一个梦想, 自己总结规律
     *
     * 1! = 1
     * 2! = 1 * 2
     * 3! = 1 * 2 * 3
     * 4! = 1 * 2 * 3 * 4
     *
     * 1! = 1
     * 2! = 1! * 2
     * 3! = 2! * 3
     * 4! = 3! * 4
     *
     * 规律: n! = (n-1)! * n
     */

    /*
     * 在企业开发中, 一般情况下能够使用递归实现的功能, 都能使用循环实现, 所以一般情况下不会使用递归
     * 递归在面试中出现得比较多, 还有就是在文件操作中使用得比较多
     */
//    printf("res = %i\n", 1 * 2 * 3 * 4);
    int res = test(4);
    printf("res = %i\n", res);
    return 0;
}
int test(int n){
    if(n == 1){
        return 1;
    }else{
        return test(n - 1) * n;
    }
}

#include <stdio.h>
int test(int n);
int main()
{
    /*
     * :
     * 有5个人坐在一起,
     * 问第5个人多少岁?他说比第4个人大2岁。
     * 问第4个人岁数,他说比第3个人大两岁。
     * 问第3个人,又说比第2个人大2岁。
     * 问第2个人,说比第1个人大2岁。
     * 最后问第1个人, 他说是10岁。
     * 请问第5个人多大?
     *
     * 第1个人: 10
     * 第2个人: 10 + 2;
     * 第3个人: 10 + 2 + 2;
     * 第4个人: 10 + 2 + 2 + 2;
     * 第5个人: 10 + 2 + 2 + 2 + 2;
     *
     * 其中第几个人是n, 10就是n的默认值
     *
     * 规律: (n - 1) + 2;
     */
    int res = test(5);
    printf("res = %i\n", res);
    return 0;
}

int test(int n){
    if(n == 1){
        return 10;
    }else{
        return test(n - 1) + 2;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 我最喜欢的小动物是小白兔,因为我就属小兔子的。爸爸说我是小黑兔,因为我长的不白,我特别生气。我觉得我就是小...
    莹宝ying阅读 3,199评论 0 0
  • 于人而言,最难受的莫过于动过真情,却无疾而终。
    球球的下午茶阅读 1,209评论 0 5
  • 今日冬至,雾霾仍未散去。 推开窗,是一片灰蒙蒙,似乎一切都不可见。 岁月静好,现世安稳。只是空气糟糕。 出不得门去...
    南山寺外阅读 1,014评论 0 0
  • 1.刚换手机那阵,我让小侄子给我注册了微信。把通迅录里的人放到了朋友圈里。 偶一日发现,我的一个小学同学用云水禅心...
    子丑寅阅读 1,774评论 0 0