鱼C论坛

 找回密码
 立即注册
查看: 2146|回复: 5

[已解决]指针与malloc内存管理问题

[复制链接]
发表于 2022-4-22 19:43:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 风车呼呼呼 于 2022-4-22 19:45 编辑

通过malloc申请的空间,为什么通过指针能访问到申请空间大小以外的空间
以下用malloc(2)为例
申请2字节空间,指针能够对第3、4字节空间进行操作
考虑到申请空间之外的空间可能不属于必须自己手动释放的范围,但经过测试,free之后,之前对第3、4字节空间的赋值一同被清除了
之后尝试通过指针修改较远一些的空间,再次free后,却又并没有被清除数据

上述,产生了一系列矛盾和疑问:
malloc申请的空间之外连续的空间是否属于malloc的作用范围,
如果不属于,又为何能被free影响
如果属于,范围又有多大呢?同时我们规定申请的字节数岂不是没有意义

以下为个人验证过程及结果:
#include <stdio.h>
#include <stdlib.h>

int main(void){
        char *ptr = NULL;
        int i;
        ptr = (char *)malloc(2);
        for(i = 0; i < 14; i++){
                printf(" address of ptr[%d]: %p\n", i, &ptr[i]);
        }
        ptr[0] = 'A';
        ptr[1] = 'B';
        ptr[2] = 'C';
        ptr[3] = 'D';

        printf("ptr[13]:%d\n", ptr[13]);
        ptr[13] = 'X';

        for(i = 0; i < 14; i++){
                printf("%c\n", ptr[i]);
        }

        printf("address ptr: %p\n", ptr);
        free(ptr);
        printf("释放后:\n");
        for(i = 0; i < 14; i++){
                printf("%c\n", ptr[i]);
        }
        printf("address ptr: %p\n", ptr);
        return 0;
}
address of ptr[0]: 0x1a7c010
 address of ptr[1]: 0x1a7c011
 address of ptr[2]: 0x1a7c012
 address of ptr[3]: 0x1a7c013
 address of ptr[4]: 0x1a7c014
 address of ptr[5]: 0x1a7c015
 address of ptr[6]: 0x1a7c016
 address of ptr[7]: 0x1a7c017
 address of ptr[8]: 0x1a7c018
 address of ptr[9]: 0x1a7c019
 address of ptr[10]: 0x1a7c01a
 address of ptr[11]: 0x1a7c01b
 address of ptr[12]: 0x1a7c01c
 address of ptr[13]: 0x1a7c01d
ptr[13]:0
A
B
C
D









X
address ptr: 0x1a7c010
释放后:













X
address ptr: 0x1a7c010
最佳答案
2022-4-24 10:12:56
风车呼呼呼 发表于 2022-4-23 19:09
的确有所收获。对于第4点我想进一步讨论一下,倘若第3、4字节空间在free之后数据被清空的原因是ptr被释放 ...


这个问题我也想了。
ptr[13]的值是通过指针越界赋值的。释放ptr后,还是通过指针ptr访问到ptr[13]
思考结果:
1.指针ptr释放后,但指针变量ptr没有被删除,只是释放指针ptr指向的内存空间。
释放后:
              v
address ptr: 007618B8
这个时候指针ptr是一个野指针。误以为ptr是个合法的指针而在接下来程序中错误的使用它,既然知道不合法,就不应该再通过ptr取错误访问。虽然错误访问,但C语言不做检查。
2.为避免野指针导致非法访问,free(ptr)后,应ptr=NULL
3.程序结果出现'v',野指针访问出现的未知结果
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-4-22 21:03:37 | 显示全部楼层
事实就是:不属于。读取这些内存区域就是未定义行为,简称UB。
所谓未定义行为,就是“鬼知道会有什么后果”的行为,可能像你这样修改成功,可能像我的VS那样弹出一个错误框……使用这些内存区域已是错,探究背后的道理无疑是错上加错,所以还是省省心吧。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-4-22 21:04:22 | 显示全部楼层

1.  char *ptr = NULL;  //ptr是一个指向char类型的指针变量,既然是变量肯定有地址,只不过初始化地址为空

2.  ptr = (char *)malloc(2);  //指针变量指向2字节的连续空间首地址,ptr不是一个地址块,而且ptr的地址已经不为空了

3.  指针ptr能够对第3、4字节空间进行操作,因为C语言不检查指针越界问题,靠程序员自己把控

4. “free之后,之前对第3、4字节空间的赋值一同被清除了之后尝试通过指针修改较远一些的空间,再次free后,却又并没有被清除数据”。free释放的是指针ptr指向的2字节空间,通过指针ptr取访问第3、4字节空间是不可行的。

代码如下:
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *ptr = NULL;
    int i;
    printf(" address of ptr: %p\n", ptr);
    printf(" address of ptr's size(Byte): %d\n", sizeof (ptr));
    ptr = (char *)malloc(2);
   
    for (i = 0; i < 4; i++)
    {
        printf(" address of ptr[%d]: %p\n", i, &ptr[i]);
    }
    ptr[0] = 'A';
    ptr[1] = 'B';
    ptr[2] = 'C';
    ptr[3] = 'D';

    for (i = 0; i < 4; i++)
    {
        printf("%c\t", ptr[i]);
    }
    printf ("\n");
    free(ptr);
    printf("释放后:\n");
    for (i = 0; i < 4; i++)
    {
        printf("%c\t", ptr[i]);
    }
    printf ("\n");
    printf("address ptr: %p\n", ptr);
    return 0;
}

验证如下:
address of ptr: 00000000
address of ptr's size(Byte): 4
address of ptr[0]: 007618B8   
address of ptr[1]: 007618B9   
address of ptr[2]: 007618BA   
address of ptr[3]: 007618BB   
A       B       C       D      
释放后:
              v
address ptr: 007618B8


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-4-23 18:59:45 | 显示全部楼层
lhgzbxhz 发表于 2022-4-22 21:03
事实就是:不属于。读取这些内存区域就是未定义行为,简称UB。
所谓未定义行为,就是“鬼知道会有什么后果 ...

是的,偶然发现这个情况本想稍加验证一下,却连续得出自相矛盾的结果。短时间也不能确定这结果是因为偶然的不确定性造成,还是真的涉及到我不了解的知识领域且具有一定的规律性。
在不同的编译环境下测试确实是区分这两者的一个方法,值得尝试
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-4-23 19:09:45 | 显示全部楼层
cjgank 发表于 2022-4-22 21:04
1.  char *ptr = NULL;  //ptr是一个指向char类型的指针变量,既然是变量肯定有地址,只不过初始化地址为 ...

的确有所收获。对于第4点我想进一步讨论一下,倘若第3、4字节空间在free之后数据被清空的原因是ptr被释放,不再能通过ptr去访问到第3、4字节空间,为何我测试中的ptr[13]中的数据却没有被清空呢?
以及你测试结果的最后,不知释放后的那个V是从何而来?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-4-24 10:12:56 | 显示全部楼层    本楼为最佳答案   
风车呼呼呼 发表于 2022-4-23 19:09
的确有所收获。对于第4点我想进一步讨论一下,倘若第3、4字节空间在free之后数据被清空的原因是ptr被释放 ...


这个问题我也想了。
ptr[13]的值是通过指针越界赋值的。释放ptr后,还是通过指针ptr访问到ptr[13]
思考结果:
1.指针ptr释放后,但指针变量ptr没有被删除,只是释放指针ptr指向的内存空间。
释放后:
              v
address ptr: 007618B8
这个时候指针ptr是一个野指针。误以为ptr是个合法的指针而在接下来程序中错误的使用它,既然知道不合法,就不应该再通过ptr取错误访问。虽然错误访问,但C语言不做检查。
2.为避免野指针导致非法访问,free(ptr)后,应ptr=NULL
3.程序结果出现'v',野指针访问出现的未知结果
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-5 20:20

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表