自动为C结构分配内存

时间:2016-12-27 13:11:46

标签: c struct malloc

我一直在使用C / C ++,但今天我在某本书中看到了一些我以前从未见过的东西:

QueryManager

上面打印的值正常,这是struct item { int code; float prize; }; void main() { struct item a,*b; a.code = 123; a.prize = 150.75; printf ("Code: %d, Prize %d", a.code, a.prize); b->code = 124; b->prize = 200.75; printf ("Code: %d, Prize %d", a->code, a->prize); } 部分的一个惊喜。由于b是一个指针,为它分配的内存应该在大小为*b(例如64位)的堆栈上,而它的数据只能通过在堆上单独分配来获得:

size_t

显然,没有必要。这怎么可能?

2 个答案:

答案 0 :(得分:5)

在您的情况下,b->codeb->prize正在访问未初始化的内存,结果为undefined behavior 不要那样做

详细说明,没有发生 魔法 自动内存分配,使这些指针指向任何有效的内存。仅仅因为C 允许你编写一个访问未初始化指针的代码并不强制它是有效的代码。 必须使指针指向某个有效的内存位置,然后才能访问(读取或写入)它们。

任何体面的编译器都可能(虽然不需要)对这样的代码产生警告。对于gcc,启用-Wuninitialized(通过添加-Wall启用)应显示类似

的警告
  

警告:'b'在此函数中未初始化使用[-Wuninitialized]

那就是说,你有另一个主要问题。您正在传递一个float作为%d格式说明符参数,该参数再次调用它自己的UB。

 printf ("Code: %d, Prize %d", a.code, a.prize);
                         ^^^           ^^^^^^^^

相关,引用C11,章节§7.21.6.1

  

[...]如果有任何论据   不是相应转换规范的正确类型,行为是   未定义。

您应该使用%f来打印float

最后,对于托管环境,main()的签名至少应为int main(void),以符合标准。

答案 1 :(得分:1)

正确诊断后,b是未初始化的指针。访问成员进行读取和写入会调用未定义的行为,会自动分配给未指定的指针指向的内存。未初始化的指针只有一个不应使用的不确定值。

在你的情况下,程序似乎正常 ,但这只是一个巧合,在现代系统中不太可能:如果b恰好有一个指向的值一些可访问的内存,因此不会发生分段错误,但是谁知道修改了哪个对象以及可能产生的进一步后果......

请勿执行此操作,并在启用更多警告的情况下进行编译,因为当前编译器能够检测到此类错误:gcc -Wall -Wextraclang -Weverything

您的代码中还有其他一些问题:

  • 您不包含标准标题<stdio.h>;
  • 您为float格式printf;
  • 传递了%d
  • 您将main定义为返回void,它应该返回int;
  • 您不会使用换行符将输出结束到stdout

第二项也会调用未定义的行为。其他3通常没有可怕的后果,但仍应予以纠正。

以下是更正后的版本:

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

struct item {
   int code;
   float prize;
};

int main(void) {
    struct item a, *b;

    a.code = 123;
    a.prize = 150.75;
    printf("Code: %d, Prize %f\n", a.code, a.prize);

    b = malloc(sizeof(*b));
    if (b != NULL) {
        b->code = 124;
        b->prize = 200.75;
        printf ("Code: %d, Prize %f\n", b->code, b->prize);
    }
    return 0;
}