在c语言中,每一个变量和函数有两个属性:数据类型数据的存储类别

C语言中局部变量和全局变量变量的存储类别(static,extern,auto,register)

1. 从变量的作用域划分变量(即从空间)角度来分

1.全局变量
2.局部变量

2. 从变量值存在的时间或存储类别(即生存期)角度来分

2.1. 静态存储区

存放下面数据: 代码段(text)仅仅读数据段(rodata)读写数据段(rwdata)未初始化数据段(bbs)

静态存储区存放所有的全局变量, 这些变量将在链接之后产生, 程序执行完成就释放, 程序执行的过程中它们占领固定的存储单元, 而不会动态的进行分配和释放

2.2. 动态存储区

存放下面数据: 函数形參自己主动变量(未加static声明的局部变量)函数调用时的现场保护和返回地址

对以上这些数据,在函数開始调用时分配动态存储空间。函数结束时释放这些空间。

3. 从用户内存空间角度分为三个部分

1. 程序区
一行一行的等待执行的机器码
2. 静态存储区
3. 动态存储区

4. 从C程序执行时又可分为下面存储区

1. 代码段 (Code | Text)

代码段由程序中执行的机器代码组成。

在C语言中。程序语句进行编译后,形成机器代码。在执行程序的过程中,CPU的程序计数器指向代码段的每一条机器代码。并由处理器依次执行。

2. 仅仅读数据段(ROData)

2.1 ROData介绍
  1. 仅仅读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式相似查表式的操作。因为这些变量不须要更改,因此仅仅须要放置在仅仅读存储器中就可以。
  2. 仅仅读数据段由程序中所使用的数据产生,该部分数据的特点是在执行中不须要改变,因此编译器会将该数据段放入仅仅读的部分中。C语言中的仅仅读全局变量仅仅读局部变量。程序中使用的常量等会在编译时放入仅仅读数据区
  3. 注意:定义全局变量const char a[100]={“ABCDEFG”};将生成大小为100个字节的仅仅读数据区,并使用“ABCDEFG”初始化。

    假设定义为:const char a[ ]={“ABCDEFG”};则依据字符串长度生成8个字节的仅仅读数据段(还有’\0’),所以在仅仅读数据段中,一般都须要做全然的初始化。

2.2 Example
#define A=18;       ##常量

const int A = 18;     ##仅仅读全局变量
int main(){
const int B = 18; ##仅仅读局部变量
}

3. 已初始化读写数据段(RW data)

3.1 RWData介绍
  1. 已初始化数据是在程序中声明,而且具有初值的变量。这些变量须要占用存储器的空间。在程序执行时它们须要位于可读写的内存区域内。并具有初值。以供程序执行时读写。
  2. 全局变量所有存放在静态存储区,在程序開始执行时给全局变量分配存储区程序行完成就释放。在程序执行过程中它们占领固定的存储单元而不动态地进行分配和释放

全局变量

静态(static) 局部变量

3.2 Example
int global_init_val=1;                   ## 全局变量
int main(int argc, char * argv[]){
static int a=1; ## 静态(static) 局部变量
}

4. 未初始化数据段(BSS)

4.1 BSS介绍

未初始化数据是在程序中声明,可是没有初始化的变量,这些变量在程序执行之前不须要占用存储器的空间。

4.1 Example
int global_noinit_val;                   ## 全局未初始化全局变量
char *p1; ## 全局未初始化全局变量 int main(int argc, char * argv[]){
......
}

5. 堆(heap)

5.1 堆空间介绍

堆内存仅仅在程序执行时出现。一般由程序猿分配释放

在具有操作系统的情况下,假设程序没有释放操作系统可能在程序(比如一个进程)结束后回收内存

5.2 Example
p1 = (char*) malloc(10);     ## 分配得来的10和20个字节的区域就在堆区
p2 = (char*) malloc(20);

6. 栈(stack)

6.1 栈空间介绍
  1. 栈内存仅仅在程序执行时出现。在函数内部使用的变量函数的參数以及返回值使用栈空间,
  2. 栈空间由编译器自己主动分配和释放。

  3. 栈空间动态开辟回收的。在函数调用过程中,假设函数调用的层次比較多,所须要的栈空间也逐渐加大
  4. 对于參数的传递返回值,假设使用较大的结构体,在使用的栈空间也会比較大
6.2 栈区主要用于下面数据的存储
  1. 函数内部的动态变量
  2. 函数的參数
  3. 函数的返回值
6.3 Example
void main(void){
  int b; ## 栈
  char s[] = "abc"; ## 栈
  char *p2; ## 栈
  char *p3 = "123456"; ## 123456\0在常量区 ## p3 在栈上。
}

===================================华丽的切割线=========================

5. 4种局部变量和全局变量的存储类别(static, extern, auto, register)

5.1 Static

有时希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。

int f(int a)
{
auto int b=0;
static int c=3;
b=b+1;
c=c+1;
return(a+b+c);
}
int main(void)
{
int a=2,i;
for(i=0;i<3;i++)
printf("%d",f(a));
}

对静态局部变量的说明:

1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个执行期间都不释放。而自己主动变量(即动态局部变量)属于动态存储类别。占动态存储空间,函数调用结束后即释放。

2)静态局部变量在编译时赋初值,即仅仅赋初值一次;而对自己主动变量赋初值是在函数调用时进行,每调用一次函数又一次给一次初值。相当于执行一次赋值语句。

3)假设在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自己主动赋初值0(对数值型变量)或空字符(对字符变量)。而对自己主动变量来说,假设不赋初值则它的值是一个不确定的值。

5.2 Extern

外部变量即全局变量)是在函数的外部定义的。它的作用域为从变量定义处開始,到本程序文件的末尾。假设外部变量不在文件的开头定义,其有效的作用范围仅仅限于定义处到文件终了。假设在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”。

表示该变量是一个已经定义的外部变量。有了此声明。就能够从“声明”处起。合法地使用该外部变量

int max(int x,int y)
{
int z;
z=x>y?x:y;
return(z);
}
int main(void)
{
extern A,B;
printf("%d\n",max(A,B));
}
int A=13,B=-8;

说明:

在本程序文件的最后1行定义了外部变量A。B,但因为外部变量定义的位置在函数main之后,因此本来在main函数中不能引用外部变量A,B。如今我们在main函数中用extern对A和B进行“外部变量声明”,就能够从“声明”处起,合法地使用该外部变量A和B。

5.3 Auto

函数中的局部变量。如不专门声明为static存储类别,都是动态地分配存储空间的。数据存储在动态存储区中

函数中的形參和在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自己主动释放这些存储空间。这类局部变量称为自己主动变量。自己主动变量用关键字auto作存储类别的声明。

int f(int a)         /*定义f函数,a为參数*/
{
auto int b,c=3; /*定义b,c自己主动变量*/
}

a是形參,b,c是自己主动变量,对c赋初值3。执行完f函数后,自己主动释放a。b,c所占的存储单元。

关键字auto能够省略,auto不写则隐含定为“自己主动存储类别”,属于动态存储方式

占用栈空间

5.4 Register

为了提高效率,C语言同意将局部变量得值放在CPU中的寄存器中,这样的变量叫“寄存器变量”,用关键字register作声明。

int fac(int n)
{
register int i,f=1;
for(i=1;i<=n;i++)
f=f*I;
return(f);
}
int main(void)
{
int i;
for(i=0;i<=5;i++)
printf("%d!=%d\n",i,fac(i));
}

说明:

1) 仅仅有局部自己主动变量和形式參数能够作为寄存器变量

2)一个计算机系统中的寄存器数目有限,不能定义随意多个寄存器变量

3)局部静态变量不能定义为寄存器变量

6. 总结

  1. 从变量的作用域(即从空间)角度来,能够分为全局变量局部变量
  2. 从变量值存在的作时间(即生存期)角度来,能够分为静态存储方式和动态存储方式。
  3. 代码段仅仅读数据段读写数据段未初始化数据段属于静态区域

    静态区域: 是指在程序执行期间分配固定的存储空间的方式

  4. 属于动态区域

    动态区域: 是在程序执行期间依据须要进行动态的分配存储空间的方式。

  5. 代码段仅仅读数据段读写数据段在链接之后产生

  6. 未初始化数据段在程序初始化的时候开辟
  7. 在程序的执行中分配和释放
  8. C语言程序分为映像执行时两种状态。

    在编译-连接后形成的映像中,将仅仅包括代码段(Text)仅仅读数据段(RO Data)读写数据段(RW Data)

  9. 程序执行之前。将动态生成未初始化数据段(BSS)
  10. 程序的执行时还将动态形成堆(Heap)区域和栈(Stack)区域。

    一般来说,在静态的映像文件里,各个部分称之为节(Section),而在执行时的各个部分称之为段(Segment)。假设不具体区分,能够统称为

  11. C语言在编译和连接后,将生成代码段(Text)、仅仅读数据段(RO Data)和读写数据段(RW Data)。

    执行时,除了以上三个区域外,还包括未初始化数据段(BSS)区域和堆(Heap)区域和栈(Stack)区域。

7. 一些实例

   const char ro[ ] = {"this is read only data"}; //仅仅读数据区

  static char rw_1[ ] ={"this is global read write data"}; //已初始化读写数据段

  char BSS_1[ 100]; //未初始化数据段

  const char *ptrconst ="constant data"; //字符串放在仅仅读取数据段

  int main()

  {

      short b; //在栈上。占用2个字节

      char a[100]; //在栈上开辟100个字节, 它的值是其首地址

      char s[ ]="abcdefg"; //s在栈上,占用4个字节,"abcdefg"本身放置在仅仅读数据存储区,占8个字节

      char *p1; //p1在栈上。占用4个字节

      char *p2="123456"; //p2 在栈上。p2指向的内容不能改,“123456”在仅仅读数据区

      static char rw_2[ ]={"this is local read write data"};//局部已初始化读写数据段

      static char BSS_2[100]; //局部未初始化数据段

      static int c = 0; //全局(静态)初始化区

      p1=(char *)malloc(10 * sizeof(char ) ); //分配内存区域在堆区

      strcpy(p1,"xxxx"); //“XXXX”放在仅仅读数据区。占5个字节

      free(p1); //使用free释放p1所指向的内存

      return 0;

  }

  读写数据段包括了忆初始化的全局变量 static char rw_1[ ]以及局部静态变量static rw_2[ ].其区别在于编绎时,是在函数内部使用的还是能够在整个文件里使用。对于rw_1[] 不管有无static 修饰。其都将被放置在读写数据区。仅仅是是否能被其他文件引用与否。

对于后者就不一样了。它是局部静态变量。放置在读写数据区,假设没static修饰,其意义全然改变,它将会是开辟在栈空间的局部变量,而不是静态变量。在这里rw_1[],rw_2[]后没具体数值。表示静态区大小同后面字符串长度决定。

  对于未初始化数据区BSS_1[100]与BSS_2[100]。其区别在于前者是全局变量。在所有文件里都能够使用;后者是局部变量,仅仅在函数内部使用。未初始化数据段不设置后面的初始化数值,因此必须使用数值指定区域的大小,编绎器将依据大小设置BSS中须要添加的长度。

參考文章

深入探讨C语言中局部变量与全局变量在内存中的存放位置

C语言编程程序的内存怎样布局

C语言编程程序的内存怎样布局的更多相关文章

  1. C语言编程程序的内存如何布局

    重点关注以下内容: C语言程序在内存中各个段的组成 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式 一:C语言程序的存储区域 由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过 ...

  2. C语言应用程序的内存图

    1.综述 c语言应用程序加载到内存,这时它所占据的内存分为四个区,分别为栈Stack,堆Heap,静态存储区Static Area,代码存储区Code Area,这四个区分别放置应用程序的不同部分,从 ...

  3. c#基础语言编程-程序集和反射

    程序集 什么是程序集? 1.程序集(assembly)是一个及一个以上托管模块,以及一些资源文件的逻辑组合. 2.程序集是组件复用,以及实施安全策略和版本策略的最小单位. 3.程序集是包含一个或者多个 ...

  4. Linux 上 C 程序的内存布局

    在仔细研究这个问题之前,我认为 C 程序在内存中只有代码段,堆和栈三部分构成.前几天面试被问到了这个问题,才发现自己的印象是不完全的. 在本文中通过解析析一个 C 程序中变量和函数的地址来分析 C 程 ...

  5. C语言程序的内存布局

    C语言程序的内存布局 一:C语言程序的存储区域 C语言编写的程序经过编绎-链接后,将形成一个统一的文件,它由几个部分组成,在程序运行时又会产生几个其他部分,各个部分代表了不同的存储区域: 1.代码段( ...

  6. Anatomy of a Program in Memory.剖析程序的内存布局

    原文标题:Anatomy of a Program in Memory 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译 ...

  7. 程序的内存分布 - 以 Linux 为例,基于 C 语言分析

    这里以 Linux 为例,用 C 语言进行演示. 内存模型 - 内存空间名称 内容 读写操作 分配时机 高地址 kernel 内核空间 命令行参数.环境变量等 不可读写 程序运行时 - stack 栈 ...

  8. 【自学编程】C语言编程简单的小程序,计算长方体体积!

    计算长方体体积 有朋友会说长方体体积还不好算吗?长X宽X高.没错用计算器一下就可以出结果,编程反而麻烦些,但是我们说的是这种思维,如果复杂的重复运算的话写好程序就非常简单了. 简单运算下一个固定高度的 ...

  9. C++核心编程 1 程序的内存模型

    1.内存分区模型 C++程序在执行时,将内存大方向划分为4个区域 代码区:存放函数体的二进制代码,由操作系统进行管理(写的所有代码都在代码区) 全局区:存放全局变量.静态变量以及常量 栈   区:由编 ...

随机推荐

  1. SQL insert 主键冲突

    待总结 https://blog.csdn.net/JavaCoder_juejue/article/details/82313891 https://blog.csdn.net/a772304419 ...

  2. 什么是事件委托?jquery和js怎么去实现?

    事件委托又叫事件代理,事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件. js: window.onload = function(){ var oul = docume ...

  3. Ansible学习记录三:配置文件

    0.配置文件 两个核心文件:ansible.cfg和hosts文件,默认都存放在/etc/ansible目录下. ansible.cfg:主要设置一些ansible初始化的信息,比如日志存放路径.模块 ...

  4. virmon防火墙64位正式版(暂定)公布

    ChangeLog: 2015-06-2564位版本号签名问题临时得到解决.还要致谢一下某位黑客. 支持版本号x64 Windows Vista.7.8.8.1以上等.个人仅仅在Windows7上做了 ...

  5. 如何创建Hiren的BootCD USB磁盘 -- 制作U盘启动盘

    如何创建Hiren的BootCD USB磁盘 原文 https://www.wintips.org/how-to-create-hirens-bootcd-usb-disk/  本文基本是谷歌翻译 H ...

  6. Cookie应用--显示看过的商品

    package cn.itcast; import java.io.IOException; import java.io.PrintWriter; import java.util.LinkedHa ...

  7. HTML5的设计目的是为了在移动设备上支持多媒体

    HTML5的设计目的是为了在移动设备上支持多媒体

  8. gulp几个常见问题及解决方案

    1. 找不到local gulp 报错代码: $ gulp [23:29:31] Local gulp not found in [23:29:31] Try running: npm install ...

  9. hibernate中的事务管理是怎么概念?

    1.JDBC事务 JDBC 事务是用 Connection 对象控制的.JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交. ja ...

  10. 洛谷——P1823 音乐会的等待

    https://www.luogu.org/problem/show?pid=1823 题目描述 N个人正在排队进入一个音乐会.人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人.队列中任 ...