IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 指针的错误用法(一) -> 正文阅读

[C++知识库]C++ 指针的错误用法(一)

好久没用指针了,有点晕头,随手就写了个Bug,大概长这样:

struct Object{
    int type;
};

int get_object(Object *obj)    
{
    obj = new Object;       
    obj->type = 1;
    return 0;
}    
                      
int main()
{
    Object *obj = 0;   
    get_object(obj);
    std::cout << "obj:" << obj;
}

输出是 obj:0,obj?为空,为什么呢?

************************************** 让 * 我 *? 想 * 一 * 想 ***********************************************

我们一句一句分析:

Object *obj = 0; ? ?// ①

int get_object(Object *obj) ? ? // ②
{
? ? obj = new Object; ? ?//? ③
? ? obj->type = 1;
? ? return 0;
} ? // ④
① 为局部变量 obj 分配栈空间,存储地址0

② 为形参 obj 分配栈空间 (为方便区分,记为obj1),并接收实参 obj 传递进来的数据,赋值为0

③?申请内存,并将obj1 指向该内存的首地址 ?

④?函数结束,销毁局部变量 obj1

其实 new Object 就像是申请了一块地,建了一座房子,obj 就是这座房子的钥匙,通过它可以对房里的东西做任何事情。用这个想法,我们可以把上面这段代码重新解释一遍:

① 将 obj 配为0号地址的钥匙,但注意,0号地址是受到保护、禁止访问的

② 以 obj 为模板,重新配一把钥匙 obj1,此时,obj1 也是0号地址的钥匙

③ 申请一块地,建了一座房子,将 obj1 重新制作成这座房子的钥匙

④ 丢弃钥匙 obj1

分析完很容易就发现问题的关键:此obj非彼obj,分配内存的首地址是存在 obj1 中的,与 obj 没半毛钱关系。

来验证一下我的想法:

int get_object(Object *obj)
{
    obj = new Object;
    obj->type = 1;
    std::cout << "obj address 1:" << &obj << " pointed object address:" << obj << std::endl;
    return 0;
}

int main()
{
    Object *obj = 0;
    std::cout << "obj address 0:" << &obj << " pointed object address:" << obj << std::endl;
    get_object(obj);
    std::cout << "obj address 2:" << &obj << " pointed object address:" << obj << std::endl;
}

输出为:

obj address 0:0x64fe18 pointed object address:0
obj address 1:0x64fdf0? pointed object address:0x7317b0
obj address 2:0x64fe18 pointed object address:0

main() 函数中的 obj 变量本身的地址在0x64fe18,而 get_object() 函数中的 obj 变量本身的地址在0x64fdf0。

注意,这段代码还有个大问题:get_object() 函数调用结束后,函数中的 obj 会被销毁,但这片内存还在,会造成内存泄露

如果先 new 出一片内存A,将首地址赋值给指针 obj,再将 obj 传参给一个函数的参数 obj1,在这个函数中修改指针内容,这是可以的,因为指针 obj 和 obj1 都指向内存A,它们是两把克隆的一模一样的钥匙,通过谁都是操作的内存A。

如果一定需要用这种方法来获取一个对象,可以将实参 obj 的地址传给形参

int get_object(Object **obj)
{
    *obj = new Object;
    (*obj)->type = 1;
    std::cout << "obj address 1:" << &obj << " pointed object address:" << obj << std::endl;
    return 0;
}

int main()
{
    Object *obj = 0;
    std::cout << "obj address 0:" << &obj << " pointed object address:" << obj << std::endl;
    get_object(&obj);
    std::cout << "obj address 2:" << &obj << " pointed object address:" << obj << std::endl;
}

输出:

obj address 0:0x64fe18 pointed object address:0
obj address 1:0x64fdf0? pointed object address:0x64fe18
obj address 2:0x64fe18 pointed object address:0x6a17b0

形参obj指向实参obj的地址,*obj即为实参对象,分配内存后,将其指向首地址。

拓展阅读

In C++, the definition of NULL is 0, so there is only an aesthetic difference. I prefer to avoid macros, so I use 0. Another problem with NULL is that people sometimes mistakenly believe that it is different from 0 and/or not an integer. In pre-standard code, NULL was/is sometimes defined to something unsuitable and therefore had/has to be avoided. That's less common these days.
If you have to name the null pointer, call it nullptr; that's what it's called in C++11. Then, "nullptr" will be a keyword.

在 C++ 中,NULL 的定义是 0,所以只有审美差异。 我更喜欢避免使用宏,所以我使用 0。NULL 的另一个问题是人们有时会错误地认为它不同于 0 和/或不是整数。 在标准前的代码中,NULL 有时被定义为不合适的东西(最近不太常见),因此必须避免。
如果必须命名空指针,则称其为 nullptr; 这就是它在 C++11 中的名称,“nullptr”将是一个关键字。

详见:https://www.stroustrup.com/bs_faq2.html#null

  • 内存空间的地址划分

以32位Windows系统为例,内存空间的地址划分为:

分区x86 32位Windows
空指针赋值区0x00000000~0x0000FFFF
用户模式区0x00010000~0x7FFEFFFF
64KB禁入区0x7FFF0000~0x7FFFFFFF
内核

0x80000000~0xFFFFFFFF

其中,空指针赋值区和?64KB禁入区都为保留区,是受到保护、禁止访问的,操作系统并没有使用这片区域,我们将指针指向0地址,可以防止指针变成野指针。


感觉这个系列可以写不少......

欢迎提出你宝贵的建议和想法

欢迎关注我的知乎?安暖 - 知乎 (zhihu.com),你问,我必答😎

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:03:37  更:2021-08-09 10:05:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/9 22:08:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码