1. 函数是什么?
数学中我们常见到函数的概念,C语言中也有函数。
在维基百科中,函数称为子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。这些代码通常被集成为软件库。
🍩每个 C 程序都至少有一个函数,即主函数 main()
2. 函数的分类
2.1 库函数
为什么会有库函数?
🍥 在学习C语言编程的时候,我们会频繁的使用一个功能:printf(),它的作用是将信息按照一定的格式打印到屏幕上。
🍥 如果你需要通过键盘给程序中的变量赋值,scanf()函数可以帮你实现。
🍥 在编程时,我们也会进行计算,比如sqrt(),帮助我们获得某一个数字平方根。
像上面描述的常用功能,C语言将它们进行了封装,提供一系列类似的库函数,放便大家使用。
C语言常用的库函数:
- IO函数(input-output):scanf、printf、getchar、putchar
- 字符串操作函数:strlen、strcmp…
- 字符操作函数:islower、isupper
- 内存操作函数:memset、memcmp
- 时间/日期函数:time
- 数学函数:sqrt、pow…
- 其他库函数
🍩注:使用库函数,必须包含#include对应的头文件
cplusplus–大家可以通过此网站查询函数的具体使用方法
2.2 自定义函数
现实生活中,库函数并不能解决所有问题,于是就有了自定义函数。
自定义函数和库函数一样,有函数名,返回值类型和函数参数。
但是不一样的是这些都是我们自己来设计。
函数的组成:
ret_type fun_name(para1, * ) { statement;//语句项 } //ret_type:返回类型 //fun_name:函数名 //para1:函数参数
🍤实例:
求两个整数之和
#include<stdio.h> //sum函数的设计 int sum(int x, int y)//int是返回类型,sum是函数名 { return x + y; } int main() { int a = 10; int b = 10; int s = sum(a, b);//调用sum函数 printf("%d\n", s); return 0; }
这里的sum函数就是用户自定义的一个求和函数,根据求和的个数和数据的类型,可以改变参数的数量以及返回的类型。
3. 函数的参数
3.1 实际参数
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。
3.2 形式参数
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。
形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
🍤举个例子说明一下:
使用函数交换两个整型变量的内容
#include<stdio.h> void swap1(int x, int y) { int temp = x; x = y; y = temp; } void swap2(int* p, int* q) { int temp = *p;//temp = a *p = *q;//a = b *q = temp;//b = temp } int main() { int a = 10; int b = 20; printf("交换前:a=%d b=%d\n", a, b); swap1(a, b);//传值调用:在这种设计中,形参是实参的一份临时拷贝,对形参的修改不会影响实参 printf("交换后:a=%d b=%d\n", a, b); printf("交换前:a=%d b=%d\n", a, b); swap2(&a, &b);//通过形参的指针就能够访问到函数外部的变量,并进行操作。 printf("交换后:a=%d b=%d\n", a, b); return 0; }
上面swap1和swap2函数中的参数 x、y、p、q都属于形参。
main函数中的传给swap1的a、b,和传给swap2函数的&a、&b都属于实参。
这里可以看到swap1函数在调用的时候,x,y拥有自己的空间,同时拥有了和实参一模一样的内容。
可以简单的认为:形参实例化之后其实相当于实参的一份临时拷贝。
4. 函数的调用
4.1 传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
前面交换两个变量内容的例子中,swap1函数就是传值操作:
上面的实例表明了,虽然在函数内改变了 a 和 b 的值,但是实际上 a 和 b 的值没有发生变化。
4.2 传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。
前面的swap2函数就是传址操作:
与传值调用不同,传址调用在函数内改变了 a 和 b 的值,实际上也改变了函数外 a 和 b 的值。
5. 函数的嵌套调用和链式访问
🍩函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。
5.1 嵌套调用
函数的嵌套可以简单的理解为,在一个函数中可以调用其他函数。
🍤实例:
int sum(x, y) { return x + y; } int test(x,y) { printf("%d\n", sum(x, y));//调用sum函数 } int main() { int a = 10; int b = 20; test(a, b); return 0; }
🍩函数可以嵌套调用,但是不能嵌套定义。
5.2 链式访问
把一个函数的返回值作为另外一个函数的参数。
🍤实例:
//代码1 #include <stdio.h> #include <string.h> int main() { char arr[20] = "hello"; int ret = strlen(strcat(arr, "bit"));//strlen函数--求字符串的长度,不包括'\0' printf("%d\n", ret); return 0; }
//代码2 #include <stdio.h> int main() { printf("%d", printf("%d", printf("%d", 43)));//4321 //注:printf函数的返回值是打印在屏幕上字符的个数 return 0; }
6. 函数的声明和定义
6.1 函数声明
告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
- 函数的声明一般出现在函数的使用之前。要满足先声明后使用。
- 函数的声明一般要放在头文件中的。
如果函数在主函数main()前,不需要声明,直接调用;
如果函数在主函数之后,要先声明:
//声明格式: 返回类型 函数名(形参1,形参2,...);
//函数声明 int Add(int x, int y); int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b); int c = Add(a, b);//函数调用 printf("%d\n", c); return 0; } //函数的定义 int Add(int x, int y) { return x + y; }
6.2 函数定义
函数的定义是指函数的具体实现,交待函数的功能实现。
//函数的定义-定义是一种特殊的声明 int Add(int x, int y) { return x + y; } int main() { int a = 0; int b = 0; scanf("%d %d", &a, &b); int c = Add(a, b);//函数调用 printf("%d\n", c); return 0; }
结束语
函数是 C 语言中非常重要的概念。本文介绍了 C 语言函数的声明和定义、调用、参数等内容,希望对你有所帮助。