C语言中的函数分为库函数和自定义函数,本篇重点介绍自定义函数中的函数调用
函数由一个或多个语句块组成,负责完成某项特定任务, 相较于其他代码,具有相对的独立性,一般会有返回值和输入参数,提供对过程的封装和细节的隐藏
在C语言的编程中会频繁的用到一些功能如:
为了支持程序的可移植性和开发的效率,C语言的基础库提供了一系列的库函数,但是库函数的具体实现是由编译器实现的
C语言中常用的库函数有:
当想要了解库函数的细节时可以参考以下网站
cplusplus.com
cppreference.com
注意:使用库函数必须用#include包含对应的头文件
函数的组成:
ret_type fun_name(paral, ...) //函数首部
{
statement //语句项
}
ret_type: 返回值类型
fun_name:函数名 (符合标识符命名规则)
paral: 函数参数(0个或多个)
函数的首部加上一个分号,代表函数的声明,如:
void fun1();
int fun2(int, char);
int fun3(int x, int y);
函数的定义是指函数的具体实现,交代函数的功能实现
列如:实现一个函数求两个整数的最大值
int max(int x, int y) //函数首部
{
return x > y ? x : y;
}
当返回类型为 void 时,函数中允许使用 return
实参:函数实际传递的参数,可以是常量,变量,表达式,函数等
无论实参是何种类型的值,在进行函数调用时,都必须有确定的值,以便把这些值传递给形参
形参:用来接收函数传递的参数
形参只有在函数调用时才分配内存空间,当函数调用结束之后,形参的内存空间便自动销毁了,形参只在函数中有效
因此函数的形参变量名可以和实参变量名一样
函数调用传递参数有两种方法,传值调用和传址调用
例如:用函数实现两个整数的交换
此函数不能完成两个数的交换
函数的形参和函数的实参并未占用同一块内存空间,在函数中改变了形式参数,并不能影响到实参
函数的形参和函数的实参虽然不是占用同一块内存空间,但是形参接收的是实参变量的地址,通过对指针的解引用,便可以改变实参
在函数的调用中实参和形参所占用的并不是同一块内存空间,改变形参并不能改变实参,但是形参的内容和实参相同,
练习:写一个函数每调用一次这个函数,就会将 num 的值加 1
int main()
{
int num = 0;
//调用函数,使得 num 加 1
return 0;
}
传值调用
#include
int add_one(int num)
{
return num + 1;
}
int main()
{
int num = 0;
num = add_one(num); //调用函数,使得 num 加 1
num = add_one(num);
num = add_one(num);
printf("%d\n", num);
return 0;
}
传址调用
#include
void add_one(int* num)
{
*num += 1;
}
int main()
{
int num = 0;
add_one(&num); //调用函数,使得 num 加 1
add_one(&num);
add_one(&num);
printf("%d\n", num);
return 0;
}
#include
void new_line()
{
printf("haha"\n);
}
void three_line()
{
int i = 0;
for(i = 0; i < 3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
在该程序中 main 函数 调用 three_line 函数 three_line 函数调用 new_line 函数
一个大型复杂的问题,可以层层转化为一个与原问题相似且规模较小的问题时,可以考虑采用递归
一个函数直接或间接调用自身就被称为函数递归
递归只需要少量的代码便可以描述出解题过程中的多次重复计算,大大的减少了程序的代码量
在使用函数递归时为了避免死递归导致栈溢出,需要满足两个条件
例题:输入一个正整数,按照顺序打印他的每一位,输出的数之间以空格隔开
列如:
输入 123
输出 1 2 3 ;输出数字的每一位之间,以空格隔开
//对于一个正整数 n,n % 10 可以很容易的得到 n 的最后一位
//打印 123 的每一位可以转化为打印 12 的每一位后打印 3 空格
//打印 12 的每一位可以转化为打印 1 的每一位后,打印 2 空格
//此时只剩下 1 位数字,便可以直接打印,函数不必继续转化
void print(int n)
{
if (n > 9)
print(n / 10); //每次调用 n 减少一位
//越来越接近函数递归退出的条件
//只有当 前 n - 1 位打印完后,才会执行
printf("%d ", n % 10);
}
int main()
{
int n = 0;
scanf("%d", &n);
//使用函数递归来解决
print(n);
return 0;
}
链式访问:把一个函数的返回值作为另外一个函数的参数
例如:
#include
#include
int main()
{
char str[] = "abcdef";
//strlen 求字符串长度是 头文件中的库函数
printf("%d\n", strlen(str));
return 0;
}
练习:程序输出什么
#include
int main()
{
//了解 printf 函数的返回值就迎刃而解
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}
printf 函数的返回值为打印字符的个数,程序输出4321
自定义函数给编程带来了极大的发展空间,结合函数调用,可以实现许多功能