V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhangjinghua
V2EX  ›  程序员

请教一个非常简单的 c 语言内存申请问题

  •  
  •   zhangjinghua · 2022-01-04 21:14:41 +08:00 · 1815 次点击
    这是一个创建于 835 天前的主题,其中的信息可能已经有所发展或是发生改变。
    https://s4.ax1x.com/2022/01/04/TOB5oq.png
    为啥么会这样报错呢,看不懂了(不会发图,希望大佬教一下)
    23 条回复    2022-01-04 23:08:41 +08:00
    zhangjinghua
        1
    zhangjinghua  
    OP
       2022-01-04 21:18:08 +08:00
    嗡嗡嗡,求回复
    dlsflh
        2
    dlsflh  
       2022-01-04 21:26:09 +08:00 via Android
    不懂
    TaylorJack123
        3
    TaylorJack123  
       2022-01-04 21:42:21 +08:00 via iPhone
    memset 时,把变量 c 强制转成 unsigned char*。c 是 int 型指针,你如果对 8 个单位清零,应该是越界了^_^
    msg7086
        4
    msg7086  
       2022-01-04 21:51:46 +08:00 via Android
    一眼没看出问题,但是 memset 是不是应该在 if 里面才对?(虽然这不是引发问题的原因。)
    zhangjinghua
        5
    zhangjinghua  
    OP
       2022-01-04 21:53:45 +08:00
    破案了,我觉得应该不是越界了
    没有强转啊

    #include <stdlib.h>

    加了这个好了,但是我仍然不知道为什么
    basncy
        6
    basncy  
       2022-01-04 21:55:16 +08:00
    static int *c = NULL;

    笔试的时候别说是我教的.
    iOCZ
        7
    iOCZ  
       2022-01-04 21:59:45 +08:00
    代码没啥问题。。。所以,应该是别的问题
    xiri
        8
    xiri  
       2022-01-04 21:59:59 +08:00
    @zhangjinghua
    malloc 函数在 stdlib.h 里面,memset 函数在 string.h 里面,printf 在 stdio.h 里面,正常来说你需要把这三个头文件都加上。我刚刚还特地试了下,gcc 9.3.0 下可以正常编译和运行,没有任何问题,但是不加头文件的话会弹警告(实际上就是默认给加上了)。
    Tanix2
        9
    Tanix2  
       2022-01-04 22:01:51 +08:00
    @zhangjinghua 按理说没有 stdlib.h 用不了 malloc
    iOCZ
        10
    iOCZ  
       2022-01-04 22:04:17 +08:00
    试试没有 include 的情况下,能不能从 IDE 跳过去。。。。
    ipwx
        11
    ipwx  
       2022-01-04 22:05:51 +08:00
    When the application is linked with a debug version of the C run-time libraries, malloc resolves to _malloc_dbg

    https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/malloc?view=msvc-170

    盲猜没引入 stdlib.h 所以没解析到 _malloc_dbg ,隐式连接了正统 malloc ,然后调试器跪了
    zhangjinghua
        12
    zhangjinghua  
    OP
       2022-01-04 22:06:06 +08:00
    @xiri 正解正解
    话题终结
    zhangjinghua
        13
    zhangjinghua  
    OP
       2022-01-04 22:07:10 +08:00
    好丢人啊,这么低级的错误
    (确实好久没用这个函数了,公司不让用,有其他的函数申请内存)
    Origami404
        14
    Origami404  
       2022-01-04 22:12:45 +08:00 via Android   ❤️ 2
    @zhangjinghua 因为如果你不引入 malloc 的声明的话,按照 k&r c 的遗留标准,这个函数会被声明为 int (*)(), 于是在 64 位平台上 malloc 的返回值,那个指针,有可能被截断为一个 int ,导致你 c 指向的地方不对了。这也就是为什么 modern c 里推荐不要强转 malloc 返回值,以检测到这类错误

    不大确定,希望多加指正
    Origami404
        15
    Origami404  
       2022-01-04 22:15:52 +08:00 via Android
    当然我觉得理论上现代编译器应该能检测到这种问题,尤其是对这么常见的函数,所以我觉得 @ipwx 老哥的解释也很有可能,这可能需要看看编译出的汇编是怎么样的才能决定了(当然两个原因有可能一起发生也说不定)
    wevsty
        16
    wevsty  
       2022-01-04 22:16:52 +08:00
    最新的 MSVC 其实有弹警告,你可能没注意到。

    warning C4013: “malloc”未定义;假设外部返回 int

    根据提示我猜测:
    编译器没找到 malloc 的定义,然后默认返回的 int* 为 int 。
    然后链接器是正常 link 到了 malloc 上,在 32 位下面这样是没问题的,但如果编译 64 位的程序返回的 int* 本来是占 8 字节但是编译器强行截断成了 4 字节的 int 在赋值给 int* 所以地址就不对了。
    wevsty
        17
    wevsty  
       2022-01-04 22:18:48 +08:00
    我自己实测结果:VS2022
    编译位 X86 不加 stdlib.h 运行调试都没问题
    如果编译为 X64 不加的情况下调试就会弹错误了。
    zhangjinghua
        18
    zhangjinghua  
    OP
       2022-01-04 22:22:22 +08:00
    #include <stdio.h>
    #include <stdlib.h>

    int* a = NULL;

    int* b()
    {
    int c[2] = { 0 };
    if (c != NULL)
    {
    c[0] = 123;
    c[1] = 456;
    }
    return c;
    }

    int main()
    {

    a = b();
    printf("a[0] : %d \n", a[0]);
    printf("a[1] : %d \n", a[1]);
    printf("Hello World!\n");
    }

    结果 :
    a[0] : 123
    a[1] : 0
    Hello World!

    #include <stdio.h>
    #include <stdlib.h>

    int* a = NULL;

    int* b()
    {
    static int c[2] = { 0 };
    /////////这里加了 static
    if (c != NULL)
    {
    c[0] = 123;
    c[1] = 456;
    }
    return c;
    }

    int main()
    {

    a = b();
    printf("a[0] : %d \n", a[0]);
    printf("a[1] : %d \n", a[1]);
    printf("Hello World!\n");
    }

    结果
    a[0] : 123
    a[1] : 456
    Hello World!

    这里为啥会这样呢??? 虽然我知道和变量生命周期有关,但是为什么会留一半呢???
    zhangjinghua
        19
    zhangjinghua  
    OP
       2022-01-04 22:22:53 +08:00
    @wevsty 厉害啊,老哥,原来还有这样一说
    Origami404
        20
    Origami404  
       2022-01-04 22:23:46 +08:00 via Android
    @zhangjinghua 是 ub ,第一个程序理论上可以出现任何行为,包括让你电脑爆炸
    wevsty
        21
    wevsty  
       2022-01-04 22:24:15 +08:00
    @zhangjinghua
    未定义行为的结果就不要纠结了。
    iOCZ
        22
    iOCZ  
       2022-01-04 22:39:44 +08:00
    莫非是嵌入式的?不让用标准库
    msg7086
        23
    msg7086  
       2022-01-04 23:08:41 +08:00 via Android
    看代码的时候确实看到 include 段太短,猜到了没引入头文件,但没猜到默认返回类型太短截断指针的问题。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5193 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 07:13 · PVG 15:13 · LAX 00:13 · JFK 03:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.