当前位置 博文首页 > HyDraZya的博客:【C语言基础】初步理解函数

    HyDraZya的博客:【C语言基础】初步理解函数

    作者:[db:作者] 时间:2021-09-05 09:45

    函数

    目录

    一、C语言中函数的分类

    二、自定义函数

    三、函数的参数?

    四、函数的调用

    ????????练习

    五、函数的嵌套调用和链式访问

    ????????嵌套调用

    ????????链式访问

    六、函数的声明和定义

    ????????函数声明

    ????????函数定义

    七、函数递归

    ????????练习

    ????????递归与迭代



    一、C语言中函数的分类

    1.库函数

    2.自定义函数

    函数放在main函数之前,不用+声明

    C语言常用的库函数

    • IO函数(input output 输入/输出函数)
    • 字符串操作函数
    • 字符操作函数
    • 内存操作函数
    • 时间/日期函数
    • 数学函数
    • 其他库函数

    strcpy:

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        char arr1[] = "bit";
        char arr2[20] = "############";
        // bit->bit\0#########由于\0是结束标志所以后面的#不打印
        strcpy(arr2, arr1);
        printf("%s\n", arr2);
        //strlen - string length - 字符串长度
        //strcpy - string copy - 字符串拷贝
        return 0;
    }

    memset:

    memory(内存) +set(设置)

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        char arr[] = "hello world";
        memset(arr, '*', 5);
        //'*'存入的数组的是ACSll码值,42,也是也是一个整型
        printf("%s\n", arr);
        return 0;
    }

    二、自定义函数

    函数的组成:

    ret_type fun_name(para1, * )
    {
     statement;//语句项
    }
    ret_type 返回类型
    fun_name 函数名
    para1    函数参数
    

    例子:

    #include <stdio.h>
    //get_max函数的设计
    int get_max(int x, int y)
    {
        if(x>y)
            return x;
        else
            return y;
    }
    int main()
    {
        int a = 10;
        int b = 20;
        int max = get_max(a, b);
        printf("max = %d\n", max);
        return 0;
    }

    ?用一个函数交换两个整型:

    #include <stdio.h>
    void Swap1(int x, int y)
    {
        int tmp = 0;
        tmp = x;
        x = y;
        y = tmp;
    }
    void Swap2(int* px, int* py)
    {
        int tmp = 0;
        tmp = *px;
        *px = *py;
        *py = tmp;
    }
    int main()
    {
        int a = 10;
        int b = 20;
        printf("a = %d b = %d\n", a, b);
        Swap1(a, b);
        //调用Swap1函数-传值调用
        Swap2(&a, &b);
        //调用Swap2函数-传址调用
        printf("a = %d b = %d\n", a, b);
        return 0;
    }

    三、函数的参数?

    实际参数(实参):

    真是传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。

    形式参数(形参)

    形式参数是指函数名后括号中的变量,因为形式参数只有在函数两用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。

    ?上面Swap1和Swap函数中的参数x. y. px. py都是形式参数。在mian函数中传给Swap1的num1,num2和传给Swap2函数的&num1,&num2是实际参数

    四、函数的调用:

    传值调用:

    函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。

    传址调用

    • 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
    • 这种传参方式可以让函数和函数外边的变量建立起正真的联系,也就是函数内部可以直接操 作函数外部的变量。

    注:传值函数需要的只是最终的一个结果值,而传址函数才需要的是对实参进行一些实际操作,如交换


    练习:

    1. 写一个函数可以判断一个数是不是素数

    #include <stdio.h>
    #include <math.h>
    //是素数返回1,不是素数返回0
    int is_prime(int n)
    {
        //2->n-1
        int j = 0;
        for(j=2; j<=sqrt(n); j++)
        {
            if(n%j == 0)
                return 0;
        }
        //if(j == n)
        return 1;
    }
    int main()
    {
        int i = 0;
        for(i=100; i<=200; i++)
        {
            //判断i是否为素数
            if(is_prime(i) == 1) 
                printf("%d ", i);
        }
        return 0;
    }

    2. 写一个函数判断一年是不是闰年

    #include <stdio.h>
    int is_leap_year(int y)
    {
        if((y%4 == 0 && y%100 != 0) || (y%400 == 0))
            return 1;
        else
            return 0;
    }
    
    int main()
    {
        int year = 0;
        for(year= 1000; year<=2000; year++)
        {
            //判断yaer是否为闰年
            if(1 == is_leap_year(year))
            {
                printf("%d ", year);
            }
        }
        return 0;
    }

    3. 写一个函数,实现一个整形有序数组的二分查找

    #include <stdio.h>
    //本质上arr是一个指针
    int binary_search(int arr[], int k, int sz)
    {
        //算法的实现
        int left = 0;
        int right = sz-1;
    
        while(left<=right)
        {
            int mid = (left+right)/2;//中间元素的下标
            if(arr[mid] < k)
            {
                left = mid-1;
            }
            else if(arr[mid] > k)
            {
                right = mid - 1;
            }
            else
            {
                return mid;
            }
        }
        return -1;
    }
    int main()
    {
        //二分查找
        //在一个有序数组中查找具体的某个数
        //如果找到了返回,这个书的下标。找不到的返回-1
        int arr[] = {1,2,3,4,5,6,7,8,9,10};
        int k = 7;
        int sz = sizeof(arr)/sizeof(arr[0]);
        //传递过去的是 arr[] 首元素的地址
        int ret = binary_search(arr, k, sz);
        if(ret == -1)
        {
            printf("找不到制定的数字\n");
        }
        else
        {
            printf("找到了,下标是:%d\n",ret);
        }
        return 0;
    }

    4. 写一个函数,每调用一次这个函数,就会将num的值增加1

    #include <stdio.h>
    void Add(int* p)
    {
    	(*p)++;
    }
    int main()
    {
    	int num = 0;
    	Add(&num);
    	printf("num = %d\n", num);
    	Add(&num);
    	printf("num = %d\n", num);
    	Add(&num);
    	printf("num = %d\n", num);
    	return 0;
    }

    五、函数的嵌套调用和链式访问

    函数和函数之间可以有机的组合的。

    嵌套调用

    #include <stdio.h>
    void new_line()
    {
        printf("hehe\n");
    }
    void three_line()
    {
        int i = 0;
        for(i=0; i<3; i++)
        {
            new_line();
        }
    }
    int main()
    {
        three_line();
        getchar();
        return 0;
    }

    ?链式访问

    把一个函数的返回值作为另外一个函数的参数。

    #include <stdio.h>
    #include <string.h>
    int main()
    {
        //1
        int len = 0;
        len = strlen("abc");
        printf("%d\n", len);
        //2
        printf("%d\n", strlen("abc"));
        getchar();
        return 0;
    }
    #include <stdio.h>
    int main()
    {
        printf("%d", printf("%d", printf("%d", 43))); //4321
        //打印顺序为从右括号最内的向左进行打印
        //1.首先打印出43,
        //2.因为43是2位数所以返回值为2,第二次打印2在43的后面,即此时为432
        //3.又因为2是1位数所以返回值为1,第三次1打印在2的后面,所以最后打印结果为4321
        return 0;
    }

    六、函数的声明和定义

    函数声明

    • 告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,无关紧要
    • ?函数的声明一般出现在函数的使用之前(要满足先声明后使用)
    • ?函数的声明一般要放在头文件中的

    函数定义

    函数的定义是指函数的具体实现,交待函数的功能实现

    头文件.h放函数声明,源文件.c放函数的定义,在配合函数调用多个文件运行

    #ifndef -if not define

    #define

    #endif

    七、函数递归

    递归函数:一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法。

    递归函数的主要思考方式在于——把大事化小

    递归的两个必要条件:

    • 存在限制条件,当满足这个限制条件的时候,递归便不再继续。
    • 每次递归调用之后越来越接近这个限制条件。

    递归常见错误:栈溢出


    练习

    (1)接受一个整型值(无符号),按照顺序打印它的每一位。 例如: 输入:1234,输出 1 2 3 4

    #include <stdio.h>
    void print(int n)
    {
        if(n>9)
        {
            print(n/10);
        }
        printf("%d ", n%10);
    }
    
    int main()
    {
        unsigned int num = 0;
        scanf("%d", &num);
        print(num);
        return 0;
    }
    

    (2)编写函数:不允许创建临时变量,求字符串的长度

    while写法:

    #include <stdio.h>
    #include <string.h>
    int my_strlen(char* str)
    //str是指针变量
    {
        int count = 0;
        while(*str != '\0')
        {
            count++;
            str++;
            //指针+1即指针指向下一个地址
        }
        return count;
    }
    int main()
    {
        char arr[] = "bit";
        int len = my_strlen(arr);//arr是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
        printf("len = %d", len);
        return 0;
    }

    递归写法:

    #include <stdio.h>
    #include <string.h>
    int my_strlen(char* str)
    {
        if(*str != '\0')
            return 1+my_strlen(str+1);
        else
            return 0;
    }
    int main()
    {
        char arr[] = "bit";
        int len = my_strlen(arr);//arr是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
        printf("len = %d", len);
        getchar();
        return 0;
    }

    递归与迭代

    (3)求n的阶乘。(不考虑溢出)

    while写法:

    #include <stdio.h>
    int Fac1(int n)
    {
        int i = 0;
        int ret = 1;
        for(i=1; i<=n; i++)
        {
            ret *= i;
        }
        return ret;
    }
    int main()
    {
        //求n的阶乘
        int n = 0;
        int ret = 0;
        scanf("%d", &n);
        ret = Fac1(n);//循环的方式
        printf("%d\n", ret);
        return 0;
    }

    递归写法:

    int Fac2(int n)
    {
        if(n<=1)
            return 1;
        else
            return n*Fac2(n-1);
    }
    int main()
    {
        //求n的阶乘
        int n = 0;
        int ret = 0;
        scanf("%d", &n);
        ret = Fac2(n);//循环的方式
        printf("%d\n", ret);
        return 0;
    }

    (4)求第n个斐波那契数。(不考虑溢出)

    递归写法:

    #include <stdio.h>
    #include <stdlib.h>
    int Fib(int n)
    {
        if(n<=2)
            return 1;
        else
            return Fib(n-1)+Fib(n-2);
    }
    int main()
    {
        int n = 0;
        int ret = 0;
        scanf("%d", &n);
        //TDD - 测试驱动开发
        ret = Fib(n);
        printf("ret = %d\n", ret);
        return 0;
    }

    while循环:

    #include <stdio.h>
    int count = 0;
    int Fib(int n)
    {
        int a = 1;
        int b = 1;
        int c = 1;
        while(n>2)
        {
            c = a + b;
            a = b;
            b = c;
            n--;
        }
        return c;
    }
    int main()
    {
        int n = 0;
        int ret = 0;
        scanf("%d", &n);
        ret = Fib(n);
        printf("ret = %d\n", ret);
        return 0;
    }
    

    cs