【问题标题】:Is the printf statement valid?printf 语句是否有效?
【发布时间】:2013-06-05 11:32:57
【问题描述】:
int main()
{

    struct a
    {
        struct a *next;
        struct a *prev;
    };

    struct a *A[2];

    printf("Address of (&(A[0])->next) = %p",(&(A[0])->next));
    getch();
    return 0;
}

在上面的 printf 语句中,我正在访问“struct a”结构的“next”指针,当我在开发编译器中运行程序时,它给了我有效的内存地址(尽管我还没有为它分配任何内存)。解释为什么会发生这种情况将非常有帮助。

是否为“下一个”和“上一个”字段分配了内存?

【问题讨论】:

  • 但它是正确的内存地址吗?不,AFAICS 你正在取消引用一个未初始化的指针,所以如果它有效,那就是侥幸。请注意,您实际上并没有为 As 分配任何内存——您是在告诉它您有一个指向 As 的指针数组。您分配的唯一内容是存储这些指针的内存。
  • 它可能会一直发生,是的,例如它重用了以前指向某个 init 结构或堆栈上其他位置的堆栈帧的某些部分。但是不能保证会有一个有效的指针,如果你例如使用大多数编译器在调试模式下编译它会将堆栈初始化为无效指针,例如像 0xCCCCCCCC 这样的奇数,肯定会失败。
  • printf-statement 本身非常有效,但是您尝试打印的数据却不是。取消引用统一化的指针将导致undefined behaviour,这可能会导致程序可能做你想做的事,但它们也可能让你的猫着火。
  • @Rup 我认为这种侥幸每次都在发生。 + 如果我将 printf 修改为 printf("Address of (&(A[0])->next) = %p", (((struct a *)(&(A[0])))->next) );侥幸永远不会发生

标签: c pointers struct


【解决方案1】:

让我们想想这意味着什么:

&(A[0])->next

它是next 指针的地址(不是它指向的位置,而是指针本身的地址)。而next指针是struct a的第一个元素,所以next的地址与其封闭的a的地址相同。

因此,表达式就是A[0]所引用的struct a的地址。在您的原始代码中,您从不在那里分配任何东西,所以它只是一个正在打印的垃圾值。正如@alk 在另一个答案中指出的那样,您可以初始化变量A 中的两个指针,然后您会看到这些值中的第一个被打印出来(例如,0x0)。

顺便说一句,如果你想快速初始化A,就这样做吧,而不是更冗长的memset()

struct a *A[2] = {0};

它做同样的事情(将两个指针设置为 0)。

虽然打印的值是垃圾,但代码可能不是非法的。这可能看起来令人惊讶,但请看这里:Dereferencing an invalid pointer, then taking the address of the result - 你有类似的东西,尽管你承认你已经通过取消引用结构的成员而不是简单地使用 * 更进一步。所以我心中的悬而未决的问题是:鉴于foo 是指针时&*foo 总是合法的(如上面的链接所示),&foo->bar 是否同样适用?

【讨论】:

  • 请注意,您链接到的问题是关于 C++ 的,因此 C 的答案实际上可能不同。
  • @Shahbaz:不,这个问题被标记为 C++,但大部分讨论都是关于 C 的,它说 &*foo 在 C 中总是合法的,即使在 C++ 中不清楚。
  • struct a *A[2] = {}; 是一个 C++ 结构。在 C 中,您需要在大括号中添加一个初始化器,例如 struct a *A[2] = {{0}};
  • @DanielFischer:谢谢,已将{}(如果您不使用-pedantic GCC 接受)更新为{0}
【解决方案2】:
&(A[0])->next

A数组中第一个结构的next成员的地址。

这可以被认为是&A[0] + offsetof(struct a, next)。即,这只会导致未初始化指针A[0] 的值加上next 成员与结构基地址的偏移量(恰好为零,因为next 是第一个结构的元素)。

根据 C 标准,您的程序调用 未定义行为,因为它对无效指针执行指针运算。 但是,在实践中,这很可能不会崩溃并打印出虚假地址(仅执行加法,没有任何内容访问指针后面的内存)。但是,如果您实际上取消引用指针,预计会发生崩溃。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-15
    • 1970-01-01
    • 2016-12-20
    • 2012-01-10
    • 1970-01-01
    • 2011-03-20
    • 1970-01-01
    相关资源
    最近更新 更多