🔥小陈又菜:个人主页
📖个人专栏:《MySQL:菜鸟教程》《小陈的C++之旅》《Java基础》
✨️想多了都是问题,做多了都是答案!

目录
1. 静态局部变量、全局变量、局部变量的特点,以及使用场景?
1. 静态局部变量、全局变量、局部变量的特点,以及使用场景?
简要回答:
- 静态局部变量:在函数内定义,使用static修饰。生命周期是整个程序,在作用域外不能被修改。只能初始化一次,之后都保持与上一次调用结束后的值一致。存储在数据段。
- 全局变量:在函数外定义,生命周期是整个程序运行过程。能够在程序任何一个地方被访问。被创建在数据区。
- 局部变量:在函数内定义,生命周期和作用域只能在声明该变量的函数内或类内访问。每一次调用需要被重新创建,生命周期随着函数的返回而结束。被创建在栈上。
图表理解:
分类 静态局部变量 全局变量 局部变量 生命周期 程序运行就存在,知道程序结束 程序已启动就创建,知道程序结束销毁 进入函数时创建,函数结束就销毁 作用域 当前函数内部或代码块内 程序的任何一个地方都能够访问 函数内能够访问 初始化行为 初始化一次(默认为0),之后的值会保留 默认初始化为0 不赋值的话不确定(随机值) 存储位置 数据段或BSS段(非栈),可长期保存 数据段或BSS段,可长期保存 栈(速度快,但并不持久) 适合场景 想要在函数中记住之前的值(统计次数、递归深度) 整个程序都要共享的数据(配置信息) 临时变量(循环中的变量、临时数组)
详细回答:
- 静态局部变量:
- 定义在函数或代码块内部,使用static关键字声明(static int a)。其生命周期不会随着函数的结束而被销毁。
- 第一次被调用时进行初始化(默认值为0),之后的调用不会再次进行初始化,会保留上一次调用结束的值。和局部变量一样存储在静态存储区。
- 适合用来做计数器,或者需要在多次函数调用之间被保留的值。
- 全局变量:
- 定义在函数外部,整个程序都能够访问,生命周期是从程序启动到程序结束。
- 如果要在别的文件使用该全局变量,需要使用extern关键字修饰(同样会被初始化为0),和静态局部变量一样存储在静态存储区。
- 使用static修饰的全局变量只能在当前文件使用,避免与其他文件的同名变量冲突。
- 局部变量:
- 定义在函数内部,这种变量的特点就是“随用随弃”,生命周期随着函数的调用结束而销毁。
- 如果不赋值的话将会是一个随机值,因为存储在栈中所以存取速度很快。
- 局部变量适合存放一些临时数据,如中间计算结果、临时数组、循环计数器,用完就释放不会占用额外内存。
- 值得注意的是,如果局部变量和全局变量同名,函数内会优先使用局部变量,相当于屏蔽了全局变量。
怎么用?
- 全局变量:是那种“很多地方都要用的数据”,如配置参数、程序状态等,放在最外面,全局共享。但是不推荐随便使用,因为会使得程序变得混乱、难以维护,没有必要的使用不要使用,确实要使用的话需要写好注释。
- 静态局部变量:适用在函数需要“记住上一个值”情况,例如在函数中设计一个计数器、记录某一个初始化状态,那可以在变量前面加上一个static,函数每一次运行都能够记住之前的结果。
- 局部变量:最为常见,是最干净、安全、不会出错的变量,只在当前函数内生效,函数结束后就销毁,处理临时数据、记录中间运算结果直接使用局部变量即可。
代码实例:
- 静态局部变量实例:
#include <iostream> using namespace std; void counter() { static int count = 0; // 静态局部变量 count++; cout << "Static local count: " << count << endl; } int main() { counter(); // 输出: Static local count: 1 counter(); // 输出: Static local count: 2 return 0; }
- 全局变量实例:
#include <iostream> using namespace std; int globalVar = 100; // 全局变量 void modifyGlobal() { globalVar += 50; cout << "Modified global: " << globalVar << endl; } int main() { cout << "Initial global: " << globalVar << endl; // 输出: Initial global: 100 modifyGlobal(); // 输出: Modified global: 150 return 0; }
- 局部变量实例:
void calculate() { int localVar = 5; // 局部变量 localVar *= 2; cout << "Local variable: " << localVar << endl; // 输出: Local variable: 10 // localVar 在此处销毁 } int main() { calculate(); // cout << localVar; // 错误:局部变量不可见 return 0; }
知识扩展:
- 静态变量、静态静态局部变量、全局变量特点示意图:
- 内存四区示意图:
![]()
2. 指针和引用的区别?
简要回答:
- 指针:
- 指针是一个变量,存储另一个变量的地址,使用时需要解引用(*)访问目标值。
- 能够被赋值给其他对象,支持指针运算(如++),可以为空,可以使用const修饰。
- 引用:
- 应用是一个变量的别名,使用是不需要解引用。
- 绑定之后就不能被修改,不能为空,没有const。
重点:指针占用独立的内存,需要手动管理内存。不存在指向控制的引用,但是可以有指向空值色指针。
详细回答:
- 指针:
- 指针是存储内存地址的变量,通过声明(int * p = &a),其值为目标对象的地址。
- 底层实现上,指针变量占用独立内存(32位系统4字节,64位系统8字节)。
- 可以重新赋值(p = &b),支持指针算术(p++)。
- 指针可以为空值nullptr,但要注意的是没有初始化或没用判空的指针容易导致野指针引发崩溃。
- 引用:
- 引用是变量的别名(int& r = a)。
- 绑定之后与目标对象共享内存,没有独立内存。
- 编译时符号表记录引用目标的地址,一旦绑定无法修改。
- 引用必须被初始化且不能为空,语法上更简洁,可以直接操控目标变量。
关于const修饰问题:
指针中关于const的修饰问题取决于const的位置:
- const int *p :const修饰的是指针指向的对象,意味着不能通过指针修改对象的值,但是可以改变指针指针指向的对象(也就是指针指向的地址)。
- int* const p:const修饰的是指针本身,意味着不能修改指针所指向的对象(指针指向的地址),但是能够修改指向的值。
- const int* const p:const既修饰指针本身,也修饰指针指向的值,两者都不能改变。
指针和引用的使用演示:
#include <iostream> using namespace std; int main() { // ====== 初始化对比 ====== int a = 10; int* ptr; // 指针可以延迟初始化 ptr = &a; // 现在指向a ptr = nullptr; // 可以设为空指针 int& ref = a; // 引用必须初始化且不能为空 // int& ref2; // 错误:引用必须初始化 // int& ref3 = nullptr; // 错误:不能绑定到空 // ====== 重新绑定对比 ====== int b = 20; ptr = &b; // 指针可以重新指向b // &ref = b; // 错误:引用不能重新绑定 // ====== 内存占用对比 ====== cout << "指针大小: " << sizeof(ptr) << " bytes" << endl; // 4或8字节 cout << "引用大小: " << sizeof(ref) << " bytes" << endl; // 显示a的大小 // ====== 操作方式对比 ====== *ptr = 30; // 指针需要解引用 ref = 40; // 引用直接操作 // ====== 安全性对比 ====== if(ptr != nullptr) { // 使用指针需要判空(行29) cout << *ptr << endl; } cout << ref << endl; // 引用无需判空检查(行32) // ====== 动态内存管理 ====== int* dynPtr = new int(50); // 指针用于动态内存 cout << *dynPtr << endl; delete dynPtr; // 必须手动释放 // 引用不能用于动态内存管理 // ====== 函数参数传递 ====== auto modifyByPtr = [](int* p) { if(p) *p += 1; }; auto modifyByRef = [](int& r) { r += 1; }; modifyByPtr(&a); modifyByRef(a); cout << "a = " << a << endl; // 输出42 //====== const的修饰 ====== // 引用示例 const int ci = 10; //int& r = ci; // 错误:非const引用不能绑定到const对象 const int& cr = ci; //正确:const引用可以绑定到const对象 //指针示例 int a = 10; const int* p1 = &a; // p1指向的值是const的 //*p1 = 20; //错误:不能通过p1修改a的值 int* const p2 = &a; // p2本身是const的,不能改变指向 //p2 = &b; //错误:不能改变p2指向的对象 return 0; }
知识扩展:
面试官有可能追问:什么时候应该使用指针?什么时候应该使用引用?请举例说明:
- 什么时候使用指针?
- 需要处理null情况
- 需要改变指向的对象(遍历链表)
- 需要动态内存分配(new、delete)
- 需要多级间接访问(指针的指针)
- 什么时候使用引用?
- 函数传递参数,能够避免拷贝开销
- 必须绑定到有效对象的场景(类成员引用)
- 实现链式调用(如返回*this)
- 运算符的重载
(本篇完)



512

被折叠的 条评论
为什么被折叠?



