欢迎光临
我们一直在努力

C++学习日记 Day1:内存四区模型与new/delete

##   今天学了什么

今天学习C++的内存四区模型,以及new/delete的基本用法。

##   内存四区总结

备注:其中代码区和全局区处于程序运行前,栈区和堆区处于程序运行后。

内存四区的意义:不同区域存放的数据赋予不同的生命周期,方便管理、灵活编程。

**实测地址(Windows 64位 + VS)**:
– 全局变量 `global_a` 地址:00007FF6026BF000
– 栈区变量 `a` 地址:00000091057CF704
– 堆区 `new_a` 地址:0000026D4C157E10

##    今日代码

```cpp

#include<iostream>

using namespace std;

//全局区
//全局变量
int global_a = 10;
//静态变量
static int static_a = 1;
//常量 const修饰常量、字符串常量
const int const_a = 2;

//栈区
//局部变量
int fun(int local_a)
{
    cout << "形参local_a的地址:" << &local_a << endl;
    return local_a;
}

//堆区
int * creatNum()
{
    int* p = new int(666);
    return p;
}

int main()
{
    static int static_b = 2;

    //const char *char_a = "hello world";

    int* new_a = creatNum();
    int* pp = new int[2];

    int a = 9;

    //cout << a<<endl;
    for (int i = 0; i <2; i++)
    {
        pp[i] = i + 1;
    }
    for (int i = 0; i < 2; i++)
    {
        cout << pp[i]<<endl;
    }

    int b = 5;

    cout << "全局变量global_a的地址:" << &global_a << endl;
    cout << "静态变量static_a的地址:" << &static_a << endl;
    cout << "静态变量static_b的地址:" << &static_b << endl;
    cout << "const修饰常量const_a的地址:" << &const_a<< endl;
    cout << "字符串常量的地址:" << &"hello world" << endl;
    cout << endl;
    cout << "局部变量量a的地址:" << &a << endl;
    cout << "局部变量量b的地址:" << &b << endl;
    fun(3);
    cout << endl;
    cout << "堆区数据地址:" << new_a << endl;
    cout << "堆区指针数组的首元素地址:" << pp << endl;

    /*delete new_a;
    new_a = nullptr;*/
    delete[] pp;
    pp = nullptr;

    return 0;
}

运行结果:

##  逐步调试步骤

1.打断点 鼠标点击左边灰色栏对应行

2.按F5进入调试

3.F10/F11逐行调试,F10会直接跳过函数(F10逐过程 F11逐语句)

调试-窗口-局部变量 观察各个变量值的变化

##   问题记录

**内存泄漏实验**:在写int * p=new int(5);时,故意不写delete p;结果正常运行,什么异常也没有发现,进入逐步调试,只能看到在程序结束时,p的值还存在。

结论:内存泄漏在程序结束时看不出来,但如果长期运行程序,内存会一直涨,最终崩溃。

**指针、地址、解引用**:

```cpp

int a=10;     

int * p=&a;  //指针p的值是a的地址   int * : 整型指针

cout<<*p;  //*p 解引用,输出a的值 输出结果:10

## 深度思考:为什么打印的地址是负数?

第一次运行时,发现输出的地址是负数。查了资料才知道:
– 用 `int` 去接收地址(比如 `(int)&a`),但 `int` 只有 32 位
– 我的环境是 64 位,地址是 64 位十六进制数
– 把 64 位地址强行塞进 32 位 `int`,高 32 位被截断,剩下的最高位如果是 1,就变成负数
– 教程里老师没遇到这个问题,是因为他用的是 32 位程序,地址数值小,不会溢出

**正确做法**:直接用 `cout` 输出指针,或者转成 `uint64_t`。

## 深度思考:堆区和栈区谁的地址高?

实测发现:Windows 64位 + VS 环境下,**堆区地址比栈区地址大**。这和很多教程里“栈在顶部、堆在底部”的说法不一样。

查资料得知:堆和栈的地址顺序取决于操作系统和编译器,没有统一标准。所以不要背“谁高谁低”,记住它们的管理方式区别就行了。

** 学习堆区的作用 **

知道数据存在哪,什么时候消失,提前避开崩溃、内存泄漏这些bug,写程序的时候判断放在栈还是堆。

** 野指针的危害 **

  • 读取乱码,奇怪负数
  • 程序闪退随机崩溃,很难复现排查
  • 严重时会篡改别的变量,产生莫名其妙的错误
赞(0)
未经允许不得转载:171主机测评 » C++学习日记 Day1:内存四区模型与new/delete
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址