Part 5 函数
概念:实现具体功能的一个模块,尽可能的功能单一。
作用:
要求:低耦合,高内聚。(对外部依赖越少越好,工作内容越单一集中越好)
函数的定义
语法:
返回类型 函数名称(数据类型 参数名1,数据类型 参数名2,…) // ()是参数列表
{
return 表达式;
} //函数体
返回值:
- 类型 int,long,double,float,char,void(表示不返回任何数据)
- 情况1 表示函数调用是否成功的状态, 0(表示调用成功) 1(调用失败)
- 情况2 计算的结果。
- 不能返回数组类型。
函数名:
- 标识符
- 字母,数字,下划线。不能以数字开头
- 见名知意
参数:
- 作用:会与其他模块进行交互。
- 如果没有参数,参数列表空着;如果有多个参数,用逗号隔开。
- 参数必须要有数字类型。
示例:
在C语言源文件(xxx.c)中,存储实现类的信息
int cmptwonum(int a, int b) // 形式参数
{
if(a>b)
{
printf("num1 > num2"\\n);
}
else
{
printf("num1 <= num2\\n");
}
return 0;
}
函数的调用
定义函数 ——> 声明 ——> 调用函数
函数的声明:
声明:告诉编译器,有这个函数。
语法:
int cmptwonum(int a, int b); // 在C语言头文件(xxx.h—)中,主要存放声明类信息
int show();
函数的调用:
调用:使用函数,()是一个运算符。
语法:
函数名(参数);
注意事项:
- 参数类型匹配,个数要相同。可以是常量、变量、表达式
- 在调用函数时,会发生跳转,从函数体开始执行,当执行完后,会发回到调用的地方
- 函数调用完成后,因为是表达式,所以有类型和值。类型和值由return返回。
示例:
int main()
{
int a =10;
int b =20;
cmptwonum(a,b); //实参
int a1 =30;
int a2 =50;
cmptwonum(a1,a2);
int a3 = 20;
int a4 =70;
cmptwonum(a3,a4);
return 0;
}
标识符的作用域和生命周期
1. 作用域
概念:能够使用变量的范围,即标识符能被使用的范围,被称为变量的作用域。
局部变量
- 在函数内部定义的变量,和函数的参数,都是局部变量。
- 被包含在{}中。
- 局部变量的作用域在离该变量定义最近的大括号里。
- 在一个局部范围内,有定义一个大括号。在大括号内部,可以有同名标识符。那么,内层变量会遮挡外层变量(外层还存在),内层只能访问到内层变量。
全局变量
- 变量可以在整个工程中都可以被访问到。
2. 生命周期
概念:从变量的创建开始,到变量对应内存空间的回收,这之间的时间就是生命周期。
局部变量生命周期
- 从定义变量开始,到函数结束。
- 从定义处开始,到最近的右大括号结束。
全局变量生命周期
- 全局变量的生命周期从 ./a.out 开始运行就创建,直到 ./a.out消亡,变量才会被回收。
- 全局变量若没有给初值,那么他的初值是0。
存储类型
存储类型 数据类型 标识符;
auto int a;
register int b;
extern int c;
static intd;
int e;
auto
自动类型,就是普通的局部变量。(栈区)
auto int a == int a; auto 可省略
register
寄存器,装变量
register int b; //告诉编译器,建议把 b 这个变量存储在 cpu 的寄存器中。
extern
extern int fun(int a, int b); //函数的声明,出现在头文件中。
extern(外部),和全局变量搭配。用于多文件编程时使用。
假如在1.c 中,定义了一个全局变量。需要在 2.c 使用1.c 中定义全局变量。就要先使用extern 声明后,才可以使用。
static
可执行程序的内存分布图

.bss 未初始化数据段,即没有给初值的全局和静态变量。
.data 给了初值的全局和静态变量。
static 用法1
static int d;
- 使用static修饰变量的话,那么这个变量会存储在静态区(数据区)。
- 从形式上看,类似全局变量类型,但会受到作用域的限制。
- 如果没有初始化,默认初值为0。
static 用法2
限制作用域,被限制的对象是全局变量或函数。
//1.c
int a = 10;
// 如果希望这个全局变量只能在本模块(1.c)中被使用
static int a = 10;
//希望fun函数只能在本模块(1.c)中被使用
static int fun(); //如果这个函数被声明为static,就不能是extern
int fun()
{
}
调用补充:实参的个数和形参的个数要相同
int fun(int num) // num 形参(形式参数)
{
printf("%d\\n", num);
………
return 0; // 返回主调的地方(fun函数当时被调用的地方)
}
int main()
{
int a = 20;
fun(a); // main 调用fun,main 函数称为主调函数,fun 是被调函数
// main 把a变量传递给了 fun 函数,a 被称为实参(实际传递的参数)
// 当函数调用完毕后,0
int ret = fun(a);
printf("%d\\n", ret); // 先对fun(a)求值,printf("%d\\n", 0);
}
形参和实参不是同一个变量,只是把a变量(实参)的内容,复制一份给num变量(形参)。

函数的传参
1. 值传递
int fun(int num) // 0
{
int result = num++; // result = 0; num =1
// num++ 对于这个表达式而言, 变量的值和表达式的值,不一样。表达式的值是0(先用后加)。变量的值是1,会产生临时变量,把num自加前的值保存并作为表达式的值,变量直接+1行。
printf("result %d\\n",result); // 0
return result; // 0 return 1,2,3,4;
}
int fun2(int a,int b,int c)
{
}
int main()
{
int i = 0 ;
fun(i); // 0 ;
fun2(1,2,(3,3,4,5,6)); // 1,2 传递多个参数 (3,3,4,5,6),逗号表达式,值是最后一个
printf("%d\\n",i );// 0 num是i的一个复制品,所有在fun中,num(形参)无论如何改变,都无法改变实参值。
return 0;
}
- 实参将值传递给形参,形参是个副本。
- 形参的值变化无法改变实参的值。
2. 地址传递
在函数调用过程中,如果传递的是数组类型,那么这种传递方式就是地址传递。也就是形参获得了实参对应内存空间的地址,所以可以通过形参修改实参的内容。
- 在被调函数中,是可以通过修改形参,来修改主调中的实参。
- 在传递数组过程中,如果使用值传递,那么被调函数中也需要创建一样大的数组。有的时候数组可能会很大。在被调函数结束的时候,这段空间就需要回收。C语言中,数组也是值传递的话,效率会很低。
- 这个就是数组传递的时候,是地址传递,而不是值传递的原因。
整型数组传参
void show_array(int a[],int nums) // int [] 地址传递
{
int i = 0 ;
//int len = sizeof(a); // 由于是地址传递 ,sizeof(a),== 8byte ,
//printf("sizeof(a) %lu sizeof(a[0]) %lu\\n",sizeof(a),sizeof(a[0]));
for(i=0;i<nums;i++)
{
printf("%d: %d\\n",i,a[i]);
}
}
void input_array(int a[],int nums) // a -> int []
{
int i = 0;
for(i=0;i<nums;i++)
{
printf("input num:");
scanf("%d",&a[i]); // a[0]–> int &a[i]
}
return ;
}
int main()
{
int a[3]={1,2,3}; // int []
printf("before:");
show_array(a,3);
input_array(a,3);
printf("\\n change after:")
show_array(a,3);
}
字符串类型传参
void show_str(char str[])
{
int i = 0 ;
for(i=0;'\\0'!=str[i];i++)
{
printf("%c",str[i]);
}
}
int main()
{
char str[100]={0};
printf("input str:");
int len = sizeof(str)/sizeof(str[0]);
my_gets(str,100); // char []
show_str(str);
//printf("str:%s\\n",);
return 0;
}
网硕互联帮助中心






评论前必须登录!
注册