【问题标题】:Declaring a pointer to struct in C++ automatically allocates memory for its members. Am I wrong?在 C++ 中声明指向 struct 的指针会自动为其成员分配内存。我错了吗?
【发布时间】:2012-03-14 09:11:32
【问题描述】:

我编写了以下代码,我相信如果我尝试访问我什至没有为其分配内存的结构的成员,它会崩溃。但我很惊讶 C++ 自动为结构分配内存。这是正常的行为吗?作为比较,如果您声明一个指向对象的指针,然后尝试访问任何成员而没有使用运算符“new”实际创建对象,则程序将崩溃。我只是好奇为什么它在我认为它不应该起作用的情况下起作用。

这是我的程序:

#include <stdio.h>

struct Produto
{
    int codigo;
    float preco;
};

int main()
{
    struct Produto* sabonete;
    sabonete->codigo = 654321;
    sabonete->preco = 0.85;

    printf( "Codigo = %i\n", sabonete->codigo );
    printf( "Preco = R$ %.2f\n", sabonete->preco );

    return 0;
}

操作系统:Windows 7
编译器:MinGW GCC 4.6.1

【问题讨论】:

  • 你错了。这只是似乎起作用 - 这是未定义的行为。
  • 修复代码中的错误,谜团就会消失。损坏的代码会做一些奇怪的事情,就是这样。
  • 您所说的关键问题是,“C++ 自动为结构分配内存”。不,它没有。指针只是一个内存地址,它不知道它指向哪里。
  • C++ 不会自动分配内存。在堆检查器下运行它,你会得到无效内存引用的报告。出于性能原因,C++(如 C)默认不检查这些:这是高级语言中的裸机编程。

标签: c++ pointers data-structures


【解决方案1】:

如果您对幕后“可能发生的事情”感兴趣,请考虑您平台上的 sabonete 是 4 字节宽(作为指针),并且由于您的 main 没有声明参数(操作系统let in any case aailable),可能会占用相同的内存空间,通常是参数倒序。

确实如此,它会覆盖 char** argv 指向一个指针数组(它应该包含至少 16 个),该数组指向包含命令行部分的字符串。

您实际上是在将值写入该数组上进行分配,并且由于它属于您的程序,因此操作系统不会抱怨。而且由于您从不引用它的原始值并且没有其他人更改它们,所以一切看起来都很好。

但这不是因为它很好。这是因为您很幸运能够为您不感兴趣的其他东西(在这种情况下)安装一个正在使用的空间。

【讨论】:

    【解决方案2】:

    由于 g++ 编译器不会将未分配的指针初始化为 NULL,因此它可能指向内存中包含乍一看似乎正确的数据的某个部分。

    要回答这个问题,是的,当您不愿意为对象分配内存时,这是正常但未定义的行为 :)

    【讨论】:

      【解决方案3】:

      不,恰恰相反。该指针未初始化,您正在通过取消引用它来调用 UB。如果你想要一个指针,你必须通过现有指针或调用new 来初始化它(或者,更好的是,因为这是 C++,一些对象作为容器来处理分配/销毁,即 RAII) .

      根据定义,未定义的行为意味着任何事情都可能发生。当然,由于内存布局的原因,它有时可能会起作用,但不能保证它总是会起作用,而且你永远不应该编写这样的代码。

      【讨论】:

      • 令我印象深刻的是,如果指针持有一个任意内存地址,那么为什么每次我运行这段代码时,这个任意内存地址都正好指向结构。
      • @FernandoAiresCastello:您似乎仍然感到困惑。当您调用未定义的行为时,没有押韵或理由。 行为未定义。任何事情都可能发生,无需解释为什么会发生。在该指针上方添加​​一个变量声明,您可能会看到崩溃。也许不是。同样,undefined 行为。
      • 好的,谢谢。我认为它确实有效,因为这些值已正确分配给结构的成员。但我通常不这样做,我总是初始化指针。我只是在尝试看看会发生什么:)
      【解决方案4】:

      您遇到了未定义的行为

      在第 2 行,未定义 sabonete 指向的内容。它可以指向内存,如果你改变它就不会破坏任何东西,或者它可以指向你改变它时启动核武器的内存。

      C++ 根本没有为你分配内存,你只是在踩着碰巧不会破坏任何东西的内存。

      【讨论】:

        【解决方案5】:

        C++ 没有自动分配内存;指针包含一个任意值,该值恰好是程序内存空间中的有效地址,因此您没有遇到段错误。您的程序表现出未定义的行为,下次运行时它可能无法运行。

        未定义的行为保证崩溃,这就是它被称为未定义的原因。

        【讨论】:

        • 但是当 printf 执行时,它会打印出我分配给结构成员的确切值,所以实际上它可以工作。
        • @FernandoAiresCastello:不,事实上它没有。您正在调用未定义的行为。根据定义,任何事情都可能发生。您的代码不正确。
        • 它一直有效到 . . .你把数据放进去,然后做更多的工作,它就会从你下面改变。如果您编写这样的程序,您会发现它们具有看似随机的行为和安全漏洞。
        • 它的工作方式与以每小时 80 英里的速度在高速公路上疾驰而过,前保险杠和下一辆车的“工程”之间的距离为 3 英尺。你也许可以侥幸逃脱,但很可能会出现最轻微的问题,然后你就彻底崩溃了。
        • FTR 80 英里每小时大约是 130 公里每小时。
        猜你喜欢
        • 2019-04-05
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 1970-01-01
        • 2021-11-15
        • 1970-01-01
        • 2021-12-17
        • 1970-01-01
        相关资源
        最近更新 更多