【问题标题】:Dynamic memory allocation in 'c' Issues“c”问题中的动态内存分配
【发布时间】:2012-05-02 23:35:15
【问题描述】:

我正在使用 malloc 编写代码,然后遇到了一个问题,所以我编写了一个测试代码,它实际上总结了下面的整个混乱::

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

int main()     
{
     int *p = NULL;
     void *t = NULL;
     unsigned short *d = NULL;

     t = malloc(2);
     if(t == NULL) perror("\n ERROR:");
     printf("\nSHORT:%d\n",sizeof(short));
     d =t;
     (*d) = 65536;
     p = t; 
     *p = 65536;
     printf("\nP:%p: D:%p:\n",p,d);
     printf("\nVAL_P:%d ## VAL_D:%d\n",(*p),(*d));
     return 0;
  }
   Output:: abhi@ubuntu:~/Desktop/ad/A1/CC$ ./test

            SHORT:2
            P:0x9512008: D:0x9512008:
            VAL_P:65536 ## VAL_D:0

我正在使用 malloc 分配 2 个字节 的内存。返回 void * 指针的 Malloc 存储在 void* 指针't'中。

然后声明 2 个指针 p - 整数类型和 d - 短类型。然后我将 t 分配给它们*(p =t 和 d=t)* 这意味着 d 和 p 都指向堆上的相同内存位置。 p>

在尝试将 65536(2^16) 保存到 (*d) 时,我收到警告说大 int 值被截断,这是预期的。 现在我再次将 65536(2^16) 保存到 (*p) 没有引起任何警告。

*在打印 (*p) 和 (d) 时,我得到了不同的值(尽管每个值都对自己定义的指针类型正确)。

我的问题是:

  1. 虽然我已经使用 malloc 分配了 2 个字节(即 16 位)的堆内存,但我如何能够在这两个字节中保存 65536(通过使用整数类型的指针 (p)) .?? 我有一种感觉,这是因为 void 到 int* 指针(在 p = t 中)的自动类型转换,所以将 t 分配给 p 会导致访问通过 malloc 分配的内存区域之外的内存区域吗? . ??.

  2. 1234563 1).

有人能对此有所了解吗,将不胜感激..如果有人能解释这背后的原因..

非常感谢

【问题讨论】:

  • Malloc 可能会将请求的大小向上舍入到某个乘数。不知道 *nix,但 Windows 喜欢将其四舍五入为 8 字节的倍数。如果是这样的话,你在你请求的区域之外写,但它恰好在安全范围内,因此你没有破坏其他任何东西。
  • 你已经小心地滥用了铸造权力来获得未定义的行为。 C 为您提供了强大的能力和灵活性来做坏事。你必须承担起不这样做的责任。
  • @dmckee 我知道我在做什么不应该做但是在偶然发现之后我很想知道它背后的确切原因,我最初猜测是自动类型转换为 int * 的事实分配 2 字节的 void* 指针导致 int* 指针访问更多内存然后 2 字节,因为在我的机器上 int 是 4 字节。这是正确的(我的假设)
  • 好的,然后真正的乐趣开始了。阅读大字节序和小字节序。然后阅读混合端并准备好畏缩。

标签: c malloc dynamic-memory-allocation


【解决方案1】:

先回答你的第二个问题:

解释是int一般是4个字节,最重要的字节可能存放在前两个位置。一个只有 2 个字节的short 也将其数据存储在前两个位置。显然,将65536 存储在int 和short 中,但指向相同的内存位置,将导致int 相对于short 的数据偏移两个字节,int 的两个最低有效字节对应于short 的存储。

因此,当编译器打印*d 时,它会将其解释为short,并查看与short 的存储对应的区域,这不是编译器先前在@987654334 时存储65536 的位置写了@。请注意,写入*p = 65536; 会覆盖之前的*d = 65536;,并用0 填充两个最低有效字节。

关于第一个问题:编译器不将65536 的*p 存储在2 个字节内。它只是超出了您分配的内存范围 - 这可能会在某些时候导致错误。

【讨论】:

  • 因此,自动类型转换为 2 字节分配的 void* 指针的 int * 导致 int* 指针访问更多内存然后 2 字节,因为在我的机器上 int 是 4 字节。这是正确的(我的假设)
  • 感谢您清晰明了的回答,它解释了一切:)
  • 从概念上讲,就是这样。我想说的是,从技术上讲,在你的句子中说“自动类型转换”也许不是最好的措辞,因为实际上没有任何东西被转换——只是编译器正在访问内存中的字节,就好像它们正在存储一种类型一样数据,而不是像存储另一种类型一样访问它们。
  • 哦,我的坏..再次感谢您的回复和详细解释:)
【解决方案2】:

1) OS 内存管理器的粒度为 4K。一位的覆盖不太可能触发 AV/segfault,但它会破坏相邻位置的任何数据,导致:

2) 未定义的行为。这组行为包括“明显正确的操作”,(现在!)。

【讨论】:

    【解决方案3】:

    在 C 中,对于超出分配范围的写入根本没有保护。只是不要这样做,任何事情都可能发生。在这里它似乎对您有用,因为巧合的是,您分配的两个字节后面的空间没有用于其他用途。

    【讨论】:

    • 或者至少他没有做任何事情来证明该记忆有其他用途。对这种错误的沉默反应是让他们偷偷摸摸你的原因。
    猜你喜欢
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 2014-10-09
    • 2011-01-19
    • 2022-01-22
    相关资源
    最近更新 更多