【C语言】函数详解第一期,函数基础

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 本文讲解:C语言函数详解第一期,函数基础

 

拳击哥提示:闲余时间记得锻炼身体哦 🤼


目录

1、什么是函数?

2、函数的分类

2.1、库函数

2.2、库函数的使用方法

2.3、自定义函数

3、函数的参数

3.1、实参

3.2、形参

4、函数的调用

4.1、传值调用

4.2、传址调用

4.3、代码的调试

5、题目练习

5.1、写一个函数判断一个数是不是素数(解析)

5.2、写一个函数判断一个数是不是闰年(解析)

5.3、写一个函数,实现一个有序数组的二分查找(解析)

5.4、写一个函数,输入一个数n,每调用一次,n的值增加1,调用10次(解析)

5.5、实现猜数字小程序(随机生成1-100内的数字)


1、什么是函数?

    • 在数学中我们认为函数就是用来更快解决数学问题的,那么C语言中函数可跟我们的数学函数不一样,无论是从定义还是用法都有极大的不同,但归根结底它们都是用来更方便的去解决生活中的问题的。
    • 在C语言中,函数是将一个标识符(函数名)关联到一条复合语句(函数体)的C语言构造。每个 C 程序都从主函数main开始执行,也从它或者调用其他用户自定义函数或库函数终止。我们自定义的函数它负责某项特定的任务,相对于主函数里面其他的代码更具有独立性。一般都有参数返回值。而库函数里面的函数它们能实现更多的封装和细节,通常我们通过引入各个库函数的头文件来实现该函数的功能。

    2、函数的分类

    1.库函数

    2.自定义函数


    2.1、库函数

    库函数,顾名思义就是C语言库中专门提供的函数,专业名词叫基础库。我们程序员都可以通过调用这些库函数来实现自己的一个意图。什么时候我们会用到呢?我来举两个例子:

    1.当我们刚开始学习C语言想要将Hello World打印到黑框框上,这时候我们用到一个printf格式化输出函数,来实现打印。那么printf对应的头文件自然是#include<stdio.h>

    image.gif编辑


    2.当我们想要比较两个字符串大小时候,我们用赋值(==)或大小于(>、<)是比较不出来的,这时候我们用到一个strcmp函数,来实现比较。那么strcmp对应的自然是#include<string.h>

    image.gif编辑


    上面两个函数中第一个函数printf是我们编写程序时最常用的函数之一,第二个函数strcmp它不是那么常用,但是为了实现两个字符串的比较我们可以应用。所以为了我们编程的可移植性和编程的效率提供,C语言基础库中提供了一些库函数,方便我们程序员使用。他们大概分为哪些呢:

      • 输入/输出支持函数intput、output、scanf、printf、getchar、putchar等等
      • 字符/字符串操作函数strlen、strcmp等等
      • 数学函数sqrt、pow等等
      • 内存操作函数memcpy、memmove、memset等等
      • 日期和时间工具函数time等等
      • 其他库函数

      2.2、库函数的使用方法

      我们想要记住所有的库函数是不可行的,因此我们可以参考C语言手册:

      C语言参考手册英语版

      C语言参考手册中文版

      注意:以上网站非商业广告纯学习用,大家可放心点击!!!


      2.3、自定义函数

      🤼函数的组成部分是什么呢,如下图:

      image.gif编辑

        • 语句项里面的类容是各种代码组成的功能
        • 返回类型分为有返回值和无返回值
        • 自定义函数名尽量采用大驼峰的形式RetType或每个单词之间加下划线is_ret_type
        • 自定义函数的参数类型跟主函数类型保持一致

        🤼下面程序中,函数的返回类型为void,函数的参数也是void。说明,这个函数无返回任何值。只是调用这个函数。

        #include<stdio.h>
        void Test(void)
        {
          printf("Hello World\n");
        }
        int main()
        {
          Test();
          return 0;
        }

        image.gif

        结果为:Hello World


        🤼‍♀️再看一个程序输入一个数输出这个数加1:

        #include<stdio.h>
        int Test(int x)
        {
          x = x + 1;
          return x;
        }
        int main()
        {
          int a = 0;
          scanf("%d", &a);
          printf("%d\n",Test(a));
          return 0;
        }

        image.gif

        输入:5

        输出:6

        上述程序中,Test的返回类型int,函数参数也是int。说明函数有返回值并且返回的类型是int,传来的类型也是int


        为什么要有自定义函数?上一个大标题我讲到了,C语言提供了大量的库函数。这些库函数的用法都已经固定了,那么如果我们想要做点新的东西怎么办呢我们可以自定义函数,函数里面来实现我们所想的。比如我要写一个小游戏,小游戏里面得有一个菜单,得有一个实现游戏的程序。那么我们可以自定义一个名为CaiDan()的函数和一个名为Game()的函数,这两个函数里面实现的就是这个小游戏的两个部分。我们可以在主函数main()函数里面调用这两个自定义的函数。

        image.gif编辑

        上面程序中主函数main里面调用了两个自定义函数CaiDan()和Game(),两个函数的类型就是voidvoid就是无返回值。()里面什么都不填说明什么都不传过来也就是无传参。


        3、函数的参数

        3.1、实参

          • 真实传给函数的参数
          • 实参可以是常量、变量、表达式、函数等
          • 形参在调用实参时,它们的类型要保持一致,而且要有确切的值

          下面四个程序依次列出了,实参的几个常用类型:

          //当实参是常量时候
          #include<stdio.h>
          int get_max(int x,int y)
          {
            return(x > y ? x : y);
          }
          int main()
          {
            printf("%d\n", get_max(5, 3));
              return 0;
          }
          //当实参是变量时
          #include<stdio.h>
          int get_max(int x,int y)
          {
            return(x > y ? x : y);
          }
          int main()
          {
            int a = 0;
            int b = 0;
            scanf("%d %d", &a, &b);
            printf("%d\n", get_max(a,b));
            return 0;
          }
          //当时参是表达式时
          #include<stdio.h>
          int ChuanCan(int x)
          {
            return x;
          }
          int main()
          {
            int a = 0;
            int b = 0;
            scanf("%d %d", &a, &b);
            printf("%d\n", ChuanCan(a+b));
            return 0;
          }
          //当实参是函数时
          int get_max(int x,int y)
          {
            return(x > y ? x : y);
          }
          int main()
          {
            printf("%d\n", get_max(get_max(5, 3), 10));
            return 0;
          }

          image.gif

          上述程序分别是实参为常量、变量、表达式、函数的四种情况,您可以复制程序。打印一下,体验四种不同的情况。


          3.2、形参

            • 形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有
            • 形式的参数,我们可以认为它并不真实存在内存中的参数,就像我们脑中的一个想法一样。我不用它,那么这个想法并不真实,它只是形式的存在我的脑海中。只有我用到了这个想法它才算是真实的。形参也是一样的,你只有调用它,那么它才会在内存中开辟一道空间否则它就单单是几行代码而已。我们这样理解:形式参数是实际参数在内存中的若干份临时拷贝

            4、函数的调用

            4.1、传值调用

            函数的实参的形参分别占用不同的内存块,我们对形参的修改是不会影响到实参的。

            //方法一
            #include<stdio.h>
            int Max(int x, int y)
            {
              if (x > y)
              {
                return x;
              }
              return y;
            }
            int main()
            {
              int a = 0;
              int b = 0;
              scanf("%d %d", &a, &b);
              int max=Max(a, b);
              printf("%d", max);
              return 0;
            }
            ----------------------------
            //方法二
            #include<stdio.h>
            int Max(int x, int y)
            {
              return (x > y ? x : y); 
            }
            int main()
            {
              int a = 0;
              int b = 0;
              scanf("%d %d", &a, &b);
              printf("%d", Max(a, b));
                return 0;
            }

            image.gif

            以上两个程序的功能是一样的

            输入:10 9 输出:10

            输入:9 10 输出:10


            🤼第一个程序图解:

            image.gif编辑


            🤼‍♀️第二个程序图解:

            image.gif编辑

            那么上面两个程序中,我们自定义了一个名为Max的函数,我们通过主函数来调用它的功能,实现了比较两数的大小然后返回一个最大值给主函数


            4.2、传址调用

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

              🤼有一程序,用函数实现输入两个数并交换这两个数:

              #include<stdio.h>
              void Swap(int x, int y)
              {
                int tmp = x;
                x = y;
                y = tmp;
              }
              int main()
              {
                int a = 0;
                int b = 0;
                scanf("%d %d", &a, &b);
                printf("交换前:a=%d b=%d\n", a, b);
                Swap(a, b);
                printf("交换后:a=%d b=%d\n", a, b);
                return 0;
              }

              image.gif

              输入:5 6

              输出:交换前:a=5,b=6

                        交换后:a=5,b=6


              我们可以看到,它们并没有交换彼此。为什么会这样呢,那是因为Swap函数里面交换的仅仅是形参里面的x和y的值,也就是实参的临时拷贝的那两块地址里面的值,而实参里的a和b地址里面的值并未发生改变还是原来的值,所以传回的值还是5和6。我们可以借助下图理解:

              image.gif编辑


              我们可以这样改:

              #include<stdio.h>
              void Swap(int* x, int* y)
              {
                int tmp = *x;
                *x = *y;
                *y = tmp;
              }
              int main()
              {
                int a = 0;
                int b = 0;
                scanf("%d %d", &a, &b);
                printf("交换前:a=%d b=%d\n", a, b);
                Swap(&a, &b);
                printf("交换后:a=%d b=%d\n", a, b);
                return 0;
              }

              image.gif

              输入:5 6

              输出:交换前:a=5,b=6

                        交换后:a=6,b=5


              上面说到了,形参只是实参的一块临时拷贝。那么如果我把实参的地址给形参了,那么你临时拷贝的地址是不是就与实参的地址一致了,那交换的值也就一致了。

              image.gif编辑


              那么上述程序范围类型是void也就是无返回值,它们只是修改了内存中值。


              4.3、代码的调试

              下面一个截图我们可以很清楚的观察到,实参传值给形参后它们在内存中存放的地址是不同的。image.gif编辑

              下面截图中,实参把地址传给形参后,它们的地址是一致的,所以最后实现了交换。

              image.gif编辑


               那么如何监视程序呢,下面我就来介绍:


              第一步:按F10打开调试当程序左方出现箭头证明可以开始调试

              image.gif编辑


              第二步:打开调试窗口,任选一个监视。

              image.gif编辑


              第三步:按F10代码会往下走,你可以在监视窗口输入你想监视的内容。注意:监视窗口里面的内容是要输入的,你输入a则输出a的值,你输入&a则输出a的地址。

              image.gif编辑

               


              第四步:当你箭头指向scanf时你按F10然后输入a和b的值,a和b的值会自动变成你所输入的值。

              image.gif编辑

               


              第五步:当箭头来到Swap函数的时候按F11,自动跳转到函数里面

              image.gif编辑 


              第六步:分别在监视窗口输入x,y,tmp,以便观察它们的变化

              image.gif编辑


              正在发生变化

              image.gif编辑


              最后一步停止调试

              image.gif编辑

              以上就是监视窗口的六个步骤,耐下心来一步步实现,相信你能成为一个调试高手!!!


              5、题目练习

              5.1、写一个函数判断一个数是不是素数(解析)

              #include<stdio.h>
              #include<math.h>
              int PanDuan(int n)
              {
                for (int i = 2; i <= sqrt(n); i++)
                {
                  if (n % i == 0)
                  {
                    return 0;
                  }
                }
                return 1;
              }
              int main()
              {
                int n = 0;
                scanf("%d", &n);
                if (PanDuan(n))
                {
                  printf("这是一个素数\n");
                }
                else
                {
                  printf("这不是一个素数\n");
                }
                return 0;
              }

              image.gif

              输入:9输出:这是一个素数

              解析:

              素数满足条件是除1和本身之外都没有任何因子被它整除,上述程序中主函数传参到形参里面PanDan函数里面主要做的是从2开始直到n的开方数依次做为除数用传过去的参数,n依次从2除到n的开方数。如果能整除说明该数不是素数返回0,如果不整除则返回1。返回的值由if判断语句来执行,判断为真输出这是一个素数,否则这不是一个素质。


              5.2、写一个函数判断一个数是不是闰年(解析)

              #include<stdio.h>
              int LeapYear(int n)
              {
                if (n % 400 == 0 || n % 4 == 0 && n % 100 != 0)
                {
                  return 1;
                }
                return 0;
              }
              int main()
              {
                int n = 0;
                scanf("%d", &n);
                if (LeapYear(n))
                {
                  printf("这是一个闰年\n");
                }
                else
                {
                  printf("这不是一个闰年\n");
                }
                  return 0;
              }

              image.gif

              输入:2000输出:这是一个闰年

              解析:

              首先闰年的满足条件为:能被400整除或能被4整除但不能被100整除,这个程序跟第一个程序类似,都是传一个参数过去传一个参数回来,那么LeapYear里面的功能主要是判断n是否为闰年如果是返回1,否则返回0。返回的值再交给if语句来判断满足1则输出这是一个闰年否则这不是一个闰年。


              5.3、写一个函数,实现一个有序数组的二分查找(解析)

              #include<stdio.h>
              int Find(int arr2[],int key2,int str)
              {
                int left = 0;
                int right = str-1;
                int mid = 0;
                while (left<=right)
                {
                  mid = (left + right) / 2;
                  if (arr2[mid] > key2)
                  {
                    right = mid - 1;
                  }
                  else if (arr2[mid] < key2)
                  {
                    left = mid + 1;
                  }
                  else
                  {
                    return mid;
                  }
                }
                return -1;
              }
              int main()
              {
                int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
                int key1 = 0;
                scanf("%d", &key1);
                int str1 = sizeof(arr1);
                int rat = Find(arr1, key1,str1);
                if (rat==-1)
                {
                  printf("没有这个数\n");
                }
                else
                {
                  printf("有这个数,下标为%d\n", rat);
                }
                return 0;
              }

              image.gif

              解析:

              首先我们主函数要初始化一个有序数组,然后输入一个数,求出这个数组的元素个数,分别把数组,输入的数,数组元素个数传给形参。Find拿到这三个值后。设置一个左下标left为最左的下标0,设置一个右下标right为最右的下标数组元素的个数-1,和一个中间下标mid。然后进入循环,循环里就是进行查找。

              第一种情况:输入的数比中间那个数大,假设我输入的key1为8,传给key2。下图为初始状态

              image.gif编辑


              第一步、arr2[mid]<key2,就使left=mid+1,此时left=5,right=9,mid=7。

              image.gif编辑


              第二步、 arr2[mid]=8,返回mid给主函数并结束Find函数里面的程序,传回mid值给主函数。然后输出:有这个数,下标为:7。


              第二种情况,输入的数比中间的数小,假设我输入的数key1是3传给key2,下图为初始状态

              image.gif编辑


              第一步、 arr2[mid]>key2,就使right=mid-1,此时left=0,mid=1,right=3。

              image.gif编辑


              第二步、arr2[mid] <key2,就使left=mid+1,此时left=2,mid=2,right=3。

              image.gif编辑

              第三步、arr2[mid]=3,返回mid给主函数并结束Find函数里面的程序,传回mid值给主函数。然后输出:有这个数,下标为:2。


              5.4、写一个函数,输入一个数n,每调用一次,n的值增加1,调用10次(解析)

              #include<stdio.h>
              int BigOne(n)
              {
                return (n + 1);
              }
              int main()
              {
                int n = 0;
                scanf("%d", &n);
                for (int i = 0; i < 10; i++)
                {
                  n=BigOne(n);
                  printf("%d ", n);
                }
                return 0;
              }

              image.gif

              输入:5输出:6 7 8 9 10 11 12 13 14 15

              解析:

              这个函数就比较简单,输入一个数,把这个数传给形参,主函数里面for语句控制传参十次,BigOne函数里面每次传参过来,返回参值加1 。然后输出每次一传回来的参值。


              5.5、实现猜数字小程序(随机生成1-100内的数字)

              #include<stdio.h>
              #include<stdlib.h>//rand()函数、cls清理屏幕函数都用此头文件
              #include<time.h>//time时间戳
              void caidan()//这是一个菜单
              {
                printf("*********************\n");
                printf("*****  开始:1  *****\n");
                printf("*****  退出:0  *****\n");
                printf("*********************\n");
              }
              void game()//这是游戏函数
              {
                int rat = rand()%100+1;
                int num = 0;
                while (1)
                {
                  printf("请输入你的数字:>");
                  scanf("%d", &num);
                  if (rat < num)
                  {
                    printf("你猜大了\n");
                  }
                  else if (rat >num)
                  {
                    printf("你猜小了\n");
                  }
                  else
                  {
                    printf("恭喜你,你猜对了\n");
                    break;
                  }
                }
                system("cls");
              }
              int main()
              {
                int n = 0;
                srand((unsigned)time(NULL));
                do
                {
                  caidan();
                  printf("请选择:>");
                  scanf("%d", &n);
                  switch (n)
                  {
                  case 0:printf("你已退出游戏\n"); break;
                  case 1:game(); break;
                  default:printf("请输入正确的数字\n");break;
                  }
                } while (n);
                return 0;
              }

              image.gif

              解析点击此链接


              那么本期博客就到这里了,感谢大家的耐心观看,如有收获请三连,万分感谢!!!

              image.gif编辑

              每次学习都要像打拳一样全神贯注,这样才不会被对手(困难)击倒

              相关文章
              |
              1天前
              |
              算法 C语言
              【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
              本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
              25 15
              |
              1天前
              |
              C语言
              【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
              本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
              36 24
              |
              1天前
              |
              存储 算法 C语言
              【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
              本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
              36 23
              |
              1月前
              |
              存储 C语言 开发者
              【C语言】字符串操作函数详解
              这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
              72 10
              |
              1月前
              |
              存储 程序员 C语言
              【C语言】文件操作函数详解
              C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
              58 9
              |
              1月前
              |
              存储 Unix Serverless
              【C语言】常用函数汇总表
              本文总结了C语言中常用的函数,涵盖输入/输出、字符串操作、内存管理、数学运算、时间处理、文件操作及布尔类型等多个方面。每类函数均以表格形式列出其功能和使用示例,便于快速查阅和学习。通过综合示例代码,展示了这些函数的实际应用,帮助读者更好地理解和掌握C语言的基本功能和标准库函数的使用方法。感谢阅读,希望对你有所帮助!
              45 8
              |
              1月前
              |
              C语言 开发者
              【C语言】数学函数详解
              在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
              55 6
              |
              1月前
              |
              存储 C语言
              【C语言】输入/输出函数详解
              在C语言中,输入/输出操作是通过标准库函数来实现的。这些函数分为两类:标准输入输出函数和文件输入输出函数。
              311 6
              |
              1月前
              |
              存储 缓存 算法
              【C语言】内存管理函数详细讲解
              在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
              68 6
              |
              1月前
              |
              C语言 开发者
              【C语言】断言函数 -《深入解析C语言调试利器 !》
              断言(assert)是一种调试工具,用于在程序运行时检查某些条件是否成立。如果条件不成立,断言会触发错误,并通常会终止程序的执行。断言有助于在开发和测试阶段捕捉逻辑错误。
              48 5