函数 域
- C语言--备忘
- 一、函数定义
- 二、函数声明
- 三、函数定义
- 四、函数调用
- 五、函数使用
- 形式1:无参数无返回值
- 形式2:无参数有返回值
- 形式3:有参数无返回值
- 形式4:有参数无返回值
- 形式5:有参数有返回值
- 形式6:return关键字和exit函数
- 要点说明:
- 六、函数和数组
- 七、作用域与可见性
- 局部与全局
- 形式一:局部非静态变量
- 形式二:局部 静态变量 (钉子户)
- 形式三:全局 非静态变量
- 1. 在同一源文件
- 2. 在不同源文件
- 形式四:全局 静态变量
- 总结
一、函数定义
- 函数就是一堆语句的组合,可以实现一些相对独立和通用性的功能;
- 任何C语言,包括一对变量(包括数组)和一堆的函数
- 解决繁琐代码,重复编写,加大开发量;为解决这个问题,使用函数这个技术,只需编写一遍;
- 将公共代码独立化;
return -1; //一般用来让程序结束,不能继续运行
return 0; //表示程序运行成功
- 函数声明三步骤
1.1 函数声明:告诉gcc,将来这个函数可以给别人或者自己用,函数声明不分配内存空间
1.2 函数声明的语法:
1.3 如果函数定义在函数调用之前,可以省略函数声明,否则必须声明 ;
extern 返回值数据类型 函数名(形参表)
建议:函数声明加extern ,提高代码可读性;三、函数定义
函数定义:
- 函数定义功能:就是一个函数的具体实现过程,里面包含语句,可被其他调用;
- 函数定义语法:
返回值数据类型 函数名(形参表)
{
一堆的函数体语句;
}
int add(int x, int y)
{
return x+y;
}
int main(void)
{
int sum= add(100,200);
return 0;
}
四、函数调用
- 函数调用功能:俗称使用函数,调用函数,访问函数
- 调用语法:接收函数返回值的变量 = 函数名(实参表)
- 函数调用特点:实参表- 就是给函数形参表赋值的值
sum=add(100,200);//100、200就是实参 // 实参的内存空间和形参的内存空间实独立的,地址不相同,但存储的数据相同五、函数使用 形式1:无参数无返回值
void 函数名(void)
{
函数语句;
}
形式2:无参数有返回值
int 函数名(void)
{
函数语句;
}
形式3:有参数无返回值
void 函数名(int x)
{
函数语句;
}
形式4:有参数无返回值
建议小于4个,影响运行效率
void 函数名(int x,int y,int m,int n)
{
函数语句;
}
形式5:有参数有返回值
建议小于4个,影响运行效率
int 函数名(int x,int y,int m,int n)
{
函数语句;
}
形式6:return关键字和exit函数
- return:实现函数返回
- exit: 让程序强制结束,为使用次函数需添加 #include
#include要点说明:#include void print(void) { printf("1.n"); exit(0);//程序到此结束 //return;//程序返回至main函数,继续执行 printf("2.n"); } int main(void) { print(); printf("3.n"); return 0;//让程序正常结束,0表示正常 }
#includeextern void print(int a,int b,int c, int d); extern int read(void); // 自定义 print 函数 void print(int a,int b, int c, int d) { printf("a、b、c、d的四个变量的地址为%p,%p,%p,%p",&a,&b,&c,&d); //abcd的值与main函数相同,但是地址不同 return;//只要CPU碰到return,此函数立马返回// } int read(void) { int a=250; a++; a+=250 return a;//有返回值,但是若不添加return,将返回一个随机数 } int main(void) { int a=1,b=1,c=1,d=1; //查看main函数中的地址和函数中的地址是否相同, printf("abcd的地址为%p,%p,%p,%pn",&a,&b,&c,&d); // 打印,形参和实参内存情况如下图 print(a,b,c,d); printf("read的返回值为:%dn",read()); return 0; }
注意:形参就是实参的一份拷贝,实参传递至形参时,拷贝一份。
说明:数组和参数最重要的区别在于传递地址;
void 函数名(数组的首地址,数组的长度)
{
可以查看数组元素;
可以修改数组元素;
}
案例1: 说明数组与函数关系
#includevoid print_array(int a[],int length)//a[]为数组首地址 { for(int i=0;i printf("%dn",a[i]); //数组元素可直接使用 } printf("%dn"); return; } void change_array(int a[],int length) //同理 { for(int i=0;i a[i] *=10; } return; } int main(void) { int array[5]={1,2,3,4,5}; //二维数组的sizeof(array)表示空间大小 print_array(array,sizeof(array)/sizeof(array[0])); change_array(array,sizeof(array)/sizeof(array[0])); return 0; }
案例2: 实现数组元素内容交换
- 定义两个元素的数组,利用函数将这两个元素互换
- 利用函数将数组中某个元素的第n位清零
- 利用函数将数组中某个人元素的第n位置零
#include七、作用域与可见性extern void swap(int a[],int length); void swap(int a[],int length) { int c=a[0]; a[0]=a[1]; a[1]=c; return; } void clear_array_bit(int a[],int index, int n) { a[index] &=~(1< int a[2]={1,2}; printf("打印%d%d",a[0],a[1]); swap(a,sizeof(a)/sizeof(a[0])); printf("打印%d%d",a[0],a[1]); clear_array_bit(a,3,1);//将数组的第三个元素的,第 1 位清零 return 0; }
说明:按照作用域【范围】可见性【生命周期】来分:
- 局部非静态变量
- 局部静态变量
- 全局非静态变量
- 全局静态变量
定义: 定义在函数内部
void A(void)
{
int a=250;//此为局部变量
}
定义: 定义为函数之外的变量
int g_b=520;//全局变量
void A(void)
{
int a=250;//此为局部变量
}
int g_c=521;//全局变量
形式一:局部非静态变量
1. 定义:static关键字:如果定义变量前面加static关键字修饰,表明为静态变量;
2. 变量使用范围:从定义的地方开始,从定义的地方开始一次向下直到最近的花括号结束;
3. 内存生命周期:从定义的地方,操作系统会给变量分配内存,直到最近的花括号,操作系统会立马收回变量的内存;
4. 函数形参:void A(int a); //a在整个函数体都可以用,出了函数就不能用,以下代码说明:
形式1:
void A1(int c)
{
printf("a=%dn",a);//不可以,报错,gcc编译时报没有定义的错误
int a=250;//定义 局部非静态变量
printf("a=%dn",a);//可以
print("c=%dn",c);//c变量只能在函数内部使用,不允许在main函数使用
}
形式2:
void A2(void)
{
if(1){
int a=250; //此变量的作用域为最靠近的花括号{}之内,出了范围就消亡
printf("a=%dn",a);//可以
}
printf("a=%dn",a);//不可以,报错,gcc编译时报没有定义的错
}
int main()
{
A1(23);
A2();
return 0;
}
形式二:局部 静态变量 (钉子户)
1. 变量使用范围:从定义的地方开始,从定义的地方开始一次向下直到最近的花括号结束;
2. 内存生命周期:定义的地方开始分配内存直到程序结束;一次分配,程序不结束下一次不会分配内存,接着上一次的用;/重要程序不结束,下一次就不会重新分配内存;
void A1()
{
static int a=250;//定义 局部静态变量
printf("a=%dn",a);//可以
a= 10;
}
int main(void)
{
A1();//输出a=250
A1();//不会再给 static int a 分配内存,相当于语句不执行,接着上次使用,a=10;
return 0;
}
形式三:全局 非静态变量
1. 在同一源文件
1. 变量使用范围:全局非静态变量的定义和使用访问都是在同一个文件
2. 内存生命周期:定义的地方开始分配内存直到程序结束;
void B(void)
{
printf("g_a=%dn",g_a);//不可以,gcc报没有定义的错误
}
int g_a=10;//定义初始化为全局非静态变量,只从定义的地方开始,到程序结束;
void A(void)
{
printf("g_a=%dn",g_a);//可以,函数内部访问全局非静态变量
}
2. 在不同源文件
1. 明确:如果一个源文件定了一个全局非静态变量,另外一个文件想要直接访问这个全局非静态,只需要extern 声明这个全局非静态即可
2. 语法:声明全局非静态变量的语法:extern 数据类型 全局非静态变量名;
3. 结论:一旦声明,就可以访问别的文件定义好的全局非静态变量。
4. 切记:变量使用范围分两种情况:
- 如果本文件访问,范围为定义的地方开始向下可以访问,前面的不可以;
- 如果是不同文件(跨文件)之间访问,范围是声明的地方依次向下所有的函数都可以访问;
- 此变量生命周期:从启动运行程序时,操作系统就会分配内存;知道程序结束,操作系统回收。
- 切记:全局非静态变量实际开发时少用,慎用,避免出现乱序,一定记得互斥访问保护,但是降低执行效率。
// #include形式四:全局 静态变量int g_a=250; void A(void) { printf("A函数:g_a=%dn",g_a); } void B(void) { g_a++; } *vim func2.c* #include extern void A(void); extern void B(void);//由于跨文件访问函数,故调用前需要声明才行 extern int g_a;//由于跨文件访问变量,故调用前需要声明才行 int main(void) { A();//打印250 B();//变量自加1 A();//打印251 printf("g_a=%d",g_a); return 0; } /最后执行 gcc -o func1 func1.c func2.c
- 全局 静态变量的定义和使用访问都是在同一个文件
- 全局静态变量只能用于本文件,其他源文件不可访问;
- 能降低乱序的可能性;
- 只能用于定义变量的文件中,而且从定义的地方开始。
- 生命周期:启动程序开始,分配内存,直到结束再将内存收回。
- 少用、慎用,迫不得已,互斥访问,但是比全局非静态发生乱序的现象要小;
// vim var.c #include总结void B(void) { printf("g_a=%dn",g_a);//不可以,gcc报没有定义的错误 } static int g_a=10;//定义初始化为全局静态变量,只从定义的地方开始,到程序结束; void A(void) { printf("g_a=%dn",g_a);//可以,函数内部访问全局非静态变量 } static void C(void)//vim var1.c无法访问此函数 { g_a--; } /vim var1.c #include extern void B(void);//声明函数A extern void A(void) ;//声明函数B extern g_a; //声明全局变量g_a,报错 int main(void) { B(); A(); C();//报错 return 0; } gcc -o var var.c var1.c
- static修饰的全局变量只能用于本文件,其余文件不允许。
- static 修饰的函数只能用于本文件,其他文件不能访问。
- static 的变量和函数用起来 相对安全,间接保护,降低乱序发生概率
- 抢夺CPU能力:A程序



