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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 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++
              C语言 之 内存函数
              C语言 之 内存函数
              34 3
              |
              7天前
              |
              C语言
              c语言调用的函数的声明
              被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
              23 6
              |
              27天前
              |
              存储 缓存 C语言
              【c语言】简单的算术操作符、输入输出函数
              本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
              34 10
              |
              21天前
              |
              存储 算法 程序员
              C语言:库函数
              C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
              |
              26天前
              |
              机器学习/深度学习 C语言
              【c语言】一篇文章搞懂函数递归
              本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
              53 7
              |
              26天前
              |
              存储 编译器 程序员
              【c语言】函数
              本文介绍了C语言中函数的基本概念,包括库函数和自定义函数的定义、使用及示例。库函数如`printf`和`scanf`,通过包含相应的头文件即可使用。自定义函数需指定返回类型、函数名、形式参数等。文中还探讨了函数的调用、形参与实参的区别、return语句的用法、函数嵌套调用、链式访问以及static关键字对变量和函数的影响,强调了static如何改变变量的生命周期和作用域,以及函数的可见性。
              29 4
              |
              1月前
              |
              存储 编译器 C语言
              C语言函数的定义与函数的声明的区别
              C语言中,函数的定义包含函数的实现,即具体执行的代码块;而函数的声明仅描述函数的名称、返回类型和参数列表,用于告知编译器函数的存在,但不包含实现细节。声明通常放在头文件中,定义则在源文件中。
              |
              1月前
              |
              C语言
              c语言回顾-函数递归(上)
              c语言回顾-函数递归(上)
              32 2
              |
              1月前
              |
              Java 编译器 C语言
              【一步一步了解Java系列】:Java中的方法对标C语言中的函数
              【一步一步了解Java系列】:Java中的方法对标C语言中的函数
              22 3
              |
              1月前
              |
              存储 程序员 编译器
              C语言——动态内存管理与内存操作函数
              C语言——动态内存管理与内存操作函数