news 2026/7/13 4:13:57

一篇文章带你吃透函数

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
一篇文章带你吃透函数

函数,简言之,就是实现某种特定功能的一段代码。函数分为库函数和自定义函数。函数具有以下特点:1.封装性。 2.复用性。


一、 库函数

库函数是一些已经配置好功能的一些函数,根据自己的现实需要来选择库函数。因为库函数是在标准头文件中声明的,所以在使用库函数时应该加上对应的头文件。否则程序运行时会不认得这函数。

库函数的学习工具:https://legacy.cplusplus.com/

二、 自定义函数

库函数的功能不能满足功能的实现,所以就需要自己通过写代码来实现这个功能,将它包装成函数,这样的函数就叫做自定义函数。

2.1 结构

ret_type fun_name(形式参数)//函数头 { …………;//(函数体) }
  • 函数头,包括函数名,参数,返回类型。
  1. 函数名:尽量有意义。
  2. 参数:这里的参数叫做形式参数。在调用函数时,传过去的参数叫做实参。
  3. 返回类型:根据函数返回的数据类型来确定函数返回类型。函数返回类型不写的话,会默认为int 类型。
  • 函数体:就是自己实现功能的代码部分。

函数体里面有一个return语句:用来退出函数并返回数据。

  1. return 语句后面可以是表达式,也可以是函数值。
  2. 如果函数的返回类型为void类型(不返回任何参数),则无需return 语句,也可以直接写为 "return ;"
  3. 在if-else语句中应保证每种情况都有返回。

红框框圈住的是我们自定义函数,那里的参数为形参。蓝框框圈住的是函数调用部分(即我们要使用这个函数),括号里的是实参(就是我们传给数据),然后形参收到数据之后用这些数据进行计算。

要保证函数的形参和实参数值和个数要相对应。

2.2 实参和形参的关系

这是两形参的地址。

这是两实参的地址。

可以发现实参和形参虽然数值相同,但是地址并不同。

结论

  1. 形参是实参的一份临时拷贝。(为啥叫临时拷贝呢?因为当函数调用结束后就会销毁形参)
  2. 形参的改变并不会影响是实参的改变。

2.3、 数组作为函数参数

  • 数组作为参数,定义数组是什么类型,那么参数就是什么类型。
  • 参中可以不写数组大小,只写框框。
  • 实参中传数组应该只写数组名(数组传参实际上是地址传参),因此形参不会创建新数组,形参和实参使用的是同一个数组。
  • 二维数组类似,只不过二维数组行可以省略,但是列不可以省略。

练习:数组内容全部置为-1,再打印数组。

#include <stdio.h> void arr_value(int arr[10], int len) { int i = 0; for (i = 0; i < len; i++) { arr[i] = -1; } } void print_arr(int arr[], int len) { for (int i = 0; i < len; i++) { printf("%d ", arr[i]); } } int main() { int arr1[10] = {1}; arr_value(arr1, 10); print_arr(arr1, 10); return 0; }

三、 函数的嵌套调用

函数嵌套就是函数里又再次调用了另一个函数。

练习:计算某年某月有多少天?

#include <stdio.h> #include <stdbool.h> bool is_leap_year(int year) { if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) { return true; } else { return false; } } int get_days(int year,int month) { int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; if (month == 2) { if (is_leap_year(year)) { return 29; } else { return 28; } } else { return days[month]; } } int main() { int month = 0; int year = 0; scanf("%d %d",&year, &month); int days=get_days(year,month); printf("%d\n", days); return 0; }

四、 函数的链式访问

链式访问就是一个函数的返回值作为另一个函数的参数。

#include <stdio.h> #include <string.h> int main() { char arr[] = "abcdef"; printf("%zu\n", strlen(arr)); return 0; }

五、 函数的声明和定义

5.1 单个文件

  • 函数调用:使用函数的过程(相当于用函数的窗口)。
  • 函数定义:就是自己定义函数头(函数名,参数,返回类型)以及函数体。
  • 函数声明:当函数调用时,程序会从函数调用的地方向上寻找这个函数,如果我们将函数写到下方,那么就会找不到,所以就需要函数声明,告诉程序我有这个函数。函数声明中的参数可以只写数据类型,省略变量。

5.2 多个文件

当我们在做一个项目时,我们往往会使用多个文件,一个是用来函数声明的头文件(.h),一个是用来函数定义的文件(.c),另一个是用来函数调用的测试文件(.c)。

但是在函数调用前要加上头文件如:“Add.h”,这是包含自己创建的头文件。而< >是库函数的头文件,如:<stdio.h>。

5.3 static 与 extern

5.3.1 作用域与生命周期

作用域:创建的变量可用的代码范围;生命周期:变量从创建到被销毁的时间段。

  • 局部变量:作用域:仅能在变量所被创建的代码块(用{ }括住的代码)中有效,一旦超出,程序将显示未定义。生命周期:进入作用域局部变量被创建,生命周期开始,出去作用域生命周期结束。
  • 全局变量:作用域:整个工程,但是要记住用extern声明一下(不在同一个文件)。生命周期:程序开始,生命周期开始;程序结束,生命周期结束。

5.3 extern

extern是用来声明外部符号的。

5.3.3 static

1.修饰局部变量

//代码1 #include <stdio.h> void test() { int i = 0; i++; printf("%d ", i);//1 1 1 1 1 } int main() { int i = 0; for(i=0; i<5; i++) { test(); } return 0; } //代码2 #include <stdio.h> void test() { //static修饰局部变量 static int i = 0; i++; printf("%d ", i); //1 2 3 4 5 } int main() { int i = 0; for(i=0; i<5; i++) { test(); } return 0; }

内存中用栈区,堆区以及静态区。

  • 栈区:用来存放局部变量和函数参数。
  • 堆区:用来动态内存申请。
  • 静态区:用来存放全局变量和静态变量。

当用static来修饰局部变量,局部变量称为静态变量,进入静态区,调用函数,函数销毁但是静态变量并不销毁,仍保持不变,并且在下一次调用时继续接着上一次的值进行计算。

结论:static修饰局部变量,作用域不变,延长生命周期,存储类型改变:栈区->静态区。

2.修饰全局变量

结论:全局变量原本具有外部链接属性,即可以用extern声明就可以在同工程的其他文件进行使用。但是,全局变量一旦被static修饰,外部链接属性就会变为内部,即使有声明也不能使用。只能在本源文件中使用。

3.修饰函数

结论:与全局变量类似,函数也具有外部链接属性。函数一旦被static修饰就仅能在本源文件中使用。

六、 函数递归

函数递归是指函数自己调用自己。递归,递推和回归。

递归的思想就是大事化小的思想,将大问题逐渐拆解成一个个小问题。

6.1 递归的限制条件

  1. 递归存在限制条件,当满足限制条件时,递推停止,开始回归。
  2. 每一次递归都在不断地接近限制条件。

6.2 递归举例

练习1:求正整数n的阶乘。

思路:n!=n*(n-1)!(n>=1); n!=1(n=0时)

Fact(n)=n*Fact(n-1);0!=1。

#include <stdio.h> int Fact(int n) { if (n == 0) { return 1; } else { return n * Fact(n - 1); } } int main() { int input = 0; scanf("%d", &input); printf("%d\n",Fact(input)); return 0; }

练习2:顺序打印一个整数的每一位。

比如:输入:1234;输出:1 2 3 4

输入:520; 输出:5 2 0

分析:我们如果是逆序打印的话,只需要%10,取到最后一位,/10删去最后一位。运用大事化小的思想来解决,我们最容易取出最后一位,可是,要求先打印第一位,那么就不断/10,直到成为个位数,就可以%10,打印。

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

6.3 递归与迭代

练习1中既可以用递归写,也可以用迭代写。

//迭代 unsigned int Fact(int n) { int sum = 1; for (int i = 1; i <=n; i++) { sum = sum * i; } return sum; } int main() { int input = 0; scanf("%d", &input); printf("%u\n" ,Fact(input)); return 0; }

上述例子中由于递归可能会出现栈溢出,而迭代没有栈溢出的风险,写起来逻辑并不复杂,效率更高,所以练习1优先选迭代。

练习3:斐波那契数列

分析:n=1,2时,Fib(n)=1;n>2时,Fib(n)=Fib(n-1)+Fib(n-2)。、

//递归 #include <stdio.h> unsigned int Fib(int n) { if (n <= 2) { return 1; } return Fib(n - 1) + Fib(n - 2); } int main() { int input = 0; scanf("%d", &input); printf("%u\n", Fib(input)); return 0; } //迭代 #include <stdio.h> unsigned int Fib(int n) { int a = 1; int b = 1; int c = 1; while (n > 2) { a = b; b = c; c = a + b; n--; } return c; } int main() { int input = 0; scanf("%d", &input); printf("%u\n", Fib(input)); return 0; }

递归中有好多数都被重复算多次,造成冗余,运行效率较低,所以这个练习迭代较为好。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 4:09:26

国内开发者快速上手Codex智能体:两步接入与完整实战指南

最近在AI开发圈里&#xff0c;Codex智能体确实火得不行&#xff0c;但很多国内开发者一看到"OpenAI"、"API Key"这些词就头疼——网络限制、付费流程、接口调用复杂度都是实实在在的门槛。不过好消息是&#xff0c;现在通过国内平台接入Codex已经变得非常简…

作者头像 李华
网站建设 2026/7/13 4:09:26

PLC通信与故障处理06-DeviceNet现场总线——CAN总线在工业领域的二次元,一根五芯线「吃」遍32个IO模块?聊聊DeviceNet这头工业驴

想象一下&#xff1a;你走进一间数控加工中心&#xff0c;32个I/O模块像多米诺骨牌一样排开&#xff0c;每块之间的距离超过100米&#xff0c;而连接它们的——只是一根五芯电缆。 没有复杂的交换机拓扑&#xff0c;没有TCP/IP三层协议栈&#xff0c;没有动辄几百页的设备配置…

作者头像 李华
网站建设 2026/7/13 4:09:24

Claude Mythos:AI驱动的零日漏洞挖掘与系统级安全跃迁

1. 项目概述&#xff1a;一场静默却震耳欲聋的AI能力跃迁 这周&#xff0c;整个AI安全圈没有爆炸性新闻稿&#xff0c;没有铺天盖地的发布会直播&#xff0c;只有一份措辞克制、数据密集的系统卡片&#xff08;System Card&#xff09;和一份由英国AI安全研究所&#xff08;AIS…

作者头像 李华
网站建设 2026/7/13 4:08:44

YOLO与RT-DETR目标检测框架在SCI论文中的创新应用策略

对于想要在SCI 3/4区发表论文的研究者来说&#xff0c;YOLO和RT-DETR这两个目标检测框架提供了很好的研究切入点。关键不在于简单地应用这些模型&#xff0c;而是要在现有基础上做出有意义的创新。从实际研究经验看&#xff0c;SCI 3/4区期刊更看重研究的实用性和创新点的明确性…

作者头像 李华
网站建设 2026/7/13 4:07:12

C++ 游戏开发实战:从 300 行代码解析双人实时对战程序的 3 个核心模块

C 游戏开发实战&#xff1a;从 300 行代码解析双人实时对战程序的 3 个核心模块在游戏开发领域&#xff0c;C 因其高性能和底层控制能力一直是主流选择。本文将带你深入一个精简但功能完整的双人对战游戏实现&#xff0c;通过模块化重构揭示游戏开发的核心架构。无论你是刚接触…

作者头像 李华
网站建设 2026/7/13 4:07:05

影刀RPA社区版实战指南:从零搭建办公自动化流程

如果你每天要花大量时间在重复的电脑操作上——比如从不同系统导出数据、批量处理Excel报表、定时发送邮件&#xff0c;或者在不同软件间手动切换复制粘贴&#xff0c;那么这篇文章就是为你准备的。影刀RPA正在改变传统办公自动化的实现方式&#xff0c;但很多人对它的认知还停…

作者头像 李华