C语言:函数

一. 函数的概念

在C语言也引入了函数的概念,有些翻译为:子程序,子程序这种翻译更加准确⼀些。

C语言中的函数就是⼀个完成某项特定的任务的一小段代码。这段代码是有特殊的写法和调用方法的。

在C语言中我们⼀般会见到两类函数:

• 库函数

• 自定义函数

二. 库函数

‌库函数是将函数封装入库,供用户使用的一种方式。这些函数通常被编译成二进制形式,存放在库文件中,但C语言并不提供库函数,然而C语言的国际标准ANSI C规定了一些常用的函数的标准,被称为标准库。

库函数相关头文件:https://zh.cppreference.com/w/c/header

1.库函数的使用方法

我们可以举个例子

int sqrt (int x);

//sqrt 是函数名

//x 是函数的参数,表示调用sqrt函数需要传递⼀个int类型的值

//int 是返回值类型 - 表示函数计算的结果是int类型的值

功能: 计算平方根和返回平方根

关于库函数的学习和查看我们可以去用这些工具

C/C++官方的链接:https://zh.cppreference.com/w/c/header

cplusplus.comhttps://legacy.cplusplus.com/reference/clibrary/

2.头文件包含

库函数是在标准库中对应的头文件中声明的,所以库函数的使用,务必包含对应的头文件,不包含可能会出现⼀些问题的。

例如:在使用sqrt时需要包含#include<math.h>文件。

cs 复制代码
#include<stdio.h>
#include<math.h>
int main()
{
	int a = 16;
	int c = sqrt(a);
	printf("%d", c);
}

三.自定义函数

1.语法形式

ret_type fun_name(形式参数)

{

}

ret_type 是函数返回类型

fun_name 是函数名

括号中放的是形式参数

{}括起来的是函数体

2.代码举例

cs 复制代码
#include <stdio.h>
int Add(int x, int y)
{
	return x+y;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int r = Add(a, b);
	printf("%d\n", r);
	return 0;
}

四. 形参和实参

在函数使用的过程中,把函数的参数分为,实参和形参。

1.那么什么是形参,什么是实参呢?

  • 实参:实参就是真实传递给函数的参数,既实际参数。
  • 形参:是形式上存在的,不会向内存申请空间,不会真实存在的参数,既形式参数。

(形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才向内存申请空间,这个过程就是形参的实例化。)

从上面的代码来看a和b为实参,x和y为形参。

2.实参和形参的关系

我们通过上面的例子来解释

在调试下它们的地址是不一样的,但x和y的确得到了a和b的值,所以我们可以理解为形参是实参的⼀份临时拷贝。

五. return 语句

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

六. 数组做函数参数

在这里我们需要记住几个重要的知识点

  • 函数的形式参数要和函数的实参个数匹配
  • 函数的实参是数组,形参也是可以写成数组形式的
  • 形参如果是⼀维数组,数组大小可以省略不写
  • 形参如果是⼆维数组,行可以省略,但是列不能省略
  • 数组传参,形参是不会创建新的数组的
  • 形参操作的数组和实参的数组是同⼀个数组

这样的话,我们可以利用数组做函数参数,建立两个函数,将数组的值全赋值为0,并打印数组。

cs 复制代码
void set_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		arr[i] = 0;
	}
}
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	set_arr(arr, sz);
	print_arr(arr, sz);
	return 0;
}

七.嵌套调用和链式访问

1.嵌套调用

简单来说在一个函数内部调用另一个函数

cs 复制代码
#include<stdio.h>
void another(int z)
{
	printf("%d\n", z);
}
void other(int x)
{
	int y=3;
	printf("%d\n", x);
	another(y);
}
int main()
{
	int a=5;
	other(a);
}

2. 链式访问

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

cs 复制代码
#include <stdio.h>
int main()
{
	int len = strlen("abcdef");
	printf("%d\n", len);
	return 0;
}





#include <stdio.h>
int main()
{
	printf("%d\n", strlen("abcdef"));//链式访问
	return 0;
}

对于这两个代码,其实就是第二个代码直接将strlen的返回值直接作为printf函数的参数,这就是所谓的链式访问 。

八.函数的声明和定义

1.单个文件

cs 复制代码
#include<stdio.h>
int Add(int x, int y) 
{
	return x + y;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int r=Add(a, b);
	printf("%d\n", r);
	return 0;
}

如果我们将Add函数调到下面会怎样

cs 复制代码
#include<stdio.h>
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int r=Add(a, b);
	printf("%d\n", r);
	return 0;
}
int Add(int x, int y)
{
	return x + y;
}

在这里就会报一个警报,说Add为定义,所以我们要定义Add函数

cs 复制代码
#include<stdio.h>

int Add(int x, int y);

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	int r=Add(a, b);
	printf("%d\n", r);
	return 0;
}
int Add(int x, int y)
{
	return x + y;
}
cs 复制代码
int Add(int x, int y);

我们只需在函数之前定义一个Add函数即可。

2.多个文件

我们只需要创建三个文件

并把函数的声明放在add.h文件里,将函数的定义放在add.c文件里,并在test.c文件里定义#include"add.h"即可

九.static 和 extern

static 和 extern 都是C语言中的关键字。

static 是 静态的 的意思,可以用来

• 修饰局部变量

• 修饰全局变量

• 修饰函数

extern 是用来声明外部符号的。

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

extern 是用来声明外部符号的,如果⼀个全局的符号在A文件中定义的,在B文件中想使用,就可以使用extern 进进声明,然后使用。

十.作用域和生命周期

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

  1. 局部变量的作用域是变量所在的局部范围。

  2. 全局变量的作用域是整个⼯程(项目)。

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

  1. 局部变量的生命周期是:进入作用域变量创建,生命周期开始,出作用域生命周期结束。 2. 全局变量的生命周期是:整个程序的生命周期。
相关推荐
yqcoder9 分钟前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
baivfhpwxf202320 分钟前
C# 5000 转16进制 字节(激光器串口通讯生成指定格式命令)
开发语言·c#
许嵩6623 分钟前
IC脚本之perl
开发语言·perl
长亭外的少年34 分钟前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
直裾34 分钟前
Scala全文单词统计
开发语言·c#·scala
心仪悦悦35 分钟前
Scala中的集合复习(1)
开发语言·后端·scala
JIAY_WX37 分钟前
kotlin
开发语言·kotlin
代码小鑫1 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计