-

🍀指尖燃热血,代码铸锋芒;以信仰破局,向顶峰生长
🎬秦苒&的简介:

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

如果一个函数如果能完成某项特定任务的话,那么函数也是可以复用的。这样可以更好的 提升我们开发软件的效率。
我们之前学到的printf,scanf都是库函数,库函数也是一种函数,只不过这些函数是被规定好的,我们可以直接使用。各种编译器的标准库提供了一系列库函数,这些函数跟据功能进行划分,在不同的头文件中进行声明。 想了解更多库函数相关头文件的寻宝者请点击如下链接: https://zh.cppreference.com/w/c/header
C/C++官⽅的链接:https://zh.cppreference.com/w/c/header cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
这里我给大家举例说明:(sqrt)
double sqrt(double x);其中 sqrt 是函数名 x是函数参数——调用sqrt函数需要传递一个double类型的值 double是返回值类型——函数的计算结果是double类型的值 库函数在标准库中对应的头文件中声明的,因此库函数的使用务必包含对应的头文件,不包含可能会出问题。
库函数虽然可以解决我们遇到的大多数问题,但还要与自定义函数配合使用,以便给程序员写代码更多创造性
ret_tape fun_name(形式参数)
{
}其中 ret_tape是函数返回类型 fun_name是函数名——方便使用,尽量根据函数功能起名字 括号中是形式参数 {}中是函数体——完成计算过程
#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;
}函数的参数部分要说明:参数个数,参数类型,形参名字

为什么叫形式参数呢?
实际上,如果只是定义了Add函数,而不去调用的话,Add函数的参数x和y 只是形式上存在的,不会向内存申请空间,不会真实存在的, 所以叫形式参数。形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形参的实例化。
两者关系
a.形参和实参是完全不同的两个内存空间; b.形参是实参的临时拷贝(临时:传一个函数参数只能用一下,在函数外不可用) 可参考如下图:

我们在调试的时候可以观察到,x和y确实得到了a和b的值,但是x和y的地址和a和b的地址是不一样的,所以我们可以理解为形参是实参的一份临时拷贝。
注意事项: 🧸 return后边可以是一个数值,也可以是一个表达式,如果是表达式则先执行表达式,再返回表达式 修 使 的结果。 🧸 return后边也可以什么都没有,直接写return;这种写法适合函数返回类型是void的情况。 🧸 return返回的值和函数返回类型不一致,系统会自动将返回的值隐式转换为函数的返回类型。 🧸 return语句执行后,函数就彻底返回,后边的代码不再执行。 🧸 如果函数中存在if等分支的语句,则要保证每种情况下都有return返回,否则会出现编译错误。
参照上面,照猫画虎即可要求:写⼀个函数将⼀个整型数组的内容,全部置为-1,再写⼀个函数打印数组的内容
#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;
}这⾥我们需要知道数组传参的⼏个重点知识:
🧸 函数的形式参数要和函数的实参个数匹配 🧸 函数的实参是数组,形参也是可以写成数组形式的 🧸 形参如果是⼀维数组,数组⼤⼩可以省略不写 🧸 形参如果是⼆维数组,⾏可以省略,但是列不能省略 🧸 数组传参,形参是不会创建新的数组的 🧸 形参操作的数组和实参的数组是同⼀个数组
嵌套调用就是函数之间的相互调用
例如:计算某年某月有多少天
#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 函数之间相互调用,最后成为解决问题的强大程序。
链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。 “千面函数” 的输出结果是什么呢?让我来带大家撕破他的伪装吧!!!
#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 你是否找到了他的破绽呢?!
比如:我们要写一个函数判断一年是否是闰年
#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这个函数,声明函数只要交代清楚: 函数名,函数的返回类型和函数的参数。 参考图如下:

注意: 🧸 函数的调⽤⼀定要满⾜,先声明后使⽤; 🧸 函数的定义也是⼀种特殊的声明,所以如果函数定义放在调⽤之前也是可以的。
在C语言入门阶段,我们通常会将所有代码写在一个 .c 文件中,这种方式对于几十行、上百行的小程序来说简单直观,但当项目规模扩大(比如几百行、上千行代码)时,就会出现代码混乱、难以维护、无法复用、多人协作困难等问题。
而多文件编程,就是解决这些问题的核心方案——它通过将代码按“功能模块”拆分到多个 .c 和 .h 文件中,实现“高内聚、低耦合”,不仅让代码结构更清晰,还能提升开发效率和代码复用性,是C语言项目开发(尤其是嵌入式、服务器端小项目)的必备技能。 如下: add.h
//函数的定义
int Add(int x, int y)
{
return x+y;
}add.h
//函数的声明
int Add(int x, int y);test.c
#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语言相关内容的寻宝者有所帮助,不要忘记给博主“一键三连”哦!你的每一次鼓励都为我提供 了前行的动力!
小喵很期待你再次跟它寻宝奥 ᰔᩚ/•᷅•᷄\୭