鱼C论坛

 找回密码
 立即注册
123
返回列表 发新帖
楼主: 匡吉

[已解决]malloc内存方面的问题

[复制链接]
 楼主| 发表于 2018-8-20 14:28:17 | 显示全部楼层
无符号整形 发表于 2018-8-20 14:22
对呀……我就怀疑你是计算到了指针大小
结果那样也没用

老哥之前那个答案说改用sizeof(*buf),是计算一个char类型的大小,也就是一个字节
当时我一心认为strcpy那边出现问题,sizeof那么没细看.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-20 14:39:04 | 显示全部楼层
claws0n 发表于 2018-8-20 14:23
其实我一直在等您的答案。可是我试了一下,他 27 楼给的答案也不完全吧?
free 只能针对 memset, malloc ...


1.png

a是一个变量,在内存中占4个字节
变量a的地址是0x012FFD8C,在变量a中存储的值是100(0x64)
变量a从地址0x012FFD8C开始到地址0x012FFD8F结束(包含0x012FFD8F)
012FFD8C 地址存储 64
012FFD8D 地址存储 00
012FFD8E 地址存储 00
012FFD8F 地址存储 00
0x00000064就是十进制100

p是一个变量,在内存中占4个字节
变量p的地址是0x012FFD80,在变量p中存储的值是0x012FFD8C
变量p从地址0x012FFD80开始到地址0x012FFD83结束(包含012FFD83)
012FFD80 地址存储 8C
012FFD81 地址存储 FD
012FFD82 地址存储 2F
012FFD83 地址存储 01
变量p中保存的是 0x012FFD8C,这是变量a的地址

在变量p中保存了变量a的地址,我们就说变量p指向变量a
或者指针p指向变量a
变量p有地址,在这个地址可以保存值
#include <stdio.h>
#include <string.h>
#include <stdint.h>

int main(void)
{
        int a = 100;
        int *p = &a;

        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(p) = %d\n", sizeof(p));
        printf("\n");

        printf("&a = %.8X\n", &a);
        printf(" a = %.8X\n", a);
        printf("&p = %.8X\n", &p);
        printf(" p = %.8X\n", p);
        printf("\n");

        for(int i = 0; i < sizeof(a); ++i)
        {
                uint8_t *address = &a;
                printf("%.8X -> %.2X\n", address + i, *(address + i));
        }
        printf("\n");

        for(int i = 0; i < sizeof(p); ++i)
        {
                uint8_t *address = &p;
                printf("%.8X -> %.2X\n", address + i, *(address + i));
        }
        printf("\n");

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

使用道具 举报

发表于 2018-8-20 15:07:44 | 显示全部楼层
人造人 发表于 2018-8-20 14:39
a是一个变量,在内存中占4个字节
变量a的地址是0x012FFD8C,在变量a中存储的值是100(0x64)
变量a ...

第一次看过这样把地址给显示出来
又有新招了~
这个指针指向变量的懂
比如 swap 函数我能理解
这里的 p 只占 4 个字节是 32 位的原因吧?

我只是一开始以为 free() 了之后,变量也跟着不见。毕竟我目前处理的代码量还算少。但是我刚才试了一下,free 不能直接用在变量上,而是要有 malloc 等。所以 free 是把额外申请的内存空间给清除,那么他原本 char *buf = NULL 的空间是没有被清除的。因此,最后 buf = NULL 是有效的赋值。
我在意的不是 buf = NULL 的作用

所以最后一次回复是想问哥哥,他 27 楼的解释不够完整,而我这样理解比较合适对吧?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-20 15:33:51 | 显示全部楼层
本帖最后由 人造人 于 2018-8-20 15:39 编辑
claws0n 发表于 2018-8-20 14:23
其实我一直在等您的答案。可是我试了一下,他 27 楼给的答案也不完全吧?
free 只能针对 memset, malloc ...


1.png


我们在写程序时需要用内存存储数据
可以这么写
int data[10];
有时候我们并不知道究竟需要多少内存空间,写大了浪费,写小了不够,当程序运行到某一时刻时才能知道需要多少内存
这时我们可以动态的向系统申请,因为我们总不能随便找一个地址就用呀,例如直接使用0x12345678,我们并不知道这个地址存储了什么,我们不能随便使用一个地址,需要内存就要向系统申请
C语言用malloc
malloc执行了一段代码,返回了一个地址,malloc能够保证这段内存空间没有 有意义的数据,你可以随便用,如果用完了,你需要还给系统,如果你没还给系统,那么只有你的程序终止,系统才能回收这段内存空间
如果你的程序需要一直运行着,运行几天或者几年(例如服务器的某个守护进程),如果你用完了不释放内存,那么系统就不能把这段内存分配给其他位置(当前程序的其他位置,或者其他程序),不断的申请而不释放,内存很快就会用完


上面说了一堆废话,现在说一下这个程序^_^

int *p = malloc(sizeof(int) * 5);
向系统申请5个int的存储空间(20个字节)
p的地址是 007CF8CC
p中保存的是 00DE6990
也就是说 malloc保证 00DE6990 ~ 00DE69A0 内存空间可用

执行 free(p);之前
p的地址是 007CF8CC
p中保存的是 00DE6990
执行 free(p);之后
p的地址是 007CF8CC
p中保存的是 00DE6990

p中仍然保存着这个位置,只是free执行完后,这个位置已经可以给其他地方使用了,也许现在这个位置还没有分配给其他地方使用,但是这个位置已经不属于当前程序了,很可能你在free后又在这个位置写了一些数据例如100,等过了一会从这个位置读取出来的是0,因为这个位置已经分配给其他地方使用了,所以说free后就不要再使用哪个位置了

但是p中仍然保存着这个位置,这不安全,说不定之后在哪就不小心访问到这个位置了
所以
p = NULL;
让p中保存0,也就是p指向内存地址0,说明p不指向 “任何位置”
后面如果不小心使用了,那就必然报错
但是空指针有一个好处,因为是空指针,你能判断这个指针是不是空指针,如果是空指针那就不要用就没问题了,但是你却没办法判断已经free过的这个指针(你要如何判断这个指针已经free过了?)


忘了代码了,现在补上
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
        int *p = malloc(sizeof(int) * 5);
        printf("%.8X -> %.8X\n", &p, p);
        printf("\n");
        
        for(int i = 0; i < 5; ++i)
        {
                p[i] = i;
        }

        for(int i = 0; i < 5; ++i)
        {
                printf("%.8X -> %.8X\n", &p[i], p[i]);
        }
        printf("\n");

        printf("%.8X -> %.8X\n", &p, p);
        free(p);
        printf("%.8X -> %.8X\n", &p, p);
        printf("\n");

        for(int i = 0; i < 5; ++i)
        {
                printf("%.8X -> %.8X\n", &p[i], p[i]);
        }
        printf("\n");

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

使用道具 举报

发表于 2018-8-20 16:44:02 | 显示全部楼层
人造人 发表于 2018-8-20 15:33
我们在写程序时需要用内存存储数据
可以这么写
int data[10];


嗯嗯
让 p = NULL; 是不是等于作废了?这个指针不能再用了,用了会报错~
之前地址表示使用 %p 出来的数字很长 T_T

malloc 前后,p 的地址改变了
但是照理来说,动态内存是在【堆】,也就是低地址,但 0061FE1C  -> 001D6CC0 被推高了?
还是说 windows 不一样而已??
#include <stdio.h>
#include <stdlib.h>
//#include <string.h>

int main () {
   int a[10] = {10, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   int b = 5;
   int *p = &b;
   
   printf("size a= %d,  Address = %0.8X\n", sizeof(a), a);
   printf("size b= %d,  Address = %0.8X\n\n", sizeof(b), b);
   
   printf("val= %10d,  Address = %0.8X,   size = %d\n", *p, p, sizeof(p));
   p = (int *)malloc(sizeof(b)*5) ;
   printf("val= %10d,  Address = %0.8X,   size = %d\n\n", *p, p, sizeof(p));
   
   free(p);
   printf("val= %10d,  Address = %0.8X\n\n", *p, p);
   printf("size= %d,  Address = %p\n", sizeof(a), a);

   return(0);
}
lol.jpg
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-20 23:06:29 | 显示全部楼层
claws0n 发表于 2018-8-20 16:44
嗯嗯
让 p = NULL; 是不是等于作废了?这个指针不能再用了,用了会报错~
之前地址表示使用 %p 出来的 ...

1.png

执行free之前
变量p的地址是 012FFEAC,在这个地址保存的值是 013E6640

执行free之后
变量p的地址是 012FFEAC,在这个地址保存的值是 013E6640

执行p = NULL;之后
变量p的地址是 012FFEAC,在这个地址保存的值是 00000000

现在变量p中保存的是0,表示空指针,空指针可以判断出来,free后的指针却判断不出来
判断出当前指针是空指针,那就不对当前指针解引用
判断出当前指针是free后的指针,那就也不对当前指针解引用,问题是判断不出来,要如何判断?

Print函数和SetValue函数都做了空指针判断,是空指针就不执行解引用,直接返回
这两个函数可以接受空指针,但是无法接受free后的指针,即使你free过了,这两个函数也判断不出来,照样解引用,幸运的话程序直接崩溃,不幸的话程序“正常运行”,对于操作系统来说正常
例如一个美元转换人民币的程序出现了这样的问题,而且正好覆盖到了这个金钱的内存地址,写这个地址系统不会报错,这个地址对于系统来说是合法的,可以被当前程序修改,但是计算出的结果肯定不是你想要的
#include <stdio.h>
#include <stdlib.h>

void SetValue(int *p, int len, int value)
{
        if(p)
        {
                for(int i = 0; i < len; ++i)
                {
                        p[i] = value;
                }
        }
}

void Print(int *p, int len)
{
        if(p)
        {
                for(int i = 0; i < len; ++i)
                {
                        printf("%d ", p[i]);
                }
                printf("\n");
        }
}

int main(void)
{
        int *p = malloc(sizeof(int) * 10);
        SetValue(p, 10, 123);
        Print(p, 10);
        printf("\n");

        printf("%.8X -> %.8X\n", &p, p);
        free(p);
        printf("%.8X -> %.8X\n", &p, p);
        p = NULL;
        printf("%.8X -> %.8X\n", &p, p);
        printf("\n");

        SetValue(p, 10, 123);
        Print(p, 10);
        printf("\n");
        return 0;
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-20 23:08:16 | 显示全部楼层
claws0n 发表于 2018-8-20 16:44
嗯嗯
让 p = NULL; 是不是等于作废了?这个指针不能再用了,用了会报错~
之前地址表示使用 %p 出来的 ...

printf("size b= %d,  Address = %0.8X\n\n", sizeof(b), b); // 这个打印出的不是b的地址,而是b中保存的值
printf("size b= %d,  Address = %0.8X\n\n", sizeof(b), &b); // 通过 & 得到变量b的地址
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-20 23:27:37 | 显示全部楼层
人造人 发表于 2018-8-20 23:08
printf("size b= %d,  Address = %0.8X\n\n", sizeof(b), b); // 这个打印出的不是b的地址,而是b中保存 ...

哦,原来如此
受教受教
谢谢哥哥~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-10-2 10:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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