【小陈背八股-C++】Day01- 为什么你的变量活得比别人久?指针为何总惹祸?

AgenticCoding·十二月创作之星挑战赛 10w+人浏览 405人参与

🔥小陈又菜个人主页

📖个人专栏《MySQL:菜鸟教程》《小陈的C++之旅》《Java基础》

✨️想多了都是问题,做多了都是答案!



目录

1. 静态局部变量、全局变量、局部变量的特点,以及使用场景?

简要回答:

图表理解:

详细回答:

怎么用?

代码实例:

知识扩展:

​编辑

2. 指针和引用的区别?

简要回答:

详细回答:

关于const修饰问题:

指针和引用的使用演示:

知识扩展:


1. 静态局部变量、全局变量、局部变量的特点,以及使用场景?

简要回答:

  • 静态局部变量:在函数内定义,使用static修饰。生命周期是整个程序,在作用域外不能被修改。只能初始化一次,之后都保持与上一次调用结束后的值一致。存储在数据段
  • 全局变量:在函数外定义生命周期是整个程序运行过程。能够在程序任何一个地方被访问。被创建在数据区
  • 局部变量:在函数内定义生命周期和作用域只能在声明该变量的函数内或类内访问。每一次调用需要被重新创建,生命周期随着函数的返回而结束。被创建在栈上

图表理解:

分类静态局部变量全局变量局部变量
生命周期程序运行就存在,知道程序结束程序已启动就创建,知道程序结束销毁进入函数时创建,函数结束就销毁
作用域当前函数内部或代码块内程序的任何一个地方都能够访问函数内能够访问
初始化行为初始化一次(默认为0),之后的值会保留默认初始化为0不赋值的话不确定(随机值)
存储位置数据段或BSS段(非栈),可长期保存数据段或BSS段,可长期保存栈(速度快,但并不持久)
适合场景想要在函数中记住之前的值(统计次数、递归深度)整个程序都要共享的数据(配置信息)临时变量(循环中的变量、临时数组)

详细回答:

  • 静态局部变量:
  1. 定义在函数或代码块内部,使用static关键字声明(static int a)。其生命周期不会随着函数的结束而被销毁。
  2. 第一次被调用时进行初始化(默认值为0),之后的调用不会再次进行初始化,会保留上一次调用结束的值。和局部变量一样存储在静态存储区。
  3. 适合用来做计数器,或者需要在多次函数调用之间被保留的值。
  • 全局变量:
  1. 定义在函数外部,整个程序都能够访问,生命周期是从程序启动到程序结束。
  2. 如果要在别的文件使用该全局变量,需要使用extern关键字修饰(同样会被初始化为0),和静态局部变量一样存储在静态存储区。
  3. 使用static修饰的全局变量只能在当前文件使用,避免与其他文件的同名变量冲突。
  • 局部变量:
  1. 定义在函数内部,这种变量的特点就是“随用随弃”,生命周期随着函数的调用结束而销毁。
  2. 如果不赋值的话将会是一个随机值,因为存储在栈中所以存取速度很快。
  3. 局部变量适合存放一些临时数据,如中间计算结果、临时数组、循环计数器,用完就释放不会占用额外内存。
  4. 值得注意的是,如果局部变量和全局变量同名,函数内会优先使用局部变量,相当于屏蔽了全局变量。

怎么用?

  • 全局变量:是那种“很多地方都要用的数据”,如配置参数、程序状态等,放在最外面,全局共享。但是不推荐随便使用,因为会使得程序变得混乱、难以维护,没有必要的使用不要使用,确实要使用的话需要写好注释。
  • 静态局部变量:适用在函数需要“记住上一个值”情况,例如在函数中设计一个计数器、记录某一个初始化状态,那可以在变量前面加上一个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. 指针和引用的区别?

简要回答:

  • 指针:
  1. 指针是一个变量,存储另一个变量的地址,使用时需要解引用(*)访问目标值。
  2. 能够被赋值给其他对象,支持指针运算(如++),可以为空,可以使用const修饰。
  • 引用:
  1. 应用是一个变量的别名,使用是不需要解引用。
  2. 绑定之后就不能被修改,不能为空,没有const。

重点:指针占用独立的内存,需要手动管理内存。不存在指向控制的引用,但是可以有指向空值色指针。


详细回答:

  • 指针:
  1. 指针是存储内存地址的变量,通过声明(int * p = &a),其值为目标对象的地址。
  2. 底层实现上,指针变量占用独立内存(32位系统4字节,64位系统8字节)。
  3. 可以重新赋值(p = &b),支持指针算术(p++)。
  4. 指针可以为空值nullptr,但要注意的是没有初始化或没用判空的指针容易导致野指针引发崩溃。
  • 引用:
  1. 引用是变量的别名(int& r = a)。
  2. 绑定之后与目标对象共享内存,没有独立内存。
  3. 编译时符号表记录引用目标的地址,一旦绑定无法修改。
  4. 引用必须被初始化且不能为空,语法上更简洁,可以直接操控目标变量。

关于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;
}

知识扩展:

面试官有可能追问:什么时候应该使用指针?什么时候应该使用引用?请举例说明:

  • 什么时候使用指针?
  1. 需要处理null情况
  2. 需要改变指向的对象(遍历链表)
  3. 需要动态内存分配(new、delete)
  4. 需要多级间接访问(指针的指针)
  • 什么时候使用引用?
  1. 函数传递参数,能够避免拷贝开销
  2. 必须绑定到有效对象的场景(类成员引用)
  3. 实现链式调用(如返回*this)
  4. 运算符的重载

(本篇完)

需求响应动态冰蓄冷系统与需求响应策略的优化研究(Matlab代码实现)内容概要:本文围绕需求响应动态冰蓄冷系统及其优化策略展开研究,结合Matlab代码实现,探讨了在电力需求侧管理景下,冰蓄冷系统如何通过优化运行策略参与需求响应,以实现削峰填谷、降低用电成本提升能源利用效率的目标。研究内容包括系统建模、负荷预测、优化算法设计(如智能优化算法)以及多场景仿真验证,重点分析不同需求响应机制下系统的经济性运行特性,并通过Matlab编程实现模型求解与结果可视化,为实际工程应用提供理论支持技术路径。; 适合人群:具备一定电力系统、能源工程或自动化景的研究生、科研人员及从事综合能源系统优化工作的工程师;熟悉Matlab编程且对需求响应、储能优化等领域感兴趣的技术人员。; 使用场景及目标:①用于高校科研中关于冰蓄冷系统与需求响应协同优化的课题研究;②支撑企业开展楼宇能源管理系统、智慧园区调度平台的设计与仿真;③为政策制定者评估需求响应措施的有效性提供量化分析工具。; 阅读建议:建议读者结合文中Matlab代码逐段理解模型构建与算法实现过程,重点关注目标函数设定、约束条件处理及优化结果分析部分,同时可拓展应用其他智能算法进行对比实验,加深对系统优化机制的理解。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值