当前位置: 首页 > article >正文

由浅到深认识C语言(6):变量的存储类型

该文章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 这一个变量
}

生命周期:离它最近的大括号有效,离开大括号的局部变量,系统自动回收;

存储区域:栈区;

注意事项

  1. 普通局部变量不初始化,内容不确定;

  2. 普通局部变量如果同名且不报错的情况下,就近原则;

    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;

生命周期:整个进程都有效,程序结束的时候,全局变量才被释放;

存储区域:全局区;

注意事项

  1. 全局变量不初始化,内容为零,原因是不初始化的话就会被放在bss段,该段会自动置零;

  2. 如果全局变量要在其他源文件中使用,必须在所使用的源文件中加 extern 声明;

  3. 如果全局变量和局部变量同名,在大括号语句中优先使用局部变量;

    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;
}

打印效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

存储区域:全局区;

注意事项

  1. 静态局部变量如果不初始化,内容为零;
  2. 只能被定义一次(重要);

静态全局变量

定义形式:在函数外边定义,同时加上 static 修饰;

#include<stdio.h>
static data = 10;//静态全局变量
void test() {
	return;
}
int main(int argc, char *argv[]) {
	return 0;
}

作用范围:当前源文件有效,不能在其他源文件使用;

生命周期:整个进程,当程序结束后,静态全局变量才会被识别

存储区域:全局区;

注意事项

  1. 静态全局变量不初始化,内容为零;
  2. 静态全局变量只在当前源文件有效;

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
    }
    

下一章:由浅到深认识C语言(7):预处理&二进制


http://www.kler.cn/a/273969.html

相关文章:

  • 计算机网络 —— 网络编程实操(1)(UDP)
  • Mybatis(day09)
  • 【HarmonyOS应用开发——ArkTS语言】购物商城的实现【合集】
  • 深入解析-正则表达式
  • 查询Mysql中被锁住的表以及如何解锁
  • 基于物联网的冻保鲜运输智能控制系统
  • 如何在 docker 容器内部运行 docker命令
  • 活动报名 | 数能涌现,三生万物,长安链发布三周年庆暨生态年会邀您共聚
  • 微信公众号 H5本地调试配置 hosts + nginx + openssl
  • 鸿蒙Harmony应用开发—ArkTS声明式开发(绘制组件:Path)
  • AI将如何影响我们的生活?
  • 快速高效地数据分析处理:QtiPlot for Mac中文直装版 兼容M
  • Codeforces Round 932 (Div. 2) D. Exam in MAC【正难则反+容斥原理】
  • 【Unity】CatlikeCoding SRP
  • PHP反序列化--pop链
  • 手势追踪技术在HTC VIVE中的应用与实现
  • USART串口
  • 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级的理解
  • 二、yocto 集成ros2(基于raspberrypi 4B)
  • 【经验分享】Wubuntu------体验Windows和Ubuntu的结合体
  • VUE3 自定义指令
  • [游戏开发][Unity] 导出Xcode工程,完成调试与发布
  • KKVIEW远程: TODESK退出了还能远程吗
  • 【C++】手撕AVL树
  • Python库Gym:打开机器学习与强化学习的大门
  • 深入解析分布式ID生成机制