函数
在日常码代码的过程中,我们会重复使用相同功能的代码,如果每次使用都要写一长段的代码,那就就太麻烦了、太冗余了
所以就有了函数这个功能,我们把常用的功能写到函数里面,函数像是一个模块,在需要的时候就可以使用这个模块了
函数的结构
ret_type fun_name(para1, * )
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
para1 函数参数
ret_type 返回类型
fun_name 函数名
para1, * 函数参数(参数数量可无、可一个、可多个)
statement 实现函数功能的代码
库函数
我们经常会使用printf()
把程序的结果打印到屏幕中,这个printf()
就是一个库函数
这是每个程序员都需要用到的代码,为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
我们可以通过下面途径查看库函数的文档,获得库函数的使用方法
MSDN(Microsoft Developer Network)
https://legacy.cplusplus.com/reference/cstdio/
https://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5
注:
使用库函数,必须包含 #include 对应的头文件。
函数的声明
告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。
函数的声明一般出现在函数的使用之前。要满足先声明后使用。
函数的声明一般要放在头文件中的
函数声明格式
ret_type fun_name(para1, * );
ret_type 返回类型
fun_name 函数名
para1, * 函数参数
无头文件的函数声明(不推荐)
add.c文件
int add(int a, int b)
{
int sum = 0;
sum = a + b;
return sum;
}
test.c文件
//函数的声明
int add(int a, int b);
//在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明
int add(int, int);
int main()
{
int res = 0;
res = add(4, 5);
printf("res = %d\n", res);
return 0;
}
有头文件的函数声明(推荐写法)
add.h文件(头文件)
#ifndef __ADD_h__
#define __ADD_h__
int add(int a, int b);
#endif
add.c文件
int add(int a, int b)
{
int sum = 0;
sum = a + b;
return sum;
}
test.c文件
#include "add.h"
int main()
{
int res = 0;
res = add(4, 5);
printf("res = %d\n", res);
return 0;
}
函数的定义
函数的定义是指函数的具体实现,交待函数的功能实现。
test.c文件
//定义函数且声明
int add(int a, int b)
{
int sum = 0;
sum = a + b;
return sum;
}
int main()
{
int res = 0;
res = add(3, 5);
printf("res = %d\n", res);
return 0;
}
函数的参数
实际参数(实参)
真实传给函数的参数,叫实参。
实参可以是:常量、变量、表达式、函数等。
无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形
参。
形式参数(形参)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
函数的调用
函数调用的格式
//无返回值调用
函数名字(函数所需参数);
//有返回值调用
数据类型 标识符 = 函数名字(函数所需参数);
传值调用
下面是交换数字的代码,我们将其运行
void swap(int a, int b)
{
int tmp = 0;
tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 6;
int y = 8;
swap(x, y);
printf("x = %d, y = %d\n", x, y);
return 0;
}
运行结果
x = 6, y = 8
哦,结果没有达到我们需要的结果,whilw(1){检查代码;}
,发现逻辑并没有错,为啥?
通过查看参数的地址值发现实参和形参的地址值并不相等,但是实参和形参的值是一样的,因为实参和形参指向的地址值不一样,所有swap函数并不能修改实参的值。
总结:
当swap函数被调用时,swap中的实参会自己开辟一块内存空间,并把实参传送过来的值拷贝一份到自己开辟的内存空间内,
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参,
所以,我们简单认为形参实例化其实相当于实参的临时拷贝。
为了解决这种问题,就有了传址调用。
传址调用
把swap函数改为传址调用
void swap(int* a, int* b)
{
int tmp = 0;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int x = 6;
int y = 8;
swap(&x, &y);
printf("x = %d, y = %d\n", x, y);
return 0;
}
运行结果
x = 8, y = 6
结果已达到我们需要的需求
把swap函数改为传址调用后,形参接收的就是x
和y
的地址值,那么我们就可以在swap函数里面更改地址指向的内存里面的值实现两个数字的交换。
总结:
函数的传址调用是把函数外部创建的变量的地址值当做实参的一种调用函数的方法。
这种传参方法可以让函数和函数外部的变量建立起联系,也就是函数可以直接操作函数的外部变量。
本文出现任何错误,欢迎留言批评指正。