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

本文详细介绍了C++中的局部变量、全局变量、静态变量及其存储方式,包括堆、栈和静态存储区的特点与区别。并通过具体示例阐述了static关键字的不同应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:点击打开链接

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的话),我们将这种变量或数据成为全局变量或数据。但是,对于堆区的内存空间使用更加灵活,因为它允许你在不需要它的时候,随时将它释放掉,而静态存储区将一直存在于程序的整个生命周期中。

<think>首先,用户的问题是关于理解局部变量全局变量静态变量和非静态变量的区别及用法。关键点是:区别、使用场景和编程概念。我有系统级指令:必须使用中文回答;数学表达式使用$...$或$$...$$;生成相关问题;引用的段落末尾添加引用标识如[^1]。用户提供的引用是站内引用[^1]、[^2]、[^3],但它们只是模拟引用,我需要在回答中自然地引用这些内容。引用中提到:-[^1]:全局变量静态全局变量静态局部变量的区别:存储位置(静态存储区),生命周期(和程序一样),作用域不同。默认值为0。-[^2]:全局变量(不加static)有外部链接性,作用域是整个工程;静态全局变量(加static)作用域是定义的文件。其他特点如extern的用法。-[^3]:静态变量定义:使用static关键字,在运行期间分配固定存储空间。外部变量是静态存储,但不一定是static变量;自动变量可用static定义为静态局部变量。用户指定参考这些引用,但说我应该参考用户上一次的问题和我的回答。用户上一次的问题是:“我想了解局部变量全局变量静态变量和非静态变量的区别及用法请问局部变量全局变量静态变量静态变量区别使用场景编程概念”,所以没有历史对话,这似乎是第一次互动。我需要基于这些引用构建回答,同时确保内容真实可靠。组织回答结构:1.**清晰结构**:帮助用户逐步解决问题。介绍变量类型,然后讨论区别、使用场景和编程概念。2.**定义关键变量**:-局部变量:在函数内部定义,作用域是函数内部,生命周期是函数执行期间。-全局变量:在函数外部定义,作用域是整个程序(或文件,视语言而定),生命周期是整个程序运行期间。-静态变量:用static关键字修饰的变量,可以用于局部或全局,改变存储位置和生命周期。-非静态变量:这里可能指的是自动变量(如局部变量)或普通全局变量。用户说“非静态变量”,可能对应于静态的对立面。在上下文中,非静态可能包括局部变量和未加static的全局变量。引用中提到“全局变量”和“静态变量”,[^2]区分了全局变量静态全局变量,[^3]讨论了静态局部变量。所以,分类一下:-**局部变量**:无static的,在函数内部定义,自动存储。-**静态局部变量**:有static,在函数内部,但生命期长(程序结束),只初始化一次。-**全局变量**:无static,外部链接,作用域全局。-**静态全局变量**:有static,内部链接,作用域文件级。用户说“非静态变量”,可能泛指不是static的变量,包括普通局部变量全局变量。3.**区别**:-**作用域**:局部变量仅函数内;全局变量全局;静态变量依赖于定义位置。-**生命周期**:局部变量函数执行期间;全局和静态变量程序运行期间。-**存储位置**:局部变量;全局和静态静态存储区(BSS或数据段)。-**默认值**:全局和静态变量默认0;局部变量未定义。-**链接性**:全局变量有外部链接;静态变量(全局或局部)有内部链接(或无外部链接)。-引用[^1]和[^2]覆盖了这些。4.**使用场景**:-**局部变量**:函数内部临时存储,避免全局污染。-**静态局部变量**:需要保持状态跨函数调用,如计数器。-**全局变量**:程序级共享数据,但要谨慎使用,避免耦合。-**静态全局变量**:文件内共享数据,限制作用域。5.**编程概念**:解释static关键字的含义;内存管理;变量范围和生命周期。在回答中自然地引用提供的引用。例如,当提到区别时,添加[^1]或[^2]。确保使用中文。最后,生成相关问题,以“§§相关问题§§”开头,就像系统级指令的示例。结构回答:-引言:概述变量类型。-部分1:定义和区别。-部分2:详细区别(表或段落)。-部分3:使用场景。-部分4:编程概念和最佳实践。-结尾:总结。添加引用:在相关语句的末尾添加,例如,“全局变量静态变量存储在静态存储区中[^1]”。数学表达式:如果需要,但在这个主题中可能没有,所以小心处理。如果有计算,但这里主要是定义。生成3-4个相关问题。完整回答框架:1.**介绍**:简要解释这些变量类型在编程中的重要性。2.**定义**:-局部变量-全局变量-静态变量(包括静态局部和静态全局)-解释“非静态变量”–可能包括普通局部变量全局变量。3.**关键区别**:对比作用域、生命周期、存储、默认值等。4.**使用场景**:举例说明何时使用每种。5.**编程概念**:讨论static关键字、内存模型等。6.**总结**。然后**相关问题**。引用添加:如“全局变量存储在静态存储区[^1]”或“静态全局变量作用域仅限于文件内[^2]”。</think> ### 局部变量全局变量静态变量和非静态变量的区别及用法 在编程中,变量根据作用域、生命周期和存储位置分为不同类型。理解这些概念对于写出高效、可维护的代码至关重要。这里,我们将基于提供的引用和标准编程原理,逐步解析局部变量全局变量静态变量和非静态变量的区别、使用场景和编程概念。讨论的语言环境主要集中在C/C++等系统级语言,但原理也适用于其他编程语言。 #### 1. 基本定义 - **局部变量**:在函数内部定义,作用域仅限于定义它的函数内部。生命周期是函数执行期间;函数结束时,变量被销毁。默认值未定义(需手动初始化),存储于上。例如: ```c void func() { int localVar = 10; // 局部变量,只在func内可见 // 代码使用localVar } ``` 如果未初始化,访问局部变量可能导致未定义行为。 - **全局变量**:在函数外部定义(文件作用域),作用域是整个程序(通过`extern`实现跨文件访问)。生命周期是整个程序运行期间,存储在静态存储区(如`.data`或`.bss`段)。默认值为0(如果未初始化)。全局变量不加`static`关键字,有外部链接性。例如: ```c int globalVar = 20; // 全局变量,可在其他文件通过extern访问 ``` - **静态变量**:使用`static`关键字定义的变量,根据位置分为两类: - **静态局部变量**:在函数内部定义,作用域仅限于该函数,但生命周期是整个程序运行期间。只初始化一次(首次调用时),存储在静态存储区。默认值为0。例如: ```c void counter() { static int staticLocal = 0; // 静态局部变量,保持状态跨调用 staticLocal++; } ``` - **静态全局变量**:在文件外部定义(但加`static`),作用域仅限于当前文件(内部链接)。生命周期是整个程序,存储在静态存储区。默认值为0。例如: ```c static int staticGlobal = 30; // 静态全局变量,不可被其他文件访问 ``` - **非静态变量**:这是一个相对概念,指“没有`static`关键字的变量”。在上下文中,非静态变量包括: - **非静态局部变量**:普通局部变量(如上定义的局部变量),动态存储。 - **非静态全局变量**:普通全局变量(如上定义的全局变量),有外部链接。 非静态变量强调动态性和灵活性,而非静态存储。它们的区别在于是否使用了`static`修饰。 全局变量静态变量(无论全局或局部)都存储在静态存储区中,生命期和程序一样,但作用域不同:全局变量作用域是整个项目,静态全局变量是当前文件,静态局部变量则仅限于函数内[^1]。静态变量必须由`static`显式定义,而外部变量(全局变量)本质是静态存储方式,但需注意链接性[^3]。 #### 2. 关键区别 下表总结了核心差异(基于引用[^1][^2][^3]和标准实践): | **特性** | **局部变量(非静态)** | **全局变量(非静态)** | **静态局部变量** | **静态全局变量** | **非静态变量(总结)** | |----------------|------------------------------|-------------------------------|-------------------------|-------------------------|-----------------------------| | **定义位置** | 函数内部 | 文件外部 | 函数内部加`static` | 文件外部加`static` | 无`static`(局部或全局) | | **作用域** | 定义函数内部 | 整个程序(通过`extern`链接) | 定义函数内部 | 当前文件 | 非静态局部:函数内;非静态全局:全局 | | **生命周期** | 函数执行期间 | 程序运行期间 | 程序运行期间 | 程序运行期间 | 非静态局部:短;非静态全局:长 | | **存储位置** | 上 | 静态存储区(`.bss`/`.data`) | 静态存储区 | 静态存储区 | (局部)或静态存储区(全局) | | **默认值** | 未定义(可能垃圾值) | 0 | 0 | 0 | 局部:未定义;全局:0 | | **链接性** | 无链接(外部不可访问) | 外部链接(可`extern`跨文件) | 无链接 | 内部链接(文件内) | 非静态全局:外部链接 | | **关键字** | 无(隐含自动) | 无 | `static` | `static` | 无`static` | 关键点: - **作用域 vs 生命周期**:局部变量作用域短、生命周期短,而静态变量作用域有限但生命周期长。例如,全局变量可被多个函数访问,但可能导致代码耦合;静态全局变量限制作用域,避免命名冲突[^2]。 - **非静态变量用法**:非静态局部变量适合临时计算,非静态全局变量用于全局状态,但都需谨慎初始化。 - **默认值差异**:未初始化时,全局变量静态变量默认为0,这得益于静态存储区的特性;局部变量则需显式初始化以防错误[^1]。 #### 3. 使用场景 - **局部变量(非静态)**:适用于函数内部临时数据(如循环计数器、计算中间值)。使用场景:避免全局变量,提高代码模块化。例如,在排序算法中使用局部变量存储临时数组。 - **静态局部变量**:当需要函数调用间保持状态时(如计数器、缓存机制)。使用场景:单例模式实现或性能优化(避免多次初始化)。例如,一个登录系统的尝试次数计数。 - **全局变量(非静态)**:用于程序级共享数据(如配置参数、全局状态)。使用场景:跨模块通信,但容易导致副作用,建议少用(改用参数传递或封装)。 - **静态全局变量**:适用于文件内共享数据,隐藏内部实现(如工具函数的状态)。使用场景:限制变量作用域以增强封装性,防止外部误用。 - **非静态变量总结**:优先使用非静态局部变量确保线程安全和可读性;非静态全局变量仅当必需时,配合`extern`声明使用。 编程最佳实践: - 避免过度使用全局变量:易导致耦合和调试困难,推荐通过参数传递或静态局部变量替代。 - 静态变量优势:默认0、内存高效(固定存储),但需注意初始化点(如静态局部只初始化一次)。 - 内存模型影响:全局和静态变量静态存储区(程序加载时分配),局部变量上(函数动态管理),这可能影响性能和资源占用[^3]。 #### 4. 编程概念与总结 在编程中,`static`关键字是核心概念: - 当用于局部变量时,它改变生命周期而不改变作用域(固定存储)。 - 当用于全局变量时,它改变链接性(从外部到内部)。 - 非静态变量代表默认动态行为:局部变量是自动存储,全局变量是全局访问。 总结区别: - **局部 vs 全局**:作用域隔离是键;局部防止命名冲突,全局易用但风险高。 - **静态 vs 非静态**:`static`添加“持久性”或“本地化”,优化状态管理和内存使用。 实际例子: ```c // 文件1.c #include <stdio.h> int globalVar = 0; // 非静态全局变量,可extern访问 static int staticGlobal = 1; // 静态全局变量,文件内可见 void func() { int localVar = 2; // 非静态局部变量,每次调用重建 static int staticLocal = 3; // 静态局部变量,保持值 staticLocal++; printf("局部: %d, 静态局部: %d\n", localVar, staticLocal); } // 文件2.c extern int globalVar; // 正确:访问非静态全局变量 // extern int staticGlobal; // 错误:静态全局不可跨文件访问 ``` 在这个例子中,`staticLocal`维持状态,`globalVar`可全局共享,而`localVar`只在函数内有效。这表明了各变量在内存模型中的应用。 通过合理选择变量类型,可以平衡性能和可维护性。全局和静态变量存储在静态存储区,但作用域控制是关键[^1];static定义静态变量,改变了外部变量的行为[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值