全局变量和局部变量在内存里的区别?堆和栈

本文深入解析了程序内存分配中的堆和栈的区别,包括它们的申请方式、系统响应、大小限制及存取效率等内容。通过具体实例说明了全局变量与局部变量在内存中的不同存储位置。

全局变量和局部变量在内存里的区别?堆和栈
转:一、预备知识—程序的内存分配
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
二、例子程序
这是一个前辈写的,非常详细

//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b;// 栈
char s[] = “abc”; //栈
char *p2; //栈
char *p3 = “123456”; 123456/0”;//在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1, “123456”); //123456/0放在常量区,编译器可能会将它与p3所指向的”123456”优化成一个地方。
}

三、堆和栈的理论知识
3.1申请方式
stack:
由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间
heap:
需要程序员自己申请,并指明大小,在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用new运算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在栈中的。
3.2 申请后系统的响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
3.3申请大小的限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
3.4申请效率的比较:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活
3.5堆和栈中的存储内容
栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。
3.6存取效率的比较
char s1[] = “aaaaaaaaaaaaaaa”;
char *s2 = “bbbbbbbbbbbbbbbbb”;
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:

include

<think>我们正在讨论面试中关于全局变量局部变量的常见问题。根据引用内容,我们可以总结出以下关键点: 1. **引用[1]**:提到了局部变量可以与全局变量同名,在函数内引用时优先使用局部变量。还提到如何引用已定义的全局变量(可能需要使用`extern`关键字)[^1]。 2. **引用[2]**:说明了未初始化的全局数组在BSS段的处理方式,以及`const`全局变量的不同(可能存储在只读数据段)[^2]。 3. **引用[3]**:区分了内存区域(、静态存储区、常量区),并指出全局变量静态变量存储在静态存储区[^3]。 4. **引用[4]**:展示了C++中通过常引用传递大对象以避免拷贝并保护数据,这间接涉及变量作用域生命周期的概念[^4]。 5. **引用[5]**:给出了JavaScript中全局变量局部变量的例子,展示了变量提升函数作用域的行为[^5]。 基于这些引用,我们可以整理出面试中关于全局变量局部变量的常见问题及解答: ### 1. **全局变量局部变量区别** - **作用域**:全局变量在整个程序中都可见;局部变量仅在定义它的函数或块内可见。 - **生命周期**:全局变量在程序运行期间一直存在;局部变量在函数调用时创建,函数结束时销毁。 - **存储位置**:全局变量存储在静态存储区(或BSS段);局部变量存储在上(引用[3])[^3]。 - **初始化**:未初始化的全局变量默认为0(或空指针);未初始化的局部变量值是未定义的(可能为随机值)。 ### 2. **同名变量优先级问题** - 当局部变量全局变量同名时,在函数内部优先使用局部变量(引用[1])[^1]。 - 若需在函数内访问同名的全局变量,需使用作用域解析符(如C++的`::`)或`extern`关键字(C语言)。 ### 3. **如何引用已定义的全局变量?** - 在C/C++中,若要在其他文件中使用全局变量,需用`extern`关键字声明(引用[1])[^1]。例如: ```c // file1.c int global_var = 10; // file2.c extern int global_var; // 声明使用外部定义的全局变量 ``` ### 4. **静态全局变量与普通全局变量区别** - 静态全局变量(`static`修饰)的作用域仅限于定义它的文件,其他文件无法通过`extern`访问(防止命名冲突)。 - 普通全局变量可在其他文件中通过`extern`访问。 ### 5. **静态局部变量与普通局部变量区别** - **生命周期**:静态局部变量在程序运行期间只初始化一次,且生命周期持续到程序结束;普通局部变量随函数调用结束而销毁。 - **存储位置**:静态局部变量存储在静态存储区;普通局部变量存储在上(引用[3])[^3]。 ### 6. **变量默认初始化规则** - **全局变量**:未初始化时默认值为0(如`int`为0,指针为`NULL`),存储在BSS段(引用[2])[^2]。 - **局部变量**:未初始化时值为随机值(使用前必须显式初始化)。 - **静态变量**(包括静态全局静态局部):未初始化时默认值为0。 ### 7. **`const`全局变量的特殊性** - `const`全局变量可能存储在只读数据段(引用[2])[^2],尝试修改会导致未定义行为(如程序崩溃)。 - C++中`const`全局变量默认具有内部链接性(相当于`static`),其他文件需通过`extern`显式声明才能访问。 ### 8. **JavaScript中的变量提升(Hoisting)** - JavaScript中,`var`声明的变量会提升到作用域顶部,但赋值不会提升(引用[5])[^5]。 - 示例: ```javascript console.log(a); // undefined(变量提升) var a = 10; ``` ### 9. **内存管理问题** - **溢出**:过多局部变量或过深递归可能导致溢出(引用[3])[^3]。 - **与动态分配**:全局变量一般不由程序员手动释放,而上动态分配的内存需显式管理(如C++的`new`/`delete`)。 ### 10. **设计问题:为什么避免使用全局变量?** - **命名冲突**:多个文件使用同名全局变量易引发错误。 - **耦合度高**:全局变量使函数间隐式耦合,降低代码可维护性。 - **线程安全**:多线程环境下需额外同步机制(如锁)。 ### 代码示例(C++) ```cpp #include <iostream> int global = 100; // 全局变量 void test() { int local = 10; // 局部变量 static int static_local = 0; // 静态局部变量 std::cout << "local: " << local << ", static_local: " << static_local << ", global: " << global << std::endl; local++; static_local++; } int main() { test(); // 输出: local:10, static_local:0, global:100 test(); // 输出: local:10, static_local:1, global:100(静态局部变量保持上次值) return 0; } ``` ### 总结 面试中关于全局变量局部变量的问题通常围绕**作用域**、**生命周期**、**存储位置**、**初始化规则**及**设计权衡**展开。理解这些概念对编写高效、安全的代码至关重要[^1][^2][^3][^4][^5]。 §§相关问题§§ 1. 静态局部变量全局变量内存管理上有何异同? 2. 在多线程编程中,全局变量可能引发哪些问题?如何解决? 3. `const`全局变量在CC++中的链接性有什么区别? 4. JavaScript中`let``var`在作用域上有何差异?如何避免变量提升导致的问题?</think>### 面试中关于全局变量局部变量的常见问题及解析 #### 1. **作用域与可见性区别** - **全局变量**:整个程序可见,定义在函数外部 - **局部变量**:仅在定义它的代码块(函数/循环体)内可见 - **关键面试题**: ```c int a = 10; // 全局变量 void test() { int a = 20; // 局部变量 printf("%d", a); // 输出20(局部优先)[^1] } ``` #### 2. **存储位置与生命周期** | 变量类型 | 存储位置 | 生命周期 | 初始化规则 | |----------------|-------------------|------------------------|-------------------| | 全局变量 | 静态存储区 | 整个程序运行期间 | 默认初始化为0 | | 静态全局变量 | 静态存储区 | 整个程序运行期间 | 默认初始化为0 | | 局部变量 | 内存 | 函数调用期间 | 值未定义(需显式初始化) | | 静态局部变量 | 静态存储区 | 整个程序运行期间 | 仅初始化一次 | **面试重点**: - 未初始化的全局数组存储在BSS段(不占磁盘空间,运行时分配清零)[^2] - `const`全局变量存储在常量区(不可修改)[^2] #### 3. **同名变量优先级问题** ```javascript var a = 100; // 全局 function test() { console.log(a); // undefined(变量提升) var a = 10; // 局部 console.log(a); // 10 } test(); console.log(a); // 100(全局)[^5] ``` **考点**:变量提升(Hoisting)局部优先原则 #### 4. **跨文件访问问题(C/C++)** - **普通全局变量**:可通过`extern`声明访问 ```c // file1.c int global_var = 10; // 定义 // file2.c extern int global_var; // 声明引用[^1] ``` - **静态全局变量**:`static`修饰,仅限当前文件访问(避免命名冲突) #### 5. **内存管理相关面试题** - **溢出**:过多局部变量导致空间耗尽[^3] - **内存泄漏**:全局指针未释放(需搭配`free`/`delete`) - **常引用优化**: ```cpp void printVector(const std::vector<int>& vec) { // 避免拷贝,保护原数据[^4] } ``` #### 6. **设计模式相关问题** 1. **为什么避免过度使用全局变量?** - 导致高耦合度 - 线程不安全(需同步机制) - 增加调试难度 2. **何时使用静态局部变量?** - 需要保持状态但限制作用域时 ```c int counter() { static int count = 0; // 仅初始化一次 return ++count; } ``` #### 7. **语言特性对比题** - **JavaScript特殊行为**: ```javascript function test() { b = 100; // 意外创建全局变量! } test(); console.log(b); // 100(严格模式会报错)[^5] ``` - **C++常量全局变量**:默认内部链接(需`extern`显式导出) ### 高频考点总结 1. 作用域链与变量查找优先级 2. 存储位置对性能的影响( vs 静态区) 3. `static`关键字的双重含义 4. 跨文件访问的`extern`机制 5. 变量初始化规则差异 6. 各语言的特殊行为(JS变量提升、Python的global关键字) > 面试中通常会结合具体代码片段考察分析能力,建议重点理解**存储位置****作用域链**这两个核心概念[^1][^3][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值