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