该文章Github地址:https://github.com/AntonyCheng/c-notes
在此介绍一下作者开源的SpringBoot项目初始化模板(Github仓库地址:https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址:https://blog.csdn.net/AntonyCheng/article/details/136555245),该模板集成了最常见的开发组件,同时基于修改配置文件实现组件的装载,除了这些,模板中还有非常丰富的整合示例,同时单体架构也非常适合SpringBoot框架入门,如果觉得有意义或者有帮助,欢迎Star & Issues & PR!
上一章:由浅到深认识C语言(5):函数
5.变量的存储类别
5.1.内存的分区
可执行文件未运行时所占内存:
bss
段:全局未初始化数据
data
段:全局初始化数据
text
段:代码段
可执行文件运行时所占内存:
堆区:使用
malloc
,calloc
,realloc
,free
动态申请和释放栈区:局部变量/数组、函数形参以及函数中大于 4B 的返回值
全局区:全局未初始化数据,全局初始化数据,全局变量和静态变量
static
(bss
段和data
段)文字常量区:字符串常量、符号常量
代码区:代码段,二进制代码(
text
段)
各个区域的读写性:
可读可写:堆区、栈区、全局区;
只读:文字常量区、代码区;
5.2.变量类型
普通局部变量
定义形式:在 {}
(复合语句)里面定义的普通变量;
void test()
{//复合语句
int num = 0; //普通变量
}
作用范围:离它最近的大括号之间有效;
void test()
{//复合语句
int num1 = 0; //普通局部变量 num1 对外层大括号有效
{
int num2 = 0; //普通局部变量 num2 对内层大括号有效
}
printf("num2 = %d",num2); //这里会报错,找不到 num2 这一个变量
}
生命周期:离它最近的大括号有效,离开大括号的局部变量,系统自动回收;
存储区域:栈区;
注意事项:
-
普通局部变量不初始化,内容不确定;
-
普通局部变量如果同名且不报错的情况下,就近原则;
void test(){ int data = 100; { int data = 200; printf("A = %d",data); //这里 A = 200 } printf("B = %d",data); //这里 B = 100 }
但是我们要杜绝同名的情况;
普通全局变量
定义形式:定义在函数外边的变量,称之为全局变量;
int data; //这里就是普通全局变量
void test(){
}
int main(int argc,char *argv){
}
作用范围:当前的源文件都有效(可加可不加 extern),如果让这个变量在其他源文件有效的话,必须加上 extern;
#include<stdio.h>
extern int num; //由于 num 在调取函数之间,所以此处要像函数一样声明一下;
//上面的这个代码尽量加一个 extern ,保证代码的可读性;
void test01() {
printf("test01 中 num = %d\n", num);
}
int num = 100; //这里就是 num 的一个全局变量;
void test02() {
printf("test02 中 num = %d\n", num);
}
int main(int argc, char* argv[]){
printf("main 中 num = %d\n", num);
test01();
test02();
return 0;
}
//打印结果都为 num = 100;
生命周期:整个进程都有效,程序结束的时候,全局变量才被释放;
存储区域:全局区;
注意事项:
-
全局变量不初始化,内容为零,原因是不初始化的话就会被放在
bss
段,该段会自动置零; -
如果全局变量要在其他源文件中使用,必须在所使用的源文件中加 extern 声明;
-
如果全局变量和局部变量同名,在大括号语句中优先使用局部变量;
int num = 100; int main(int argc,char *argv){ num = 10; printf("num = %d",num);//这里打印出来是 num = 10 }
静态局部变量
定义形式:在大括号中定义,前面必须加 static
修饰,这样的变量叫静态全局变量;
#include<stdio.h>
void test() {
static int num;//静态局部变量;
return;
}
int main(int argc, char *argv[]) {
test();
return 0;
}
作用范围:离它最近的大括号之间有效;
#include<stdio.h>
void test() {
{
static int num;//静态局部变量;
}
printf("num = %d\n", num);//这里不识别 num
return;
}
int main(int argc, char *argv[]) {
test();
return 0;
}
生命周期:整个进程,程序结束的时候静态局部变量才被释放;
我们来比较一下普通局部变量和静态局部变量:
普通局部变量:
#include<stdio.h> void test() { int num = 10; num++; printf(" %d ", num); return; } int main(int argc, char *argv[]) { test(); test(); test(); test(); printf("\n"); return 0; }
打印效果如下:
静态局部量:
#include<stdio.h> void test() { static int num = 10; num++; printf(" %d ", num); return; } int main(int argc, char *argv[]) { test(); test(); test(); test(); printf("\n"); return 0; }
打印效果如下:
存储区域:全局区;
注意事项:
- 静态局部变量如果不初始化,内容为零;
- 只能被定义一次(重要);
静态全局变量
定义形式:在函数外边定义,同时加上 static
修饰;
#include<stdio.h>
static data = 10;//静态全局变量
void test() {
return;
}
int main(int argc, char *argv[]) {
return 0;
}
作用范围:当前源文件有效,不能在其他源文件使用;
生命周期:整个进程,当程序结束后,静态全局变量才会被识别
存储区域:全局区;
注意事项:
- 静态全局变量不初始化,内容为零;
- 静态全局变量只在当前源文件有效;
5.3.函数类型
全局函数(普通函数)
void test() {
printf("这就是一个全局函数\n");
return;
}
- **特点:**其他源文件可以使用全局函数,但是必须加
extern
声明;
静态函数(局部函数)
static void test() {
printf("这就是一个静态函数\n");
return;
}
- **特点:**其他源文件不可以直接使用静态函数,只能在当前源文件使用;
- **注意:**如果想在其他源文件直接调用静态函数,需要将静态函数封装在全局函数中,同时全局函数和静态函数必须是同一个源文件,这样可以在其他源文件中直接调用全局函数,然后由全局函数直接调用静态函数;
**案例:**计算;
-
fun1.c
int va = 7; int getG(void){ int va = 20; return va; } // va = 7(是); getG = 20;(是)
-
fun2.c
static int va = 18; static int getG(void){ return va; } int getO(void){ return getG(); } // va = 18(否); getG = 18(否); getO = 18(是);
-
main.c
#include<stdio.h> extern int va; extern int getG(void); extern int getO(void); int main(void){ printf("va = %d\n",va); //答案为 7 printf("getO = %d\n",getO()); //答案为 18 printf("getG = %d\n",getG()); //答案为 20 printf("%d\n",va*getO()*getG()); //答案为 2520 }