包含相同类型的结构指针的结构指针的初始化
Posted
技术标签:
【中文标题】包含相同类型的结构指针的结构指针的初始化【英文标题】:Initialization of struct pointer containing a struct pointer of same type 【发布时间】:2019-12-11 14:48:36 【问题描述】:我试图了解指向结构对象的指针(其中包含指向相同类型的结构的指针)的初始化是如何发生的。例如我有一个struct
:
struct node
node *next;
;
假设我有一个内存池的起始地址,即内存池是一个指向起始位置的指针。 (为了争论,假设起始内存是1001
。)
char* pool[65536];
现在我声明一个node
类型的指针,并通过reinterpret_cast
为其分配起始内存。
node* a =reinterpret_cast<node *>(pool);
当前a
指向内存1001
。现在我声明另一个指针
node* b;
b=a;
现在发生的事情是b
指向与a
相同的地址,即1001
。指针b->next
指向某个预期的随机位置,但指针b->next
的地址与b
指向的地址相同,即1001
。即
&b->next = b
我不明白为什么b->next
的地址与b
指向的指针相同?根据我的理解b->next
应该位于b
所在的位置。
P.S:我试图找出这是如何发生的,但找不到相关文档。如果此类问题已在某些文档或其他问题中得到解答,请务必提供链接。
P.P.S:在和我的同事进一步讨论这个问题后,我发现b
是一个指针而不是一个对象。它指向一个位置(即1001
),根据b
,存在一个包含指针next
的节点对象,因此b->next
(&b->next
)的地址与b
正在指向。
【问题讨论】:
node* a =1001;
不会编译。
由于您专门使用了 C++17 标签,所以我删除了 C 标签。 C 和 C++ 是不同的语言,答案可能取决于此。如果您想询问C,请将C++标签更改为C标签。
为什么b->next
的地址与b
指向的地址不同?在您看来,b->next
还会位于何处?两者都是node*
类型的事实无关紧要。考虑:struct S int n;; S s; std::cout << ( (void*)&s == (void*)&s.n );
这将打印1
尝试随机的东西并不是学习 C++ 的好方法。
指针是一个很难且很长的话题。我建议通过指针上的 good C++ book 的 cahpter(s),然后看看是否能回答您的问题。需要的另一点信息是,对于标准布局类型(节点是什么),类的地址与其第一个成员的地址相同。
【参考方案1】:
让我们采用基本前提,但用一个有效的例子代替:
node* a = new node;
node* b = a;
现在a
和b
都指向同一个对象,内存中的同一个位置。
从图形上看,它看起来像这样:
+---+ |一个 | --\ +---+ \ +-----------------+ >--> |节点对象 | +---+ / +-----------------+ |乙 | --/ +---+因为a
和b
都指向完全相同的对象,所以a->next
和b->next
必须完全相同。您可以通过打印&a->next
和&b->next
来验证它。
a->next
和b->next
的(当前不确定的)值可能看起来不同的唯一原因是undefined behavior。首先因为a->next
(因此b->next
)是不确定的,除了初始化之外,以任何方式使用它的值都会导致UB。其次,如果您没有以正确的方式初始化 a
或 b
(例如,您确实像在您的问题中那样初始化它),那么当您取消引用 a
或 b
时,您也有 UB。
【讨论】:
这是合理的:如果 a = b,f(a) = f(b)。 “可能不同”->“可能看起来不同”【参考方案2】:假设我声明了一个节点类型的指针并为其分配一些起始内存(例如 1001)
为了论证,我将假设这段代码可以编译,你可以直接将任意整数分配给没有reinterpret_cast
的指针。
a
现在是 C++ 所说的“无效指针”。它是一个指针,但它不指向任何东西。
现在发生的情况是“b”指向与“a”相同的地址,即 1001。
没错。 b
现在与 a
一样无效。
指针“b->next”
不。如果取消引用无效指针,则会得到未定义的行为。 b
实际上并不指向 node
对象,因此没有 b->next
指针。所以说不存在的b->next
指针的值是没有意义的。
指针“b->next”的地址与b指向的地址相同,即1001。
听起来您实际上在谈论的是结构node
的布局。事实上,给定一些node
类型的对象,该对象的地址和它的第一个数据成员的地址将是相同的。因为node
是标准布局,所以这是真的。
但需要注意的是,第一个数据成员的地址并不是next
指向的地址。它是next
本身的地址。指针是一个对象,就像任何其他对象一样,因此它存储在内存中。因此,你可以得到一个指针指向一个指针。它是指向next
指针的指针,它将与它所在的node
对象具有相同的地址,而不是next
指针本身的值。
也就是说,在一个假设有效的示例中,b
和 &b->next
的地址将相同。
【讨论】:
【参考方案3】:这是 C++ 的要求(模内存填充):结构的第一个成员位于与结构本身相同的地址。
为了比较, 您可以将其视为一个数组,在字符串中
abcd
(a
是出于实际目的,与您问题中的a
不同)
a
与字符串 abcd
位于同一位置。
字符串是你的结构,每个字母都是一个字段。 a
可以是 node::next
。术语“指向一个结构”是“指向给定结构的第一个字节”的同义词。
例如,如果问题是,字符串abcd
在这个序列中的位置:
1234abcd56789
你会说4
,因为它是字符串的第一个元素所在的位置。在大多数情况下,与 C++ 相同。而a
也位于4
的位置。
注意:正如 NathanOlivier 所述,这仅对标准布局类型有效。
【讨论】:
结构的第一个成员指向与结构本身相同的地址。这仅适用于标准布局类型。以上是关于包含相同类型的结构指针的结构指针的初始化的主要内容,如果未能解决你的问题,请参考以下文章