C语言中的函数(重点介绍自定义函数)

C语言中的函数分为库函数和自定义函数,本篇重点介绍自定义函数中的函数调用

函数由一个或多个语句块组成,负责完成某项特定任务, 相较于其他代码,具有相对的独立性,一般会有返回值和输入参数,提供对过程的封装和细节的隐藏

文章目录

  • 一、 库函数
  • 二、 自定义函数
    • 1. 函数的声明和定义
      • (1) 函数的声明
      • (2) 函数的定义
    • 2. 函数的调用
      • (1)函数传参
        • 1. 传值调用
        • 2. 传址调用
      • (2) 不同函数之间的调用
      • (3)函数直接或间接调用自身 - 函数递归
      • (4)函数的链式访问

一、 库函数

在C语言的编程中会频繁的用到一些功能如:

  • 格式化输入输出函数 scanf ,printf
  • 字符串拷贝函数 strcpy

为了支持程序的可移植性和开发的效率,C语言的基础库提供了一系列的库函数,但是库函数的具体实现是由编译器实现的

C语言中常用的库函数有:

  • IO函数
  • 字符串操作函数
  • 字符操作函数
  • 内存操作函数
  • 时间/日期函数
  • 数学函数

当想要了解库函数的细节时可以参考以下网站
cplusplus.com
cppreference.com

注意:使用库函数必须用#include包含对应的头文件


二、 自定义函数

1. 函数的声明和定义

函数的组成:
ret_type fun_name(paral, ...)	//函数首部
{
	statement	//语句项
}

ret_type: 返回值类型
fun_name:函数名 (符合标识符命名规则)
paral: 函数参数(0个或多个)

(1) 函数的声明

函数的首部加上一个分号,代表函数的声明,如:

void fun1();
int fun2(int, char);
int fun3(int x, int y);
  • 在函数的声明中,函数的参数名可以省略
    函数的声明是告诉编译器函数的函数名、函数的参数个数及参数的类型和函数的返回类型是什么,但是函数具体是否存在是不能确定的
  • 函数需要满足先声明后使用
    当函数定义在函数使用之后,需要在函数使用之前加上函数的声明
    如果函数定义在函数使用之前,便不需要

(2) 函数的定义

函数的定义是指函数的具体实现,交代函数的功能实现

列如:实现一个函数求两个整数的最大值

int max(int x, int y)	//函数首部
{
	return x > y ? x : y;
}

C语言中的函数(重点介绍自定义函数)_第1张图片

当返回类型为 void 时,函数中允许使用 return

C语言中的函数(重点介绍自定义函数)_第2张图片

2. 函数的调用

(1)函数传参

  • 实参:函数实际传递的参数,可以是常量,变量,表达式,函数等
    无论实参是何种类型的值,在进行函数调用时,都必须有确定的值,以便把这些值传递给形参

  • 形参:用来接收函数传递的参数
    形参只有在函数调用时才分配内存空间,当函数调用结束之后,形参的内存空间便自动销毁了,形参只在函数中有效

因此函数的形参变量名可以和实参变量名一样

函数调用传递参数有两种方法,传值调用和传址调用

例如:用函数实现两个整数的交换

1. 传值调用

C语言中的函数(重点介绍自定义函数)_第3张图片

此函数不能完成两个数的交换
函数的形参和函数的实参并未占用同一块内存空间在函数中改变了形式参数,并不能影响到实参

2. 传址调用

C语言中的函数(重点介绍自定义函数)_第4张图片

函数的形参和函数的实参虽然不是占用同一块内存空间,但是形参接收的是实参变量的地址,通过对指针的解引用,便可以改变实参

在函数的调用中实参和形参所占用的并不是同一块内存空间改变形参并不能改变实参,但是形参的内容和实参相同,

  • 在传值调用中不能通过形参改变实参,
  • 传址调用中形参接收的是变量的地址,相当于将实参变量和函数建立了联系,此时改变解引用后的形参可以改变实参

练习:写一个函数每调用一次这个函数,就会将 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;
}

(2) 不同函数之间的调用

#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;
}

C语言中的函数(重点介绍自定义函数)_第5张图片

在该程序中 main 函数 调用 three_line 函数 three_line 函数调用 new_line 函数
C语言中的函数(重点介绍自定义函数)_第6张图片

(3)函数直接或间接调用自身 - 函数递归

一个大型复杂的问题,可以层层转化为一个与原问题相似且规模较小的问题时,可以考虑采用递归

一个函数直接或间接调用自身就被称为函数递归
递归只需要少量的代码便可以描述出解题过程中的多次重复计算,大大的减少了程序的代码量

在使用函数递归时为了避免死递归导致栈溢出,需要满足两个条件

  • 设置一个条件,条件满足时,递归不再进行
  • 在递归的过程中条件越来越接近递归退出的条件

例题:输入一个正整数,按照顺序打印他的每一位,输出的数之间以空格隔开
列如:
输入 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;
}

函数执行过程:
C语言中的函数(重点介绍自定义函数)_第7张图片

(4)函数的链式访问

链式访问:把一个函数的返回值作为另外一个函数的参数

例如:

#include
#include

int main()
{
	char str[] = "abcdef";
	
	//strlen 求字符串长度是  头文件中的库函数
	printf("%d\n", strlen(str));	
	return 0;
}

C语言中的函数(重点介绍自定义函数)_第8张图片

练习:程序输出什么

#include

int main()
{
	//了解 printf 函数的返回值就迎刃而解
	printf("%d", printf("%d", printf("%d", 43)));

	return 0;
}

printf 函数的返回值为打印字符的个数,程序输出4321

自定义函数给编程带来了极大的发展空间,结合函数调用,可以实现许多功能

你可能感兴趣的:(C语言,c语言)