Hello!彦祖们,俺又回来了!!!,继续给大家分享 《C语言从不挂科到高绩点》课程!! 本节将为大家讲解C语言中的函数:
本套课程将会从0基础讲解C语言核心技术,适合人群:
- 大学中开设了C语言课程的同学
- 想要专升本或者考研的同学
- 想要考计算机等级证书的同学
- 想要从事C/C++/嵌入式开发的同学
================点个关注吧================
=========================================
7.7 变量的作用域
全局变量:定义在所有函数之外,全局变量在程序退出之前都有效。
局部变量:定义在函数内部(形式参数也属于局部变量),局部变量在函数退出的时候会被释放。
7.7.1 局部变量
局部变量的概念:凡是被一对花括号{}包裹的变量都称为局部变量。for 循环中定义的 i 是局部变量,在 main 函数中定义的变量也属于局部变量。
局部变量的特点:
- 某个函数内部的局部变量,存储在该函数的栈空间。
- 函数定义局部变量仅在函数中使用,在函数外部无法使用
- 在函数退出的时候会被回收资源,由于函数内存取消,存在其空间里面的局部变量也会被释放。局部变量也称为临时变量。
- 函数的形式参数也属于局部变量。
- return 之后不可再访问函数的局部变量,因此返回局部变量的地址是错误的
栈内存的特点:
- 每个函数被调用的时候,系统会自动分配一块内存给函数。用于存储局部变量。
- 每个函数退出的时候,系统会自动回收函数的栈内存。
- 系统为函数分配内存,遵循从上往下分配的原则。
7.7.2 全局变量
- 程序中全局变量存在于所有函数之外,包括 main 函数。
- 全局变量的作用域是整个文件,随着程序结束而释放。
- 全局变量和局部变量可以同名,当同名时,优先使用局部变量。
7.7.3 演示案例
#include <stdio.h>
// 全局变量:定义在所有函数之外的变量
int number = 100;// 全局变量
// 全局变量的作用域:整个文件,在程序结束之前,所有的函数中都可以使用
void swaps(int a,int b){ // a,b 形式参数,属于局部变量,只能在swaps函数中使用
int temp =a; // temp是在函数内部定义的变量,也属于局部变量
a = b;
b = temp;
int number = 400;// 当局部变量和全局变量重名时,会使用局部变量
printf("swap函数-number:%d\n",number);
}
void test(){
// temp是在swaps函数中定义的局部变量,只能在swaps函数局部使用
// swaps函数结束后会被回收 ,所以在其他函数中不能使用temp局部变量
//printf("temp:%d\n",temp);
printf("test函数-number:%d\n",number);// 全局变量
}
int main()
{
swaps(20,30);
test();
printf("main函数-number:%d\n",number); // 全局变量
return 0;
}
7.7.4 static 关键字
如果对于局部变量进行 static 修饰,那么该变量在定义的时候将会被分配内存(不需要等到函数被调用的时候分配内存)。直到程序结束之后才会被释放。这个 static 修饰静态局部变量只会初始化 1 次。
#include <stdio.h>
/**
如果对于局部变量进行 static 修饰,
那么该变量在定义的时候将会被分配内存(不需要等到函数被调用的时候分配内存)。直到程序结束之后才会被释放。
这个 static 修饰静态局部变量只会初始化 1 次。
**/
void show(){
// 局部变量:每次调用函数的时候,都会重新定义并且初始化
int num = 200;
num++;
printf("%d-普通的局部变量\n",num );
} // 出了这个大括号,num会被回收释放掉
void show1(){
// 被static修改的局部变量:静态局部变量
// 1. static修饰的局部变量只会初始化一次
// 2. static修饰的局部变量只有在程序结束的时候才会被回收,
// 不会因为函数结束被回收掉
static int num = 200;// 无论调用多少次函数,这个代码只执行一次,只会初始化1次
// 在后续调用中,不会再重新初始化,会直接用前面的值
num++;
printf("%d-普通的局部变量\n",num );
}
int main()
{
show(); //201
show(); // 201
show1(); // 当这个函数结束时,static修饰的num不会被回收
show1(); // 所以这几个show1() 共用的是同一个num变量
show1();
show1();
return 0;
}
7.7.5 extern 关键字
extern 关键字可以做外部全局变量的声明,表示使用的是外部文件中的全局变量。
1. 新建一个 extern1.c 源文件
#include <stdio.h>
int number = 100;
void show(){
printf("extern1.c 文件中的show函数:%d\n",number );
}
2. 新建一个 extern2.c 源文件
#include <stdio.h>
int number = 100;
void show(){
printf("extern1.c 文件中的show函数:%d\n",number );
}
3. 联合编译:将两个源文件编译成一个可执行文件
gcc extern1.c extern2.c -o main
- 编译之后,会出现如下问题:
修改 extern2.c 中的代码
#include <stdio.h>
// 注意:此处不是在定义变量,表示在引用其他文件中的number变量
extern int number; // 不做初始化
extern void show();// 表示此处引用的是外部文件的show()函数
int main(){
show();
printf("extern2.c文件中的main函数:%d\n",number); //100
return 0;
}
运行后效果:
实际开发中一个项目通常会分为不同源文件进行开发,每个源文件负责的功能不同。通常在一个源文件中引用另一个源文件中的全局变量。这个时候可以使用 extern 关键字来引用外部的全局变量。
extern int number;
当 cpu 看到了 extern 关键字,就会认为这个变量是引用的外部文件中的变量,此时就不会重新定义变量。
7.7.6 extern 注意事项
在一个项目的多个文件中,不能存在两个变量名相同的全局变量或者相同名字的函数,否则就会出错。
extern 可以解决:当一个文件中需要使用某个变量,但是这个变量已经在其他文件中定义过了,此时不能在当前文件再定义了。这个时候就可以使用 extern 关键字,去引用其他文件的变量。
使用 extern 引用外部文件全局变量时,不能赋值,一旦赋值,编译器会认为是在重新定义变量,而不是引用其他文件的变量。
例如:下面代码中给 number 赋值为 30
#include <stdio.h>
// 注意:此处不是在定义变量,表示在引用其他文件中的number变量
extern int number =30; // 不做初始化
extern void show();// 表示此处引用的是外部文件的show()函数
// int num = 30;
int main(){
show();
printf("extern2.c文件中的main函数:%d\n",number); //100
return 0;
}
在编译的时候就会出现问题:
如果声明引用外部全局变量,但是如果找不到外部全局变量时,就会出错
例如:将 extern1.c 中定义 number 代码注释掉
#include <stdio.h>
// int number = 400;
int num = 20;
void show(){
// printf("extern1.c 文件中的show函数:%d\n",number );
}
编译时,会出现找不到引用的错误:
如果全局变量不想给外部其他文件使用,可以在全局变量前面加 static
例如:在 extern1.c 定义 number 之前加一个 static
#include <stdio.h>
static int number = 400;
int num = 20;
void show(){
printf("extern1.c 文件中的show函数:%d\n",number );
}
编译之后:
特别注意!!:在一个项目的多个文件中,不能存在名字相同的多个全局变量和函数,否则编译的时候就会报multiple definition of ‘XXX’错误
7.8 自定义头文件
7.8.1 include 的用法
#include 叫做文件包含指令,用来引入对应的头文件(.h 文件)
#include 是 C 语言中预处理命令的一种,处理过程很简单,就是将头文件中的内容插入到该命令所在的位置。从而将头文件和当前源文件链接成一个源文件(实际上就是复制粘贴)
#include 的两种用法
#include <stdio.h>
#include "myhead.h"
- 使用尖括号<>, 编译器会到系统路径下查找头文件
- 使用 双引号“”,编译器首先会在当前项目目录查找头文件,如果没有找到再到系统路径下查找。
- 一般建议:引入 C 语言标准库中的头文件使用<>,引用自定义头文件使用双引号“”。
7.8.2 引入自定义头文件
新建一个源文件 my.c,添加函数
// 函数定义
int sum(int m,int n){
return m+n;
}
新建一个头文件 my.h(头文件的后缀名.h),里面添加函数的声明
int sum(int m,int n);
新建一个源文件,添加程序的入口
#include <stdio.h>
// 引入自己写的头文件my.h
#include "my.h"
// 引入头文件,实际上就是将头文件中的内容复制粘贴到此处位置上
// 所以,引入头文件“my.h”等价于在此处写了如下代码
// int sum(int m,int n);
int main(){
printf("%d\n",sum(1,4));
return 0;
}
联合编译:编译的时候,只编译.c 源文件,.h 头文件可以 不参与编译
需要注意的是:联合编译实际上就是将所有源文件中的内容编译到同一个执行程序文件中,所以会发现虽然我们在 main.c 中没有定义 sum 函数,但是可以直接使用 my.c 中的 sum 函数。导入 my.h 头文件,只是将函数声明的代码复制到了 main.c 中。
7.8.3 注意事项
一般建议不要在头文件中编写函数的定义和变量的定义。头文件中一般只包含、宏定义、结构体声明、函数声明、以及带有 extern 的全局变量的引用。
原因在于:
- 一个项目中不能同时存在多个名字相同的全局变量以及函数。
- 引入头文件,实际上相当于将头文件中的内容复制粘贴到源文件中。
- 如果说这个项目中多个源文件中同时引入了包含全局变量定义或者函数定义的头文件,就会出现multiple definition of ‘XXX’的错误
例如:如果在 my.h 中定义了变量或者函数.
int number = 10;
int sum(int m,int n);
void swap(int a,int b){
int temp = a;
a = b;
b = temp;
}
此时如果只在 main.c 中引入 my.h 头文件,代码是可以正常运行的。
但是如果在 my.c 中也引入了 my.h 头文件,那么编译的时候,就会出现问题
#include "my.h"
// int number=10;
// int sum(int m,int n);
// 函数定义
int sum(int m,int n){
return m+n;
}
错误信息如下:会显示 number 和 swap 重复定义了
所以,不要在头文件中定义变量和函数!!!!
----------------------------------------------------------------------
分享不易,耗时耗力,喜欢的同学给个关注和赞吧
承接毕设指导,技术答疑,学习路上想要找私人教练的同学可以私信我
更多学习资料,公众号:墨轩学习网,B站:墨轩大楼
----------------------------------------------------------------------
另有下图需求的也记得私信我哟,专业班子