9

以下代码工作正常:

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

int main()
{
    struct node{
        int a, b, c, d, e;
    };
    struct node *ptr = NULL;
    printf("Size of pointer ptr is %lu bytes\n",sizeof (ptr));
    printf("Size of struct node is %lu bytes\n",sizeof (struct node));
    ptr = (struct node*)malloc(sizeof (ptr));               //Line 1
//    ptr = (struct node*)malloc(sizeof (struct node));    //Line 2

    ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;
    printf("a: %d, b: %d, c: %d, d: %d, e: %d\n",
            ptr->a,ptr->b,ptr->c,ptr->d,ptr->e);
    return 0;
}

当遵守为:

gcc -Wall file.c

我的问题是:为什么这很好?

malloc分配在其参数中指定的字节数。这sizeof ptr是我的 64 位 linux 机器上的 8 个字节。我以为malloc会提供 8 个字节,但它是如何访问所有变量 a、b、c、d、e 的?是只有 gcc 还是我缺少标准 C 的东西?

据我所知,应该有“第 2 行”而不是“第 1 行”,但其中任何一行都可以正常工作。为什么?

4

4 回答 4

11

您在这里有未定义的行为。

malloc将分配 8 个字节(如您所说),但这种转换是“坏的”:

ptr = (struct node*)malloc(sizeof (ptr));

在这一行之后,ptr将指向一个内存块,它只有 8 个分配的字节,其余的是一些“随机”字节。所以,制作

ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;

您实际上更改了一些内存,而不仅仅是分配的malloc.

换句话说,您正在改写记忆,您不应该触摸。

于 2012-07-31T17:10:44.680 回答
8

第 1 行不正确,不会分配足够的空间。如果您以后可以访问结构成员,那只是因为 C 没有做任何事情来阻止您访问不属于您的内存。

当您没有为整个结构分配足够的空间时访问ptr->b,等是未定义的行为,并且下次运行代码时它可能会崩溃,或者您最终可能会覆盖程序另一部分中的数据。ptr-c

为了演示这个问题,struct node在第一个之后立即分配第二个。这不能保证证明问题,但您可能会看到类似于以下的结果:

struct node *ptr = NULL;
struct node *ptr2 = NULL;

ptr = (struct node*)malloc(sizeof (ptr));  // Your Line 1
ptr2 = malloc(sizeof(struct node));        // alloc another struct on the heap

ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;
ptr2->a = 11; ptr->b = 12; ptr->c = 13; ptr->d = 14; ptr->e = 15;

printf("ptr:  a: %d, b: %d, c: %d, d: %d, e: %d\n",
        ptr->a, ptr->b, ptr->c, ptr->d, ptr->e);
printf("ptr2: a: %d, b: %d, c: %d, d: %d, e: %d\n",
        ptr2->a, ptr2->b, ptr2->c, ptr2->d, ptr2->e);

输出:

ptr:  a: 1, b: 2, c: 3, d: 4, e: 11
ptr2: a: 11, b: 12, c: 13, d: 14, e: 15

请注意,ptr->e已通过对 的赋值进行了修改ptr2->a,因此您可以看到一个分配不正确的结构正在踩踏另一个结构的内存。这肯定不是你想要的。

于 2012-07-31T17:10:22.917 回答
3

malloc仅分配 8 个字节,但这并不能阻止您访问除此之外的内存。您可能会破坏堆并可能覆盖其他对象。程序的行为是未定义的。

于 2012-07-31T17:11:06.313 回答
2

ptr->a = 1; ptr->b = 2; ptr->c = 3; ptr->d = 4; ptr->e = 5;您访问的内存超出了 malloc 分配的内存。
这是缓冲区溢出的情况并导致undefined behaviour.

这是可能的,因为

 C and C++ provide no built-in protection against accessing or overwriting data
in any part of memory.

因此,它有时可能会起作用,有时它也可能会使程序崩溃。

于 2012-07-31T17:12:00.183 回答