我试着运行这段代码,
int *p;
float q;
q = 6.6;
p = &q;
Run Code Online (Sandbox Code Playgroud)
虽然它会是一个警告,但我认为&q并且p大小相同,所以p可以有一个地址q.但是当我打印&q并且p我得到不同的输出.这是我的输出
*p = 6.600000
q = 0.000000, p = 0x40d33333, &q = 0x7fffe2fa3c8c
Run Code Online (Sandbox Code Playgroud)
我错过了什么?和p和&q是相同的当两个指针和变量类型是一样的.
我的完整代码是
#include<stdio.h>
void main()
{
int *p;
float q;
q = 6.6;
p = &q;
printf("*p = %f \n q = %f, p = %p, &q = %p \n",*p,q,p,&q);
}
Run Code Online (Sandbox Code Playgroud)
您需要更严肃地对待编译器警告.
C不要求编译器拒绝无效程序,它只需要"诊断"来规则违规.诊断可以是致命错误消息或警告.
不幸的是,编译器通常会为不兼容的指针类型的分配发出警告.
void main()
Run Code Online (Sandbox Code Playgroud)
这是错的; 它应该是int main(void).你的编译器可能会让你逃脱它,它可能不会导致任何明显的问题,但没有必要正确编写它.(这不是很简单,但是这已经足够接近.)
int *p;
float q;
q = 6.6;
Run Code Online (Sandbox Code Playgroud)
没关系.
p = &q;
Run Code Online (Sandbox Code Playgroud)
p属于int*; &q是类型的float*.将一个分配给另一个(没有强制转换)是违反约束的.看待它的最简单方法是它完全是非法的.
如果你真的想做这个任务,你可以使用一个演员:
p = (int*)&q; /* legal, but ugly */
Run Code Online (Sandbox Code Playgroud)
但这样做的理由很少. p是指向int; 应该指出的int,除非你有一个对象非常充分的理由,使其指向别的东西.在某些情况下,转换本身可能具有未定义的行为.
printf("*p = %f \n q = %f, p = %p, &q = %p \n",*p,q,p,&q);
Run Code Online (Sandbox Code Playgroud)
该%f格式要求double的参数(float参数提升为double在这方面如此float将是确定的).但是*p类型int.printf使用错误类型的参数调用会导致程序的行为未定义.
%p需要一个类型的参数void*,而不仅仅是任何指针类型.如果要打印指针值,则应将其强制转换为void*:
printf("&q = %p\n", (void*)&q);
Run Code Online (Sandbox Code Playgroud)
它可能在没有强制转换的情况下工作,但同样,行为是不确定的.
如果在编译程序时收到任何警告,请不要打扰它.首先修复警告.
至于标题中的问题,类型指针int*和float*不同类型的指针.一个int*应指向的int对象; a float*应该指向一个float对象.您的编译器可能会让您混合它们,但这样做的结果是实现定义或未定义.C语言,特别是许多C编译器,可以让你逃避许多没有多大意义的事情.
它们是不同类型的原因是(试图)防止或至少检测其使用中的错误.如果声明一个类型的对象,则int*表示您打算将其指向一个int对象(如果它不是空指针).在float对象中存储对象的地址int*几乎肯定是一个错误.强制类型安全允许尽早检测到此类错误(当您的编译器打印警告时,而不是在重要客户端的演示期间程序崩溃时).
它可能(但不能保证)int*并且float*具有相同的大小并具有相同的内部表示.但含义一个的int*对象不是"包含虚拟地址32(或64)位的集合",但"的东西,指向一个int对象".
你得到了未定义的行为,因为你传递了错误的类型printf.当你告诉它期望一个浮动时,它实际上期望一个double- 但你传递了一个int.
因此,它会输出错误的信息,因为printf完全依赖于格式字符串来访问传递它的参数.