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

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

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

一、 库函数

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

为了支持程序的可移植性和开发的效率,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;
}

函数说明

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

return

2. 函数的调用

(1)函数传参

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

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

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

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

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

1. 传值调用

传值调用

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

2. 传址调用

传址调用

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

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

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

练习:写一个函数每调用一次这个函数,就会将 num 的值加 1

int main()
{
	int num = 0;
	//调用函数,使得 num 加 1
	return 0;
}

传值调用

#include<stdio.h>

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<stdio.h>

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<stdio.h>

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 函数
函数调用

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

函数执行过程:
函数递归

(4)函数的链式访问

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

例如:

#include<stdio.h>
#include<string.h>

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

链式访问

练习:程序输出什么

#include<stdio.h>

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

	return 0;
}

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

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

  • 10
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值