目录
写在前面
一、函数的用法
1、声明
2、调用
3、定义
形参与实参类型不一致
形参与实参类型一致
函数值类型与返回值类型不一致
函数值类型与返回值类型一致
二、变量的作用域与生存周期
三、变量的储存类型(auto,extern,static,register)
写在最后
写在前面
本文不讲一些琐碎的概念,而将其实例化,来解决一些棘手的问题;
要讲函数,那得从声明、定义、调用、返回讲起
一、函数的用法
第一个函数结构。定义函数放在了调用函数之后,则需要在main函数之前进行声明。
第二个函数结构。定义函数放在了调用函数之前。那么则无需进行声明。
习惯问题:因为C语言程序总是从main函数开始,所以尽快找到main函数符合程序阅读的习惯,试想在一个很长的程序中找上半天才能找到main函数是多么不方便。
在开始之前,我们来问个小问题
1、void max( int,int )
2、void max( int a,int b );
3、max(a,b);
4、max(a,b)
上面四个代码,哪是声明,哪是调用,哪是定义
公布答案:1、2是声明,3是调用,4是定义
下面的所有实例均以这个代码来解释
#include<stdio.h>
void max(int a,int b); //函数声明
int main()
{
int a,b;
max(a,b); //函数调用
return 0;
}
void max(int a,int b) //函数定义
{
if(a>b)
return ;
else
printf("a<=b");
}
1、声明
void max( int a,int a ); 或者void max( int int );
返回类型+函数名+(参数类型1,参数类型2,...)
2、调用
max(a,b);
函数名(参数1,参数2),这里的参数是实参
3、定义
max(int a,int b){ }
函数名(类型1+参数1,类型2+参数2,...),这里的参数是形参
形参与实参类型不一致
以形参为主,因为编译器只知道形参的类型,不知道实参的类型,会将实参隐式转化为形参的类型
形参与实参类型一致
形参只能为变量,不能为常量和表达式,例如void max(7,a+b)就是错误的
函数值类型与返回值类型不一致
函数值类型与返回值类型不一致,以函数值类型为准,会把return 语句表达式的值的类型转化为函数值的类型
函数值类型与返回值类型一致
return (表达式) ---->有返回值
return 表达式 ---->有返回值
return ; ---->无返回值(void类型)
二、变量的作用域与生存周期
局部变量 | 全局变量 |
1、main()函数内定义的变量也是局部变量,它只能在主函数内使用,但由于程序总是从main函数开始,以main函数执行完毕结束,所以main函数内定义的局部变量生存周期与全局变量相同 | 4、从模块化程序设计的观点来看,这是不利的,一般不要使用全局变量 |
2、允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的内存单元 | 5、全局变量与局部变量重名时,全局变量会被屏蔽,要引用需要在变量名前加两个冒号 :: |
3、在复合语句中定义的变量是局部变量,作用域在复合语句(即{}里的一系列语句共同构成)范围内,生存周期是复合语句执行的时间段 | 6、全局变量必须在所有函数之外,若想在定义全局变量之前的位置上使用,需加扩展名extern |
概念解释
#include<stdio.h>
int fun1(int a,int b);//声明
int fun2(int ,int);
int fun3(int ,int);
int main()
{
int a=3,b=4;//对1的解释
printf("局部变量a=%d\n",a);
printf("全局变量a=%d\n",::a);//对5的解释
fun1(a,b);
fun2(a,b);
fun3(a,b);//函数调用
return 0;
}
extern int d=10;//对6的解释,让fun1也能用d=4
int fun1(int a,int b)//对2的解释
{
int c=0;//对3的解释,其他函数不能用c
}
int d=10;//全局变量,fun2之后的函数能用
int fun2(int a,int b)//对2的解释
{
...
}
int fun3(int a,int c)
{
...
}
三、变量的储存类型(auto,extern,static,register)
有关储存区的相关内存概念,大家自行搜索了解。
那我们平时做练习写的程序都是定义的什么变量呢?我们来看看吧
#include<stdio.h>
int fun1(int a,int b);//声明
int fun2(int ,int);
int fun3(int ,int);
int main()
{
static int a=3,b=4; //静态局部变量
printf("局部变量a=%d\n",a);
printf("全局变量a=%d\n",::a);
fun1(a,b);
fun2(a,b);
fun3(a,b);//函数调用
return 0;
}
extern int d;//一旦把前缀写出来,就容易把定义和扩展搞混,
//全局变量只能定义一次,没有赋值的就是扩展,赋值的就是定义
int fun1(int a,int b)
{
auto int c=0;//局部变量的默认存储方式是auto
}
extern int d=10;//全局变量默认存储方式是extern
int fun2(int a,int b)
{
...
}
auto型变量
一般情况下,在函数内或者复合语句内定义的变量,就是auto型变量
static型变量
static既能定义局部变量又能定义全局变量,那static修饰的静态局部变量和auto修饰的自动变量有何区别?static修饰的静态全局变量和extern修饰的全局变量有何区别?
静态局部变量 | 自动变量 | |
生存期 | 定义了该变量的源程序 | 函数或复合语句内 |
作用域 | 函数内或复合语句中,其他函数不能使用 | |
赋初值 | 若未赋初值,系统自动赋0; 如果已赋初始值,则再次调用函数时,就不会执行赋初始值的语句 | 若未赋初值,系统赋随机数; 如果已赋初始值,则再次调用函数时,还会重复执行赋初始值的语句 |
变量的值 | 一次调用函数完成后,变量的值会被保留,再次调用,还是原来的值 | 一次函数调用完成后,变量会被销毁,再次调用需要重新赋初始值 |
程序运行结果 | 1 2 3 4 5 | 1 1 1 1 1 |
//定义静态局部变量
#include<stdio.h>
int main()
{
int i;
void fun();
for(i=1;i<=5;i++)
fun(); //函数调用
return 0;
}
void fun()
{
static int j=0;
j++;
printf("%d ",j);
}
//定义自动变量
#include<stdio.h>
int main()
{
int i;
void fun();
for(i=1;i<=5;i++)
fun(); //函数调用
return 0;
}
void fun()
{
auto int j=0;
j++;
printf("%d ",j);
}
静态全局变量 | 全局变量 | |
生存期 | 定义了该变量的源文件 | 整个源文件 |
作用域 | 在定义了该变量的源文件内有效 | 同一源程序的所有源文件都有效 |
//假设一个源程序由源文件test_1和test_2组成
//test_1.c
int a,b; //定义全局变量
static char ch;//定义静态全局变量
int main()
{
...
}
//test_2
extern int a,b;//正确a,b是全局变量
extern char ch;//错误,ch是静态全局变量
fun()
{
...
}
写在最后
👍🏻点赞,你的认可是我创作的动力!
⭐收藏,你的青睐是我努力的方向!
✏️评论,你的意见是我进步的财富!