指针问题:从不兼容的类型“int”分配给“int *”
Posted
技术标签:
【中文标题】指针问题:从不兼容的类型“int”分配给“int *”【英文标题】:Pointer Problems : Assigning to 'int *' from incompatible type 'int 【发布时间】:2020-02-07 23:31:06 【问题描述】:我一直在阅读“Jumping into C++”一书,目前正在阅读指针。这是书中的一个练习:
“以下代码中x
、p_int
和p_p_int
的最终值是多少: p>
int x = 0;
int *p_int = & x;
int **p_p_int = & p_int;
*p_int = 12;
**p_p_int = 25;
p_int = 12;
*p_p_int = 3;
p_p_int = 27;
我得到了错误:
“从不兼容的类型
int
分配给int *
”
在最后三行。
我不知道为什么会这样,如果有任何见解,我将不胜感激。
此外,假设此代码以某种方式工作,我认为由于所有指针都指向单个内存 (**p_p_int -> *p_int -> x
),最后的赋值将决定内存位置。然而在书中,答案是:
x = 25, p_p_int = 27, p_int = 3
这是正确的吗?如果是这样,谁能给我解释一下?
【问题讨论】:
由于这段代码不是,也从来不是,有效的 C++,讨论输出是什么毫无意义。也许你应该试试a different book。 如果书中的其他例子与这个相似,我会选择另一本书。有一个精选列表here 那本书很旧(2013 年),并在介绍中说它不包含 C++11 标准中的任何内容。 【参考方案1】:如您所见,p_int
具有静态类型 int *
,在最后三行您正在执行类似的操作
p_int = 12;
其中12
是一个整数,因此不能分配给指针(其他两行相同)
但是,x
p_int
p_p_int
有不同的值,因为x
包含整数值,p_int
是x
的地址,p_p_int
是p_int
的地址。
还请记住,这是一个“”“”可编译的“”“”C 代码,而不是 C++,但您还会在 C 编译器上收到 3 个警告,告诉您您正在为指针分配不兼容的类型
【讨论】:
感谢您的回答,我想进一步澄清一下。我理解你所说的它们都有不同的值,但是通过适当地取消引用指针,它们都会导致内存中保存相同的值,对吗?例如,**p_p_int、*p_int 和 x 会产生相同的值吗? 没错,但它们本身就是一个“变量”,里面有一个值,每个变量之间都会发生变化【参考方案2】:这部分:
p_int = 12;
*p_p_int = 3;
p_p_int = 27;
没有办法用任何确认的 C++ 编译器编译。它只是格式不正确。即使您使用强制转换使其工作,也会导致未定义的行为。 Try a different book.
【讨论】:
不,你错了。没有未定义的行为。 "A value of any integral or enumeration type can be converted to a pointer type." 如果结果指针被取消引用,则会出现未定义的行为,但这里不会发生这种情况。 @JaMiT 你所说的是一个重大的误解。您可以将任何整数类型转换为指针,但如果该指针没有归类为basic.compound 的有效值,则评估该指针(p_int = (int*)12;
评估p_int
)会导致未定义的行为。即使你不取消引用它。因此,p_int = (int*)12
会导致未定义的行为,除非 12
恰好属于上述类别之一,这是不太可能的。
既然你喜欢引用标准,你能引用说分配无效指针未定义的部分吗?你目前的解释是缺乏的。 (例如,当p_int
被评估为p_int = (int*)12
的一部分时,p_int
中有一个有效的指针。直到赋值之后才得到一个无效的值。)
@JaMiT C17: §6.3.2.3/5 “整数可以转换为任何指针类型。除非前面指定,结果是实现定义的,可能未正确对齐,可能不指向所引用类型的实体,并且可能是陷阱表示.68)"
@JaMiT Also C17 §6.2.6.1/5 “某些对象表示不需要表示对象类型的值。如果对象的存储值具有这样的表示并且由一个没有字符类型的左值表达式,行为是未定义的。如果这种表示是由一个副作用产生的,它通过一个没有字符类型的左值表达式修改对象的全部或任何部分,则行为是未定义的。 50) 这种表示称为陷阱表示。”【参考方案3】:
int *p_int = & x;
int **p_p_int = & p_int;
这些行都指向同一个内存位置(变量 x)。
【讨论】:
并非如此。p_p_int
指向一个指向x
的变量。【参考方案4】:
您的代码 sn-p 中有三个变量。这是一个表格,显示了在执行每一行之后每个变量将具有的值(如果要实际编译代码)。
| x | p_int | p_p_int |
-------------------------+----+-------+---------|
int x = 0; | 0 | undef | undef |
int *p_int = & x; | 0 | &x | undef |
int **p_p_int = & p_int; | 0 | &x | &p_int | <-- begin: all variables lead to x
-------------------------+----+-------+---------|
*p_int = 12; | 12 | &x | &p_int |
**p_p_int = 25; | 25 | &x | &p_int |
-------------------------+----+-------+---------| <-- end: all variables lead to x
p_int = 12; | 25 | 12 | &p_int | <-- p_int now points to garbage
*p_p_int = 3; | 25 | 3 | &p_int |
-------------------------+----+-------+---------|
p_p_int = 27; | 25 | 3 | 27 | <-- p_p_int now points to garbage
------------------------------------------------/
我使用undef
表示该变量尚不存在(即未定义); &x
和 &p_int
表示这些变量的地址(因为不知道确切的值)。
如果您意识到*p_int
和p_int
引用内存中的不同值,这是一个思考练习,看看您是否了解不同级别的间接。正如您所注意到的,它无法编译。将数字文字分配给指针几乎可以肯定是一个错误,在这种思想实验之外没有用处。在实际代码中,p_int = 12
之类的行可能是拼写错误(很可能是 *p_int = 12
),编译器会提醒您注意这一点。
幸运的是,作者似乎意识到尝试访问地址 12
、3
和 27
的内存是不可取的,因为在存储时既没有取消引用 p_int
也没有取消引用 p_p_int
一个虚假的地址。尽管如此,如果作者承认这些限制,或者更好地设计一个不需要这样的免责声明的练习,那就太好了。 (希望这是一个孤立的失误。与某些人不同,我不会根据一个练习来谴责整本书。书很长,C++ 很复杂,mistakes happen。) p>
【讨论】:
不,你错了。如果没有 C++ 中的显式转换,就不能将int
分配给指针。此外,评估像 p_int = (int*)12
这样的指针会导致未定义的行为,因此不再是有效的 C++。
@Ayxan 你读过我写的“如果代码要实际编译”的部分吗?我写“这是一个思想练习”的部分??我写“它不编译”的部分???我写的部分“编译器会提醒你这一点”????我写的部分“在存储虚假地址时,p_int
和 p_p_int
都没有被取消引用”?????
一旦导致未定义的行为,您就无法再以任何有意义的方式对程序进行推理。由于您的解释假设 UB,因此您不再谈论 C++。即使这是一个理论实验。指针不仅仅是 int`s。您不能将任何旧的 int 转换为指针并期望定义明确的行为。
供将来参考: 我已经查看了 Ayxan 的 cmets 并确定它们不正确。行为是实现定义的,而不是未定义的。它是有效的 C++,并且可以以一种有意义的方式对其进行推理。
我不确定您是如何查看任何内容的,但我发布的问题没有得到任何令人满意的答案,因此我没有接受任何答案。即使它只是定义了实现,你的“思考练习”假设没有任何实现在任何有意义的方式中都是没有意义的,正如我之前提到的(你怎么能假设没有实现的实现定义的行为?)。以上是关于指针问题:从不兼容的类型“int”分配给“int *”的主要内容,如果未能解决你的问题,请参考以下文章
指向分配给“NSInteger”(又名“int”)的整数转换的不兼容指针
c++错误:从不兼容的类型'const char *'分配给'char *'
我收到错误消息,“从不兼容的类型“gameViewController”分配给“id avaudioplayerdelegate””[关闭]
从不兼容的类型“MainViewController *”分配给“id<MFMessageComposeViewControllerDelegate>”