C/C++原始指针之悬空指针、野指针、内存泄露探究

#include <iostream>
void update_p_ref(int * intp) {
    int temp = 1;
    intp = &temp;
    printf("up_r_p=%p\n", intp);
    printf("up_r_v=%d\n", *intp);
    //temp variable "temp" will be collected
}
//transfer parameters as reference
void update_p_ref2(int*& intp_ref) {
    int temp = 3;
    intp_ref = &temp;
    printf("up_rr_p=%p\n", intp_ref);
    printf("up_rr_v=%d\n", *intp_ref);
}
void update_p_ref3(int& int_ref) {
    int_ref = 5;
    printf("up_rr_p=%p\n", &int_ref);
    printf("up_rr_v=%d\n", int_ref);
}
void update_p_value(int* intp) {
    *intp = 2;
    printf("up_v_p=%p\n", intp);
    printf("up_v_v=%d\n", *intp);
}
//transfer parameters as reference
void update_p_value2(int*& intp_ref) {
    *intp_ref = 4;
    printf("up_vr_p=%p\n", intp_ref);
    printf("up_vr_v=%d\n", *intp_ref);
}
void update_p_value3(int& int_ref) {
    int_ref = 6;
    printf("up_vr_p=%p\n", &int_ref);
    printf("up_vr_v=%d\n", int_ref);
}

int main() {
    int* p = nullptr; // declare pointer and initialize it
                      // so that it doesn't store a random address
    int i = 0;
    p = &i; // assign pointer to address of object
    int j = *p; // dereference p to retrieve the value at its address
    printf("p=%p\n", p);
    printf("p_v=%d\n", *p);
    printf("--------transfer parameters pointer as value normally-------\n");
    update_p_ref(p);
    printf("p1=%p\n", p);
    printf("p1_v=%d\n", *p);
    update_p_value(p);
    printf("p2=%p\n", p);
    printf("p2_v=%d\n", *p);
    printf("--------transfer parameters pointer as reference-------\n");
    p = &i;
    update_p_ref2(p);
    printf("p3=%p\n", p);
    printf("p3_v=%d\n", *p);
    update_p_value2(p);
    printf("p4=%p\n", p);
    printf("p4_v=%d\n", *p);
    printf("--------above code generate a dangling pointer \"p\" ,%s%s",
        "because temporary variable \"3\"(in update_p_ref2) and \"5\"(in update_p_value2)",
        "'s dynamically allocated memory has been freed with foo stack quitting------- \n");
    p = new int(0);
    printf("p_ad=%p\n", p);
    printf("p_v_ad=%d\n", *p);
    delete(p);//p is a vild pointer now
    printf("p_ad2=%p\n", p);
    p = NULL;//or p=nullptr
    printf("p_ad3=%p\n", p);
    printf("--------transfer parameters value as reference-------\n");
    p = &i;
    update_p_ref3(*p);
    printf("p5=%p\n", p);
    printf("p5_v=%d\n", *p);
    update_p_value3(*p);
    printf("p6=%p\n", p);
    printf("p6_v=%d\n", *p);
}

(win10-64位操作系统下运行,分别编译目标平台为win32和x64)输出结果如下,自行体会:

 

 个人总结几个基础点:

①指针指向数据值所在的地址(或者说,当指针的值是地址时,它指向内存中的数据);

②&:寻址符(其后为一个左值——要区别于表达式),对左值寻址获得指针变量,指针变量引用内存地址中的数据;

③*:取值符(其后为一个指针变量),对指针变量取消指针引用,获得指针变量引用的内存地址中的数据;

④对于不是通过关键字new进行内存分配的指针,使用delete释放内存会报错,原因是delete只能释放在堆(heap)中分配的内存空间;其他方式如通过&寻址左值(内存分配在当前作用域的栈中)获取的指针,会在当前堆栈(stack)退出(})时自动释放。

C/C++定义了4个内存区间:代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆(heap)区或自由存储区(free store)

⑤另外的,造成野指针的原因:指针变量未初始化。造成悬空指针的原因:指针释放后之后未置空(p_ad2);指针操作超越变量作用域(p3_v、p4_v,返回堆栈分配的局部变量的地址)。

———————————————以下来自wiki—————————————

计算机科学中,指针是一种引用

原始数据(或仅仅是原始)是可以被读取或写入任何数据的计算机存储器使用一个存储器存取(例如,两者字节和一个是原语)。

数据集合体(或只是聚合)是一组是原语的逻辑在存储器中连续和被作为一个数据集中观察(例如,聚集体可以是3个逻辑上连续的字节,其值表示的3个坐标空间中的点)。当一个聚合完全由相同类型的基元组成时,该聚合可以称为数组;从某种意义上说,多字节原语是一个字节数组,有些程序就是这样使用字的。

在这些定义的上下文中,字节是最小的原语;每个内存地址指定一个不同的字节。数据的起始字节的内存地址被认为是整个数据的内存地址(或基本内存地址)。

存储器指针(或只是指针)是原始的,它的值旨在被用作存储器地址; 据说一个指针指向一个内存地址。也有人说,当指针的值是数据的内存地址时,指针指向数据[在内存中]

更一般地说,指针是一种引用,据说指针引用了存储在内存某处的数据;获得该数据就是取消对指针的引用。将指针与其他类型的引用区分开来的特点是,指针的值被解释为内存地址,这是一个相当低级的概念。

引用作为一个间接级别:指针的值确定在计算中使用哪个内存地址(即哪个数据)。因为间接性是算法的一个基本方面,指针在编程语言中通常表示为一种基本数据类型;在静态(或)类型编程语言,该类型的指针的判定基准,以该指针指向的类型。

猜你喜欢

转载自blog.csdn.net/qq_23958061/article/details/121679082