当前位置: 代码网 > it编程>编程语言>C/C++ > C语言:函数

C语言:函数

2024年07月28日 C/C++ 我要评论
C语言:函数

前言:在c语言学习中,函数的学习非常非常重要!!!

1.函数的概念

函数(function),也叫子程序。c语言中的函数就是一个完成某个特定任务的一小段代码。有特殊写法和调用方法的。
一个大的任务可以分解成若干个较小的函数完成,也可以把某些常用的功能做成函数,可以复用,提升了开发效率。
c语言中函数分为两类:

  • 库函数:提供的
  • 自定义函数:自己设计的

2.库函数

2.1标准库和头文件

c语⾔标准中规定了c语⾔的各种语法规则,c语⾔并不提供库函数;c语⾔的国际标准ansi c规定了⼀些常⽤的函数的标准,被称为标准库,那不同的编译器⼚商根据ansi提供的c语⾔标准就给出了⼀系列函数的实现。这些函数就被称为库函数。

我们前⾯内容中学到的 printf 、 scanf 都是库函数,库函数也是函数,不过这些函数已经是现成
的,我们只要学会就能直接使用了。

各种编译器的标准库中提供了⼀系列的库函数,这些库函数根据功能的划分,都在不同的头⽂件中进
⾏了声明。
库函数相关头文件

2.2库函数的使用方法

库函数的学习和查看⼯具很多,⽐如:
c/c++官⽅的链接
cplusplus.com

举例:sqrt(求平方根)

2.2.1头文件包含
库函数是在标准库中对应的头文件中声明的,所以使用库函数,需要包含对应的头文件。

2.2.2功能
例如:sqrt
compute square root 计算平⽅根
returns the squarerootof x.(返回平⽅根)

2.2.3实践

在这里插入图片描述
2.2.4库函数文档的一般形式

学会怎么读库函数

3.自定义函数

3.1函数的概念

⾃定义函数其实更加重要
概念:根据实际的需要,自己设计和实现函数,自己使用。

3.2函数的语法形式

形式:返回类型,函数名,形式参数,函数体
理解:将函数想成一个工厂,实现加工产品的功能
在这里插入图片描述
我们可以把函数想象成⼩型的⼀个加⼯⼚,⼯⼚得输⼊原材料,经过⼯⼚加⼯才能⽣产出产品,那函数也是⼀样的,函数⼀般会输⼊⼀些值(可以是0个,也可以是多个),经过函数内的计算,得出结果。

4.形参和实参

4.1概念

实参:调用函数时,传递给函数的参数就是实参。
形参:函数定义中,函数名后面括号里的参数 就是形参。

4.2关系

  1. 形参和实参是不同的内存空间,对形参的修改不会影响实参。
  2. 形参是实参的一份临时拷贝。

5.return语句

在函数的设计中,函数中经常会出现return语句,这⾥讲⼀下return语句使⽤的注意事项:

• return后边可以是⼀个数值,也可以是⼀个表达式,如果是表达式则先执⾏表达式,再返回表达式
的结果。
• return后边也可以什么都没有,直接写 return; 这种写法适合函数返回类型是void的情况。
• return返回的值和函数返回类型不⼀致,系统会⾃动将返回的值隐式转换为函数的返回类型。
• return语句执⾏后,函数就彻底返回,后边的代码不再执⾏。
• 如果函数中存在if等分⽀的语句,则要保证每种情况下都有return返回,否则会出现编译错误。

6.数组做函数参数

6.1数组传参

这⾥我们需要知道数组传参的⼏个重点知识:
• 函数的形式参数要和函数的实参个数匹配
• 函数的实参是数组,形参也是可以写成数组形式的
• 形参如果是⼀维数组,数组⼤⼩可以省略不写
• 形参如果是⼆维数组,⾏可以省略,但是列不能省略
• 数组传参,形参是不会创建新的数组的
• 形参操作的数组和实参的数组是同⼀个数组

void set_arr(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		arr[i] = -1;
	}
}
void prin_arr(int arr[10], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	//写一个函数,将数组全部置为-1
	int sz = sizeof(arr) / sizeof(arr[0]);
	set_arr(arr, sz);
	//写一个函数,将数组全部打印出来
	prin_arr(arr, sz);

	return 0;
}

6.2二维数组传参

void print(int brr[3][5], int r, int c)
{
	int i = 0;
	for (i = 0; i < r; i++)
	{
		int j = 0;
		for (j = 0; j < c; j++)
		{
			printf("%d ", brr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5} ,{ 2,3,4,5,6 }, { 3,4,5,6,7 } };
	print(arr, 3, 5);
	return 0;
}

7.嵌套调用和链式访问

7.1嵌套调用

正是因为函数之间有效的互相调⽤,最后写出来了相对⼤型的
程序。

//计算某年某月多少天
//设计函数get_days_of_month来完成
//1  2  3  4  5  6  7  8  9  10  11  12
//31 28 31 30 31 30 31 31 30 31  30  31
//   29

//闰年的判断
//1.能被4整数,不能被100整除
//2.能被400整除
//是闰年返回1,不是返回0
int is_leap_year(int y)
{
	if (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
		return 1;
	else
		return 0;
}
int get_days_of_month(int y, int m)
{
	int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31,  30,  31 };
	           // 0  1    2   3   4
	int day = days[m];
	if (is_leap_year(y) && m == 2)
		day++;
	return day;
		
}                    
int main()
{
	int year = 0;
	int month = 0;
	scanf("%d %d", &year, &month);

	int day = get_days_of_month(year, month);
	printf("%d\n", day);
	return 0;
}

7.2链式访问

所谓链式访问就是将⼀个函数的返回值作为另外⼀个函数的参数,像链条⼀样将函数串起来就是函数的链式访问。

int main()
{
	printf("%d\n", strlen("abcdef"));
	return 0;
}

例题

#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43)));
return 0;
}

弄清printf函数的返回值是啥

8.函数的声明和定义

8.1单个文件

在这里插入图片描述

  1. 函数一定要先声明后使用
  2. 函数定义是一种特殊的声明

函数的声明:是在告诉编译器,有一个函数叫什么,参数是什么,返回类型是什么(给家里介绍自己的对象)

8.2多个文件

我们往往会根据程序的功能,将代码拆分放在多个⽂件中。
⼀般情况下,函数的声明、类型的声明放在头⽂件(.h)中,函数的实现是放在源⽂件(.c)⽂件中。

.c源文件----函数的定义
.h头文件----函数的声明,类型的声明

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样写代码就更加方便了

9.static和extern

static 和 extern 都是c语⾔中的关键字。
static 是 静态的 的意思,可以⽤来:
• 修饰局部变量
• 修饰全局变量
• 修饰函数
extern 是⽤来声明外部符号的。

作⽤域和⽣命周期

一,作⽤域(scope)是程序设计概念,通常来说,⼀段程序代码中所⽤到的名字并不总是有效(可⽤)
的,⽽限定这个名字的可⽤性的代码范围就是这个名字的作⽤域。

  1. 局部变量的作⽤域是变量所在的局部范围。
  2. 全局变量的作⽤域是整个⼯程(项⽬)。

⽣命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的⼀个时间段。

  1. 局部变量的⽣命周期是:进⼊作⽤域变量创建,⽣命周期开始,出作⽤域⽣命周期结束。
  2. 全局变量的⽣命周期是:整个程序的⽣命周期。

9.1static修饰局部变量

#include <stdio.h>
void test()
{
	//static修饰局部变量
	static int i = 0;
	i++;
	printf("%d ", i);
}
int main()
{
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		test();
	}
	return 0;
}

我们从输出结果来看,i的值有累加的效果,其实 test函数中的i创建好后,出函数的时候是不会销毁的,重新进⼊函数也就不会重新创建变量,直接上次累积的数值继续计算。

结论
1.static修饰局部变量改变了变量的⽣命周期,⽣命周期改变的本质是改变了变量的存储类型,本来⼀个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。
2.存储在静态区的变量和全局变量是⼀样的,⽣命周期就和程序的⽣命周期⼀样了.
3.只有程序结束,变量才销毁,内存才回收。但是作⽤域不变的。

使⽤建议:未来⼀个变量出了函数后,我们还想保留值,等下次进⼊函数继续使⽤,就可以使⽤static修饰。
在这里插入图片描述

9.2static修饰全局变量

在这里插入图片描述
代码1正常,代码2在编译的时候会出现链接性错误。

结论
1.⼀个全局变量被static修饰,使得这个全局变量只能在本源⽂件内使⽤,不能在其他源⽂件内使⽤。
2.本质原因是全局变量默认是具有外部链接属性的,在外部的⽂件中想使⽤,只要适当的声明就可以使⽤;但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性,只能在⾃⼰所在的源⽂件内部使⽤了,其他源⽂件,即使声明了,也是⽆法正常使⽤的。

使⽤建议
如果⼀个全局变量,只想在所在的源⽂件内部使⽤,不想被其他⽂件发现,就可以使⽤static修饰。

9.3static修饰函数

在这里插入图片描述
代码1是能够正常运⾏的,但是代码2就出现了链接错误。

结论
1.其实 static 修饰函数和 static 修饰全局变量是⼀模⼀样的,⼀个函数在整个⼯程都可以使⽤,
2.被static修饰后,只能在本⽂件内部使⽤,其他⽂件⽆法正常的链接使⽤了。
3.本质是因为函数默认是具有外部链接属性,具有外部链接属性,使得函数在整个⼯程中只要适当的声明就可以被使⽤。但是被 static 修饰后变成了内部链接属性,使得函数只能在⾃⼰所在源⽂件内部使⽤。

使⽤建议:⼀个函数只想在所在的源⽂件内部使⽤,不想被其他源⽂件使⽤,就可以使⽤ static 修
饰。

9.4extern

结论:extern 是⽤来声明外部符号的,如果⼀个全局的符号在a⽂件中定义的,在b⽂件中想使⽤,就可以使⽤ extern 进⾏声明,然后使⽤。

举例如下:
在这里插入图片描述

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com