文章目录
目录
前言
- 在C语言中无处不在运用函数,比如我们的标准输入函数printf()与标准输出函数scanf(),这些都是C语言标准库里面的库函数。
- 如果恰当的使用函数可以减少代码复用量,提高编程效率。
- 在库函数中往往对应着自己所对应的头文件,如果需要使用库函数则一定要调用所对应的头文件。
函数的分类
- 库函数
- 自建函数
一 .库函数
库函数为C语言内的自有函数,如printf()(标准输出函数),scanf()(标准输入函数),strcpy()(字符串拷贝),strlen()(字符串长度),siezof()(计算占用字节大小)等,库函数众多,也不用完全记忆,这里不才推荐使用Cplusplus官网查找:cplusplus.com - The C++ Resources Network
二.自建函数
1.函数的语法结构
自定义函数和库函数一样,有函数名,返回值类型和函数参数。 但是不一样的是这些都是我们自己来设计。
ret_type fun_name(para1,......)
{
语句项;
}
-
ret_type: 返回类型
-
fun_name: 函数名
-
fun_name后面紧跟的括号中包含的就是函数参数列表,函数参数可以有零个也可以有多个
-
para1: 函数参数,用于接收调用此函数的实际参数
-
语句项中一定要包含所对应返回类型的返回值。若返回类型为空则无需返回值。
2.函数的定义
若我们此时进行一个两个数相加的加法函数的定义
函数定义是在mian函数外面进行的,我们先定义函数的名字(即函数变量),在主函数外定义函数变量名字加上函数调用操作符"()",此时我们一个不完全体的函数就已经创建好了。若我们省略返回类型不写,则默认返回类型是 int类型,下图Abd函数中代表的意思:无参数列表、无语句项、返回类型是int类型的空函数。
- 虽说我们返回类型省略不写默认是int类型,但是不才建议我们的返回类型还是写明确,避免造成逻辑上的错误。👀
此时我们需要的是加法函数返回类型要整形,则在Add()前加上整形int,此时我们的函数的返回类型就确定为 in t类型。为了确保函数的完整性,我们暂时先将返回值设定为0。此时一个无参整形函数的就创建好了。此时int为函数类型,说明Add()函数是整形函数,返回值为整形。
因为要实现加法函数,所以我们需要在参数列表中加入两个临时变量来进行接收调用此函数相加的实际参数
int Add(int a,int b) {
return 0;
}
int main() {
return 0;
}
- 在参数列表中定义了变量a和变量b, 变量a和变量B则被称为形式参数
完善Add函数内的语句项后,在main函数中Add函数调用:函数变量名 +()函数调用操作符 +在函数调用操作符内放入实际参数。
#include <stdio.h>
int Add(int a,int b) {
int sum = a + b;
return sum;
}
int main() {
int n1 = 1;
int n2 = 2;
int sum = 0;
sum = Add(n1, n2);
printf("%d\n", sum);
return 0;
}
-
此时变量n1和变量n2为实际参数,传递给Add函数中的形式参数变量a与变量B
-
这时我们打印的结果即为:3
这里不才有一个手稿图😆😆 可以较为详细的了解清楚。
3.函数的传参
- 函数的参数又分为形式参数和实际参数
举个栗子
#include<stdio.h>
int Add(int x , int y){
int z = 0;
z = x+y;
return z;
}
int main(){
int num1 = 0;
int mum2 = 0;
scanf("%d%d",&num1,&num2);
int sum = Add(num1,num2);
printf("%d\n",sum);
return 0;
}
int Add(int x , int y){ 左边这段就是在计算机里写的函数 函数定义 int 是因为return z
int z = 0; 返回z,因为z是整数,返回值为整数所以用int来定义了函数。
z = x+y; Add就是函数名字。就如定义整形变量一样int a = 0;a就是整形
return z; 变量的变量名字。
}
变量后面连接括号内的内容是在在main函数运行中(int sum = Add(num1,num2);)发送了num1,num2变量,在函数本体也接收,又因为变量为整形,所以创建两个int型的变量接收Add(int x , int y){}。其中Add面连接的括号"()"是函数调用操作符,如果单纯Add没有带上括号那他就不是函数而是一个变量。
我们在main函数中int sum = Add(num1,num2)括号内传递过去的num1与mun2称为实参,在函数Add(int x , int y)中括号创建的x和y称为形参。实参传递了多少个,形参就要创建多少个来接收。
在主函数中的 int sum = Add(num1,num2);,其中num1和mun2把这两个变量发送到Add函数然后系统会调用Add函数运行。
三、函数的调用
1.传值调用
- 函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参
函数的形参和实参分别占有不同的内存块,对形参的修改不会影响实参。在上面的例子中我们就运用到了传值调用,如果此时我们对Abd函数中变量x、y进行值更改并不会影响变量num1和num2的值。
我们在vs2022编译器中打开监视可以看到在运行中Add函数的变量x和y与变量num1、num2的内存地址不同。如下图
我们很清晰的可以看到变量num1和变量num2和变量x、y的地址完全不同
若此时我们需要定义一个函数让其可以交换变量num1和num2的值时候我们就不可以用传值调用的方法来进行更改
#include<stdio.h>
void exc(int x, int y) {
int z = 0;
z = x;
x = y;
y = z;
}
int main() {
int num1 = 10;
int num2 = 20;
printf("交换前:num1 = %d ,num2 = %d\n", num1, num2);
exc(num1, num2);
printf("交换后:num1 = %d ,num2 = %d\n", num1, num2);
return 0;
}
- 在上述代码运行结果为:交换前与交换后结果一致。并没有进行到我们想象中可以把num1和num2的值交换的场景
此时就需要用到我们的传址调用🤯🐵
2.传址调用
- 传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
- 传址调用可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操 作函数外部的变量。
我们还是使用上面的栗子
#include<stdio.h>
void exc(int* x, int* y) {
int z = 0;
z = *x;
*x = *y;
*y = z;
}
int main() {
int num1 = 10;
int num2 = 20;
printf("交换前:num1 = %d ,num2 = %d\n", num1, num2);
exc(&num1, &num2);
printf("交换后:num1 = %d ,num2 = %d\n", num1, num2);
return 0;
}
- 此时我们把exc()函数中的实际参数num1与num2进行地址的传递(简称为传值)
- 因为实际参数是以传值的形式进行传递那么在参数列表中也要以指针的形式来接收地址,此时我们获取到了num1与num2的地址进行值交换。
我们依旧在在vs2022编译器中打开监视可以看到在运行中Add函数的变量x和y与变量num1、num2的内存地址
- 此时可以看到函数Add()中的变量x与y的值是与变量num1、num2的值是相同的
使用传址调用就解决掉了我们刚刚无法通过函数来交换实参的情况。(他真的...我哭死...😭😭)
四、函数的嵌套调用和链式访问
- 函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的
1.函数的嵌套调用
#include <stdio.h>
void Kobe()
{
printf("孩子这并不好笑!\n");
}
void fun()
{
int i = 0;
for (i = 0; i < 3; i++)
{
Kobe();
}
}
int main()
{
fun();
return 0;
}
- 在上述代码中我们就实现了函数的嵌套调用,在屏幕上连续打印三次:孩子这并不好笑!
- 函数可以嵌套调用,但是不能嵌套定义。
2.链式访问
- 把一个函数的返回值作为另外一个函数的参数,即为链式访问。.
#include <stdio.h>
char* kun() {
return "你干嘛~哎哟~";
}
int main() {
printf("%s \n", kun());
return 0;
}
- 因为我们知道printf()也是一个函数,所以我把kun()函数的返回值作为printf()函数的参数,那这样就形成了链式访问,在屏幕上打印:你干嘛~哎哟~
- 而且这样的代码它并不是一个错误的代码,它并不会造成野指针访问,因为kun()函数返回的是“你干嘛~哎哟~”这个常量字符串的地址,而常量字符串是存储在静态存储区中,所以它并不会造成野指针的访问。
五、函数的声明和定义
- 函数与变量在声明与定义中有相似之处,需要先进行函数的声明后才可以进行函数的使用,如果未进行函数的声明而使用函数则编译器会报错。
- 函数的声明一般出现在函数的使用之前。要满足先声明后使用
有些小伙伴常常会写出这样的代码而后编译器报错 编译器错误 C2040 的错误码。如下代码
#include <stdio.h>
int main() {
printf("%s \n", kun());
return 0;
}
char* kun() {
return "你干嘛~哎哟~";
}
这是因为编译器是从上到下依次执行,在进入main函数之前未有KUN函数的声明所以它会报出 C2040 的错误码。但是我们已经在下面完成了函数的定义,此时我们只需要在main函数之上增加函数的声明即运行。
#include <stdio.h>
char* kun();
int main() {
printf("%s \n", kun());
return 0;
}
char* kun() {
return "你干嘛~哎哟~";
}
函数的定义是一种特殊的声明!
#include <stdio.h>
char* kun() {
return "你干嘛~哎哟~";
}
int main() {
printf("%s \n", kun());
return 0;
}
所以我们进行这样的代码编写时它并不会报错而是可以直接运行。
六、函数递归
这里我们简单聊聊什么是函数的递归。详细请看不才的函数递归详解~
- 函数自己调用自己的编程技巧称为递归
以上就是本章所有内容啦。若有勘误请私信不才修改。 万分感激!💖🌹🌹