C++局部变量、全局变量、静态变量(堆、栈、静态存储区)

1 static关键字

1.1 隐藏

eg:

//a.c文件中

char a = ‘A‘;

void msg()

{

printf("Hello\n");

}

//main.c文件中

extern char a;

printf("%c",a);

输出结果:A Hello

所有未加static前缀的全局变量和函数都具有全局可见性,其它的源文件也能访问。a是全局变量,msg是函数,并且都没有加static前缀,因此对于另外的源文件main.c是可见的。

如果加了static,就会对其它源文件隐藏。例如在a和msg的定义前加上static,main.c就看不到它们了。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏。

1.2 保持变量内容的持久(static变量中的记忆功能和全局生存期)

eg:

#include <stdio.h>

int fun(){

static int count = 10; //在第一次进入这个函数的时候,变量a被初始化为10!并接着自减1,以后每次进入该函数,a

return count--;    //就不会被再次初始化了,仅进行自减1的操作;在static发明前,要达到同样的功能,则只能使用全局变量:

}

int count = 1;

int main(void)

{

printf("global\t\tlocal static\n");

for(; count <= 10; ++count)

printf("%d\t\t%d\n", count, fun());

return 0;

}

输出结果:

global  local static

1 10

2 9

3 8

4 7

5 6

6 5

7 4

8 3

9 2

10 1

存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,说到底static还是用来隐藏的。

---基于以上两点可以得出一个结论:把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。

1.3 默认初始化为0(static变量)

其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,某些时候这一特点可以减少程序员的工作量。比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’;太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是‘\0’。

1.4 C++中的类成员声明static(有些地方与以上作用重叠)

静态成员函数不含this指针。

静态成员是可以独立访问的,也就是说,无须创建任何对象实例就可以访问。

类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致 了它仅能访问类的静态数据和静态成员函数。

2 局部变量、全局变量、静态变量

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

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

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

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

3 堆

亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。 但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。

在C++中需要开辟内存单元的时候

char* str = new char[100];

使用完之后一定要记得释放内存单元

delete[] str;

str = 0;

4 栈

在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

int a;

5 静态存储区

内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。

全局变量

static修饰的变量或函数等

下面我们来看看这几种存储区的区别:

示例1:静态存储区与栈区

char* p = "Hello World1";

char a[] = "Hello World2";

p[2] = ‘A‘;

a[2] = ‘A‘;

char* p1 = "Hello World1";

这个程序是有错误的,错误发生在p[2] = ‘A‘这行代码处,为什么呢,是变量p和变量数组a都存在于栈区的(任何临时变量都是处于栈区的,包括在main()函数中定义的变量)。但是,数据“Hello World1”和数据“Hello World2”是存储于不同的区域的。因为数据“Hello World2”存在于数组中,所以,此数据存储于栈区,对它修改是没有任何问题的。因为指针变量p仅仅能够存储某个存储空间的地址,数据“Hello World1”为字符串常量,所以存储在静态存储区。虽然通过p[2]可以访问到静态存储区中的第三个数据单元,即字符‘l‘所在的存储的单元。但是因为数据“Hello World1”为字符串常量,不可以改变,所以在程序运行时,会报告内存错误。并且,如果此时对p和p1输出的时候会发现p和p1里面保存的地址是完全相同的。

示例2:栈区和堆区

char* f1()

{

char* p = NULL;

char a;

p = return p;

}

char* f2()

{

char* p = NULL;

p = (char*)new char[4];

return p;

}

这两个函数都是将某个存储空间的地址返回,二者有何区别呢?f1()函数虽然返回的是一个存储空间,但是此空间为临时空间。也就是说,此空间只有短暂的生命周期,它的生命周期在函数f1()调用结束时,也就失去了它的生命价值,即:此空间被释放掉。所以,当调用f1()函数时,如果程序中有下面的语句:

char* p;

p = f1();

*p = ‘a‘;

此时,编译并不会报告错误,但是在程序运行时,会发生异常错误。因为,你对不应该操作的内存(即,已经释放掉的存储空间)进行了操作。但是,相比之下,f2()函数不会有任何问题。因为,new这个命令是在堆中申请存储空间,一旦申请成功,除非你将其delete或者程序终结,这块内存将一直存在。也可以这样理解,堆内存是共享单元,能够被多个函数共同访问。如果你需要有多个数据返回却苦无办法,堆内存将是一个很好的选择。

总之,对于堆区、栈区和静态存储区它们之间最大的不同在于,栈的生命周期很短暂。但是堆区和静态存储区的生命周期相当于与程序的生命同时存在(如果您不在程序运行中间将堆内存delete的话),我们将这种变量或数据成为全局变量或数据。但是,对于堆区的内存空间使用更加灵活,因为它允许你在不需要它的时候,随时将它释放掉,而静态存储区将一直存在于程序的整个生命周期中。

时间: 2024-11-19 16:35:16

C++局部变量、全局变量、静态变量(堆、栈、静态存储区)的相关文章

关于静态变量和非静态变量的区别

关于静态变量和非静态变量的区别 静态变量:被static修饰的变量,加载类的时候被创建,不随对象的创建而改变,静态变量位于方法区,类消失对应的变量消失. 非静态变量:不被static修饰的变量,每创建一次对象,就会为变量分配一次内存,存放在堆内存中,对象消失对应的变量消失. JAVA中初始化的顺序: 加载类: 静态变量初始化 静态代码块:[其只能调度静态的,不能调度非静态的] 成员变量 构造代码块 构造方法 普通代码块 原文地址:https://www.cnblogs.com/wangwswan

【C语言】局部变量、全局变量,局部静态变量,全局静态变量,extern,static的区别

局部变量: 创建在栈区(向下生长),生命周期存在于当前作用域中.     创建时若未初始化,则为随机值. 全局变量: 创建在static区,生命周期一直存在. 创建时若未初始化,则为0. 静态局部变量: 切断了外部链接属性.创建在static区. 创建时若未初始化,则为0. 全局变量和静态变量的存储是放在一块的,初始化了的全局变量和静态变量在一块区域,  未初始化的全局变量和未初始化的静态变量在相邻的另一块区域. 全局静态变量: 切断了外部链接属性,创建在static区,生命周期一直存在. 创建

堆/栈/动态存储方式/静态存储方式

动态存储方式 所谓动态存储方式是指在程序运行期间根据需要进行动态的分配存储空间的方式.动态存储变量是在程序执行过程中,使用它时才分配存储单元, 使用完毕立即释放. 典型的例子是函数的形式参数,在函数定义时并不给形参分配存储单元,只是在函数被调用时,才予以分配, 调用函数完毕立即释放.如果一个函数被多次调用,则反复地分配. 释放形参变量的存储单元. 静态存储方式 所谓静态存储方式是指在程序编译期间分配固定的存储空间的方式.该存储方式通常是在变量定义时就分定存储单元并一直保持不变, 直至整个程序结束

c进阶1(堆,栈,静态区,代码区)

一.内存四大区域 1.栈 先进后出 栈的大小固定,默认1M,可以编译的时候设置,超出则溢出 变量离开作用范围后,栈上的数据会自动释放 栈是连续的,向上增长 #include<stdio.h> #include <stdlib.h> void go(); void main() { void *p1 = malloc(10); //p1,p2栈上 void *p2 = malloc(20); //00A0F914, 00A0F908 printf("%p,%p",

c#静态变量和非静态变量的区别

静态变量的类型说明符是static.静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量,例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量. 详解: 一,静态资源在首次访问时会调用静态构造器创建类类型对象(静态属于类,动态属于对象,静态被静态构造器创建,动态被普通构造创建,所以实例对象的时候,静态不会被重新构造), 二,类型对象的生存周期是整个应用程序域的生存周期,也就说被访问过的静态资源,只有它所在的

Static静态变量和非静态变量

Static静态变量:   不同的对象共享这个变量的存储空间 而不是静态变量   每个对象具有可变的存储器空间 public class StaticDemo { private int count=0; private static int staticCount=0; public StaticDemo() { System.out.println(++count); System.out.println(++staticCount); } public static void main(S

java 成员变量 静态变量代码块 静态代码快加载顺序

序言 基类A 类B继承实现了A类 1在new B一个实例时首先要进行类的装载.(类只有在使用New调用创建的时候才会被java类装载器装入)2,在装载类时,先装载父类A,再装载子类B3,装载父类A后,完成静态动作(包括静态代码和变量,它们的级别是相同的,安装代码中出现的顺序初始化)4,装载子类B后,完成静态动作类装载完成,开始进行实例化1,在实例化子类B时,先要实例化父类A2,实例化父类A时,先成员实例化(非静态代码)3,父类A的构造方法4,子类B的成员实例化(非静态代码)5,子类B的构造方法

Java的外部类和内部类+静态变量和非静态变量的组合关系

看的李刚<疯狂java讲义>,里面讲内部类的地方感觉有点散而且不全,看完之后还是不十分清楚到底怎么用,于是自己写了个程序测试了一下.看如下代码,即可知道外部类和内部类+静态成员和非静态成员之间的相互调用规则. 运行结果如下: 总结如下: 注意: 当如下出现报错:“无法从静态上下文中引用非静态时”,问题在于非静态方法或者非静态变量所属的类可能没有被实列化.因为要使用非静态方法,必须实例化它所属的类. 例如:将第40行代码改成inter2.StaticInter(); 编译: 原因是StaticI

【转载】程序中的堆 栈 可读写数据区 常量区 代码区

一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 .注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵. 3.全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块

iOS 局部变量 全局变量 成员变量

一.成员变量 : 写在类声明的大括号中的变量叫成员变量 (也叫属性/实例变量) 成员变量不可离开类 离开了类就不是成员变量 成员变量不能再定义的同事初始化 成员量只能通过对象来访问 成员变量存储在堆中(当前对象对应的堆得存储空间中) 不会被系统自动释放 只能有程序员手动释放 二.局部变量 :写在代码块或函数中的变量为局部变量  局部变量的作用域 : 从定义的那一行开始,一直到遇到大括号或return(也就是这个变量所在的代码块或函数结束时) 局部变量可以先定义后初始化,也可以在定义的同时就初始化