【C语言】存储类

存储类定义C程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。下面列出C程序中可用的存储类:auto register static extern

auto存储类

auto存储类是所有局部变量默认的存储类

{
    int mount;
    auto int month;
}

上面的实例定义了两个带有相同存储类的变量,auto只能用在函数内,即auto只能修饰局部变量

register存储类

register存储类用于定义存储在寄存器中而不是RAM中的局部变量。(需要懂些计算机组成原理来理解)这意味着变量的最大尺寸等于寄存器的大小(通常是一个字节),且不能对它应用一元的’&'运算符(因为它没有内存位置)

{
    register int miles;
}

寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义"register"并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。

static存储类

static存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用static修饰局部变量可以在函数调用之间保持局部变量的值。

static修饰符也可以应用于全局变量。当static修饰全局变量时,会使变量的作用域限制在声明它的文件内。

在C编程中,当static用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。

#include<stdio.h>
static int count=5;//全局变量 
void func(){
	static int i=5;//局部静态变量
	i++;
	printf("i is %d and count is %d\n",i,count); 
} 
int main(){
	while(count--){
		func();
	}
	return 0;
}

运行结果:

i is 6 and count is 4
i is 7 and count is 3
i is 8 and count is 2
i is 9 and count is 1
i is 10 and count is 0

静态变量属于静态存储方式,其存储空间为内存中的静态数据区(在 静态存储区内分配存储单元),该区域中的数据在整个程序的运行期间一直占用这些存储空间(在程序整个运行期间都不释放),也可以认为是其内存地址不变,直 到整个程序运行结束(相反,而auto自动变量,即动态局部变量,属于动态存储类别,占动态存储空间,函数调用结束后即释放)。静态变量虽在程序的整个执 行过程中始终存在,但是在它作用域之外不能使用。

另外,属于静态存储方式的量不一定就是静态变量。 例如:外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。

所有的全局变量都是静态变量,而局部变量只有定义时加上类型修饰符static,才为局部静态变量。

静态变量可以在任何可以申请的地方申请,一旦申请成功后,它将不再接受其他的同样申请。

静态变量并不是说其就不能改变值,不能改变值的量叫常量。 其拥有的值是可变的 ,而且它会保持最新的值。说其静态,是因为它不会随着函数的调用和退出而发生变化。即上次调用函数的时候,如果我们给静态变量赋予某个值的话,下次函数调用时,这个值保持不变。

一、静态局部变量:

1、 Static类内部变量同auto自动变量(即未加 Static 声明的局部变量)一样,是某个特定函数的局部变量,即只能在定义该变量的函数内使用该变量,二者作用域相同;两者的不同在于:auto自动变量会随着函数 被调用和退出而存在和消失,而static类局部变量不会,它不管其所在的函数是否被调用,都将一直存在;不过,尽管该变量还继续存在,但不能使用它。倘 若再次调用定义它的函数时,它又可继续使用,而且保存了前次被调用后留下的值。换言之,Static类型的内部变量是一种只能在某个特定函数中使用,但一 直占据存储空间的变量。

2、函数体内如果在定义静态变量的同时进行了初始化,则以后程序不再进行初始化操作(出现在函数内部的基本类型的的静态变量初始化语句只有在第一次调用才执行)。而对自动变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。

3、静态局部变量的初始化表达式必须是一个常量或者常量表达式。即使局部静态变量定义时没有赋初值,系统会自动赋初值0(对数值型变量)或空字符(对字符变量);静态变量的初始值为0。而对自动变量auto来说,如果不赋初值则它的值将是个不确定的值。

4、当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。

注:局部静态变量占用内存时间较长,并且可读性差,因此,除非必要,尽量避免使用局部静态变量。

#include<stdio.h>
long factor(int n)
{
    static long int f=1;
    f*=n;
    return f;
}
int main()
{
    int i;
    for (i=1; i<=5;i++)
        printf("%ld\n",factor(i)) ;
    return 0;
}

运行结果:

1
2
6
24
120

由于f为静态变量,能在每次调用后保留其值并在下一次调用时继续使用,所以输出值成为累乘的结果。若变量f说明为自动变量(去掉static),当main中多次调用factor时,f均赋初值为1

删去static运行结果:

1
2
3
4
5

二、静态全局变量

全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。
全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。
这两者在存储方式上并无不同。

这两者的区别虽在于:
1、非静态全局变量的作用域是整个源程序 ,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
2、静态全局变量则限制了其作用域, 即只在定义该变量的源文件 内有效,在同一源程序的其它源文件(即声明了该变量的CPP文件,或包含该变量声明头文件的CPP文件)中不能使用它。

由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

从以上分析可以看出————
把局部变量改变为静态变量后是改变了它的存储方式,即改变了它的生存期。
把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。

因此static这个说明符在不同的地方所起的作用是不同的。应予以注意。

关于Static关键字
1.静态变量,分配在静态存储区,在数据段中。函数退出之后,变量值不变。
2.作用域,全局的静态变量、静态函数只能在本文件中使用。(不同于一般全局变量)
局部的静态变量同函数的局部变量


以下内容做补充,在之后的学习中会理解

五大内存分区(貌似与编译原理中不一样,不过道理是一样的,实际存在的东西总是会与理论有一定差距的)
1.在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
2.栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
3.堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
4.自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
5.全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
6.常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多)

另外:

1)、static静态变量会被放在程序的全局存储区中(即在程序的全局数据区,而不是在堆栈中分配,所以不会导致堆栈溢出),这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。

2)、static静态变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。——有信息隐蔽的作用。 (外部的 Static声明亦可用于声明函数。如果将函数声明为Static类型,则该函数名除了对该函数声明所在的文件可见外,其他文件均无法访问。 )

3)、若全局变量仅在单个C文件中访问,则可将此变量改为静态全局变量,以降低模块间的耦合度;
若全局变量仅由单个函数访问,则可将此变量改为该函数的静态局部变量,以降低模块间的耦合度。

4)、设计和使用访问动态全局变量、静态全局变量、静态局部变量的函数时,需要考虑重入问题。
所谓"可重入"(也可以说是可预测的),即:只要输入数据相同就应产生相同的输出。

函数中使用了static变量,因为static变量的特征,这样的函数被称为:带“内部存储器”功能的的函数。

如果我们需要一个可重入的函数,那么,我们一定要避免函数中使用static变量,这种函数中的static变量,使用原则是,能不用尽量不用。

当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。


extern存储类

extern存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用"extern"时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用extern来得到已定义的变量或函数的引用。可以这么理解,extern是用来在另一个文件中声明一个全局变量或函数。

extern修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候,如下所示:

main.c

#include<stdio.h>
int count;
extern void write_extern();
int main(){
	count=5;
	write_extern();
	return 0;
}

support.c

#include<stdio.h>
extern int count;
void write_extern(){
	printf("count is %d\n",count);
}

在这里,第二个文件中的extern关键字用于声明已经在第一个文件main.c中定义的count.现在,编译这两个文件,如下所示:

$gcc main.c support.c

这会产生a.out执行程序,当程序被执行时,它会产生下列结果:

count is 5

C 语言中全局变量、局部变量、静态全局变量、静态局部变量的区别

一、各关键字的含义

  • auto 是局部变量的默认存储类, 限定变量只能在函数内部使用;
  • register 代表了寄存器变量,不在内存(RAM)中使用;
  • static 是全局变量的默认存储类,表示变量在程序生命周期内可见;
  • extern 表示全局变量,即对程序内所有文件可见,类似于Java中的public关键字;

二、从作用域的角度分析

1.全局变量具有全局作用域。
全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

2.静态局部变量具有局部作用域。
它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

3.局部变量也只有局部作用域。
它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

4.静态全局变量也具有全局作用域
它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量

三、从分配内存空间来分析

1、全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间

2、全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。

1)静态变量会被放在程序的静态数据存储区(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。
2)变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。

参考博文:

static静态变量的理解 - dzqabc - 博客园 (cnblogs.com)

https://blog.csdn.net/hanfengzqh/article/details/89286714

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/572231.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenHarmony开源软件供应链安全风险

慕冬亮&#xff0c;华中科技大学网络空间安全学院副教授&#xff0c;武汉英才&#xff0c;华中科技大学OpenHarmony技术俱乐部、开放原子开源社团指导教师。研究方向为软件与系统安全&#xff0c;在国际安全会议上发表十余篇论文&#xff0c;并获得ACM CCS 2018杰出论文奖。创立…

ocr文字识别软件是干什么的?

OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;文字识别软件是一种能够将图像或者扫描的文档中的文字内容转换为可编辑的文本格式的软件。它的主要功能包括&#xff1a; 1. **文字提取&#xff1a;**识别图像中的文字并提取出来&#xff0…

CSS盒子模型的认识

前言&#xff1a; 当我们打开一个网页使用F12进行调试时&#xff0c;经常可以看到如下图片&#xff0c;这便是一个盒子。 什么是盒子&#xff1a; 所谓盒子模型&#xff08;Box Model&#xff09;就是把 HTML 页面中的元素看作是一个矩形的盒子&#xff0c;也就是一个盛装内容的…

LeetCode 热题 100 Day06

矩阵相关题型 Leetcode 48. 旋转图像【中等】 题意理解&#xff1a; 将一个矩阵顺时针旋转90度&#xff0c;返回旋转后的矩阵。 要求&#xff1a; 在原地修改&#xff0c;不借助额外的空间 如果可以使用辅助数组来实现转置,则有 matrix_new[i][j]matrix[j][row-i-1]; 解…

机器人系统开发ros2-基础实践02-自定义一个机器人动作aciton服务端和客户端(c++ 实现)

aciton 是 ROS 中异步通信的一种形式。 操作客户端向操作服务器发送目标请求。 动作服务器将目标反馈和结果发送给动作客户端。 先决条件&#xff1a; 将需要上一个 教程创建操作action_tutorials_interfaces中定义的包和接口。Fibonacci.action 步骤1&#xff1a; 1.1 创建…

ComfyUI学习旅程

一、模型文件&#xff08;Checkpoint&#xff09; 首先它很大&#xff0c;这些文件是你从huggingface或者civitai下载而来的&#xff0c; 所以这些大文件如 .ckpt 或 .safetensors &#xff0c;实际上包含了什么内容呢&#xff1f; 它包含了包含了三种不同模型的权重&#x…

用wps自带工具给图片做标注

在wps中&#xff0c;选中wps中的图片&#xff0c;右键选择【编辑】进入图片编辑器&#xff0c;在选项卡面板右侧选择【标注】工具&#xff0c;再选择【添加文本】工具&#xff0c;即可直接在图片上输入文字&#xff0c;标注完成后选择【覆盖原图】就完成标注任务。

【计算机网络】网络模型

OSI七层网络模型 七层模型如图所示 每层的概念和功能 物理层 职责&#xff1a;将数据以比特为单位&#xff0c;通过不同的传输介质将数据传输出去。 主要协议&#xff1a;物理媒介相关的协议&#xff0c;如RS232&#xff0c;V.35&#xff0c;以太网等。 数据链路层 职责&…

嵌入式Linux driver开发实操(二十三):ASOC

ASoC的结构及嵌入到Linux音频框架 ALSA片上系统(ASoC)层的总体项目目标是为嵌入式片上系统处理器(如pxa2xx、au1x00、iMX等)和便携式音频编解码器提供更好的ALSA支持。在ASoC子系统之前,内核中对SoC音频有一些支持,但它有一些局限性: ->编解码器驱动程序通常与底层So…

搜维尔科技提供电影和动画的动作捕捉解决方案

电影和动画&#xff0c;实时发现讲故事的本质 讲故事的技巧已经发展到给导演比以往更多的控制力和灵活性。从实时预可视化镜头&#xff0c;到将实时镜头与直接流入您选择的工具的同步数据进行合成。动作捕捉消除了计划中的猜测&#xff0c;使不可能成为可能。 特色解决方案-行…

学习Rust的第17天:Traits

Rust traits&#xff0c;包括自定义trait声明&#xff0c;trait边界&#xff0c;实现trait的返回类型&#xff0c;条件方法实现和blanket实现。Rust的多态性严重依赖于traits&#xff0c;这允许基于trait的分派和泛型编程。掌握traits使开发人员能够创建灵活的、可维护的代码&a…

springcloud Ribbion 实战

一、Ribbon单独使用&#xff0c;配置自动重试&#xff0c;实现负载均衡和高可用 1.spring-cloud-starter-netflix-ribbon 包引入 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-ribbon</art…

20240425,模板

感觉比学C那会好了点&#xff0c;不怎么出现照着抄但是就是不能跑的情况&#xff0c;哭死&#xff0c;但是学的顺又不复习&#xff0c;第二天跟没学一样&#xff0c;笑死&#xff0c;要是能给我开个过目不忘的挂&#xff0c;爽的不要不要的 呵呵呵蠢女人&#xff0c;别忘了你C的…

服装厂生产ERP有哪些功能

在当今竞争激烈的服装行业中&#xff0c;企业如何在保证产品质量的同时提高生产效率和市场响应速度?答案在于智能化的生产管理。ERP(企业资源计划)系统作为现代企业管理的核心工具&#xff0c;对于服装厂而言&#xff0c;它的功能不仅需要全面&#xff0c;更要针对性强、操作简…

Python浅谈清朝秋海棠叶版图

1、清朝疆域概述&#xff1a; 清朝是我国最后一个封建王朝&#xff0c;其始于1616年建州女真部努尔哈赤建立后金&#xff0c;此后统一女真各部、东北地区。后又降服漠南蒙古&#xff0c;1644年入关打败农民起义军、灭南明&#xff0c;削三藩&#xff0c;复台湾。后又收外蒙&am…

展馆设计中必不可少的场景

1、一般场景展营造 一般场景是经过对实物进行概括、提炼&#xff0c;进行符号化、审美化的处理后引入展示现场&#xff0c;而并不是将与展品有关联的事物统统罗列其中。 2、复原场景营造 复原场景营造常用于博物馆、纪念馆陈列展示中。运用复原场景就是为了营造历史上曾存在的&…

java中2个List集合值和顺序完全一样,如果判断他们相等

和判断2个字符串是否相等一样&#xff0c;List可以通过equals来判断2个集合是否相等 示例代码如下&#xff1a; 1、相等的示例 2、顺序不一致 3、值不一致

简单使用优雅的程序计数器-StopWatch

一、引入hutool-core 5.8.18包 二、代码 public static void main(String[] args) throws InterruptedException {StopWatch stopWatch new StopWatch("测试StopWatch");stopWatch.start("任务1");// 任务1花费1000毫秒Thread.sleep(1000);stopWatch.st…

Python入门与进阶

基础语法语句 在线python代码运行网址 &#xff08;推荐使用python3网址&#xff09; 基础语法&输入输出 python等号赋值 赋值类型描述示例基本赋值使用等号&#xff08;&#xff09;进行赋值。x10同一个值给多个变量可以使用一个值来赋值给多个变量。xyz10多重赋值可以…

Bentley二次开发教程27-交互窗口-界面开发方法

界面设计概述 引言 在我们掌握了交互式工具的使用方法后&#xff0c;在使用过程中会发现&#xff1a;虽然工具中拥有多种交互的手段&#xff0c;但仅凭工具中鼠标&#xff0c;特殊按键与信息提示等交互方法&#xff0c;没有办法同时对多个信息进行展示&#xff0c;也不够直观…
最新文章