首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C语言函数入门到精通】:跟着7个目录走,学会写可复用的代码模块

【C语言函数入门到精通】:跟着7个目录走,学会写可复用的代码模块

作者头像
用户11987028
发布2026-01-15 14:00:50
发布2026-01-15 14:00:50
1100
举报

-

在这里插入图片描述
在这里插入图片描述

🎬 个人主页秦苒&专栏传送门:《C语言

🍀指尖燃热血,代码铸锋芒;以信仰破局,向顶峰生长


🎬秦苒&的简介:

在这里插入图片描述
在这里插入图片描述

提示:以下是本篇文章正文内容,下面案例可供参考

一、函数的概念

数学中有函数,C语言当然也有函数了! 数学中有y=kx+b,其中k和b都是常数,给任意的x就得到一个y值。 C语言中的函数(也叫子程序)就是完成某项特定的一小段代码,每一小段代码(配合头文件、数据结构等)组成一个完整的项目,就像每一个小积木最后搭建成高楼大厦一样。

在这里插入图片描述
在这里插入图片描述

如果一个函数如果能完成某项特定任务的话,那么函数也是可以复用的。这样可以更好的 提升我们开发软件的效率。

1.库函数

a.标准库和头文件

我们之前学到的printf,scanf都是库函数,库函数也是一种函数,只不过这些函数是被规定好的,我们可以直接使用。各种编译器的标准库提供了一系列库函数,这些函数跟据功能进行划分,在不同的头文件中进行声明。 想了解更多库函数相关头文件的寻宝者请点击如下链接: https://zh.cppreference.com/w/c/header

b.库函数的使用方法

C/C++官⽅的链接:https://zh.cppreference.com/w/c/header cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/

这里我给大家举例说明:(sqrt)

代码语言:javascript
复制
double sqrt(double x);

其中 sqrt 是函数名 x是函数参数——调用sqrt函数需要传递一个double类型的值 double是返回值类型——函数的计算结果是double类型的值 库函数在标准库中对应的头文件中声明的,因此库函数的使用务必包含对应的头文件,不包含可能会出问题。

二、自定义函数

库函数虽然可以解决我们遇到的大多数问题,但还要与自定义函数配合使用,以便给程序员写代码更多创造性

1.语法形式

代码语言:javascript
复制
ret_tape fun_name(形式参数)
{

}

其中 ret_tape是函数返回类型 fun_name是函数名——方便使用,尽量根据函数功能起名字 括号中是形式参数 {}中是函数体——完成计算过程

2.写一个加法函数

代码语言:javascript
复制
#include<stdio.h>
int add(int x,int y)
{
    int z = 0;//   也可简化为:
    z=x+y;    //   return x+y;
    return z; //          
}
int main()
{
int a =0;
int b =0;
scanf("%d %d",&a,&b);
//调用加法函数,完成a和b相加
int r =add(a,b);
printf("%d\n",r);
return 0;
}

函数的参数部分要说明:参数个数,参数类型,形参名字

3.形参和实参

在这里插入图片描述
在这里插入图片描述

为什么叫形式参数呢?

实际上,如果只是定义了Add函数,而不去调用的话,Add函数的参数x和y 只是形式上存在的,不会向内存申请空间,不会真实存在的, 所以叫形式参数。形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形参的实例化。

两者关系

a.形参和实参是完全不同的两个内存空间; b.形参是实参的临时拷贝(临时:传一个函数参数只能用一下,在函数外不可用) 可参考如下图:

在这里插入图片描述
在这里插入图片描述

我们在调试的时候可以观察到,x和y确实得到了a和b的值,但是x和y的地址和a和b的地址是不一样的,所以我们可以理解为形参是实参的一份临时拷贝。

4.return语句

注意事项: 🧸 return后边可以是一个数值,也可以是一个表达式,如果是表达式则先执行表达式,再返回表达式 修 使 的结果。 🧸 return后边也可以什么都没有,直接写return;这种写法适合函数返回类型是void的情况。 🧸 return返回的值和函数返回类型不一致,系统会自动将返回的值隐式转换为函数的返回类型。 🧸 return语句执行后,函数就彻底返回,后边的代码不再执行。 🧸 如果函数中存在if等分支的语句,则要保证每种情况下都有return返回,否则会出现编译错误。

5.数组作函数参数

代码语言:javascript
复制
 参照上面,照猫画虎即可

要求:写⼀个函数将⼀个整型数组的内容,全部置为-1,再写⼀个函数打印数组的内容

代码语言:javascript
复制
#include<stdio.h>
int main()
 {
    int arr[]={1,2,3,4,5,6,7,8,9,10};
    int sz = sizeof(arr)/sizeof(arr[0]);
    set_arr(arr, sz);//设置数组内容为-1 
    print_arr(arr, sz);//打印数组内容
    return 0;
 }

这⾥我们需要知道数组传参的⼏个重点知识:

🧸 函数的形式参数要和函数的实参个数匹配 🧸 函数的实参是数组,形参也是可以写成数组形式的 🧸 形参如果是⼀维数组,数组⼤⼩可以省略不写 🧸 形参如果是⼆维数组,⾏可以省略,但是列不能省略 🧸 数组传参,形参是不会创建新的数组的 🧸 形参操作的数组和实参的数组是同⼀个数组

6.嵌套调用和链式访问

6.1.嵌套调用

嵌套调用就是函数之间的相互调用

例如:计算某年某月有多少天

代码语言:javascript
复制
#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 get_days_of_month(int y, int m)
 {
    int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int day = days[m];
    if (is_leap_year(y) && m == 2)
    day += 1;
    return day;
 }
 int main()
 {
     int y = 0;
     int m = 0;
     scanf("%d %d", &y, &m);
      int d = get_days_of_month(y, m);
     printf("%d\n", d);
     return 0;
 }

🧸 main 函数调⽤scanf 、 g printf 、get_days_of_month 🧸 get_days_of_month 函数调⽤is_leap_year 函数之间相互调用,最后成为解决问题的强大程序。

6.2.链式访问

链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。 “千面函数” 的输出结果是什么呢?让我来带大家撕破他的伪装吧!!!

代码语言:javascript
复制
 #include <stdio.h>
 int main()
 {
 printf("%d", printf("%d", printf("%d", 43)));
 return 0;
 }

解题的关键就是:print函数的返回是什么? printf函数返回的是打印在屏幕上的字符的个数。

上⾯的例⼦中,第⼀个printf打印的是第⼆个printf的返回值,第⼆个printf打印的是第三个printf的返回值。 第三个printf打印43,在屏幕上打印2个字符,再返回2 第⼆个printf打印2,在屏幕上打印1个字符,再放回1 第⼀个printf打印1 所以屏幕上最终打印:4321 你是否找到了他的破绽呢?!

7. 函数的声明和定义

7.1单个文件

比如:我们要写一个函数判断一年是否是闰年

代码语言:javascript
复制
#include <stdio.h>

int main()
{
	int y = 0;
	scanf("%d", &y);
	int r = is_leap_year(y);
	if (r == 1)
		printf("闰年\n");
	else
		printf("非闰年\n");
	return 0;
}
int is_leap_year(int y)
{
	
	if ((y % 4 == 0)&& (y % 100!= 0)||(y%400==0))
		return 1;
	else
		return 0;
}

VS就会出现如下警告:

在这里插入图片描述
在这里插入图片描述

这是因为C语言编译器对源代码进行编译的时候,从第一行往下扫描的,当遇到第7行的is_leap_year数函数调用的时候,并没有发现前面有is_leap_year的定义,就报出了上述的警告。 🧸 怎么解决这个问题呢?就是函数调用之前先声明is_leap_year这个函数,声明函数只要交代清楚: 函数名,函数的返回类型和函数的参数。 参考图如下:

在这里插入图片描述
在这里插入图片描述

注意: 🧸 函数的调⽤⼀定要满⾜,先声明后使⽤; 🧸 函数的定义也是⼀种特殊的声明,所以如果函数定义放在调⽤之前也是可以的。

7.2多个文件

在C语言入门阶段,我们通常会将所有代码写在一个 .c 文件中,这种方式对于几十行、上百行的小程序来说简单直观,但当项目规模扩大(比如几百行、上千行代码)时,就会出现代码混乱、难以维护、无法复用、多人协作困难等问题。

而多文件编程,就是解决这些问题的核心方案——它通过将代码按“功能模块”拆分到多个 .c 和 .h 文件中,实现“高内聚、低耦合”,不仅让代码结构更清晰,还能提升开发效率和代码复用性,是C语言项目开发(尤其是嵌入式、服务器端小项目)的必备技能。 如下: add.h

代码语言:javascript
复制
 //函数的定义
 int Add(int x, int y)
 {
    return x+y;
 }

add.h

代码语言:javascript
复制
 //函数的声明
 int Add(int x, int y);

test.c

代码语言:javascript
复制
#include <stdio.h>
 #include "add.h"
 int main()
 {
     int a = 10;
     int b = 20;
     //函数调⽤
     int c = Add(a, b);
     printf("%d\n", c);
     return 0;
   }

为什么需要多文件编程?

先举一个直观的例子:如果我们要写一个“学生成绩管理系统”,包含「录入成绩、计算平均分、打印成绩、查找成绩」4个功能,若全部写在一个 main.c 文件中,会出现以下问题: 🧸 代码冗长:所有功能堆在一起,找某个功能的代码要翻半天,调试时定位错误极难;

🧸 无法复用:如果后续其他项目也需要“计算平均分”的功能,只能复制粘贴代码,无法直接调用;

🧸 协作困难:若两个人同时开发这个系统,修改同一个文件容易出现代码冲突;

🧸 可读性差:别人接手你的代码时,需要逐行阅读才能理解功能划分,维护成本极高。

而用多文件编程拆分后,结构会非常清晰:

🧸 score.c :实现成绩相关的核心功能(录入、计算、查找)

🧸 score.h :声明 score.c 中的函数(供其他文件调用)

🧸 main.c :主函数,调用 score.c 中的功能,实现程序入口

这种拆分的核心逻辑的是:“实现和声明分离” —— .c 文件写“函数实现”(具体代码), .h 文件写“函数声明、宏定义、结构体定义”(告诉其他文件“我有这些功能可以用”)。


总结

希望这篇博客能帮你理清多文件编程的核心逻辑,避开重复包含的坑,也愿你在C语言学习路上,既能夯实基础细节,也能逐步掌握项目化编程思维,后续不妨试着将自己的单文件程序改成多文件版本,在实践中加深理解,稳步进阶~

结尾

勇敢的寻宝者啊,这次旅途你挖掘到多少宝藏呢,苒苒很期待下次与您相遇!

结语:希望对寻找C语言相关内容的寻宝者有所帮助,不要忘记给博主“一键三连”哦!你的每一次鼓励都为我提供 了前行的动力!

小喵很期待你再次跟它寻宝奥 ᰔᩚ/•᷅•᷄\୭

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、函数的概念
    • 1.库函数
      • a.标准库和头文件
      • b.库函数的使用方法
  • 二、自定义函数
    • 1.语法形式
    • 2.写一个加法函数
    • 3.形参和实参
    • 4.return语句
    • 5.数组作函数参数
    • 6.嵌套调用和链式访问
      • 6.1.嵌套调用
      • 6.2.链式访问
    • 7. 函数的声明和定义
      • 7.1单个文件
    • 7.2多个文件
  • 总结
  • 结尾
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档