9

我试图运行这段代码,

int *p;
float q;
q = 6.6;
p = &q;

虽然这将是一个警告,但我认为&qp大小相同,所以p可以有一个地址q。但是当我打印时&qp我得到了不同的输出。这是我的输出

*p =  6.600000 
 q = 0.000000, p = 0x40d33333, &q = 0x7fffe2fa3c8c 

我错过了什么?当指针和变量类型相同时, pand&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);
}
4

3 回答 3

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属于类型intprintf使用错误类型的参数调用会导致程序的行为未定义。

%p需要 type 的参数void*,而不仅仅是任何指针类型。如果要打印指针值,应将其转换为void*

printf("&q = %p\n", (void*)&q);

它可能在没有演员表的情况下工作,但同样,行为是未定义的。

如果您在编译程序时收到任何警告,请不要费心运行它。首先修复警告。

至于标题中的问题,类型指针和类型int*不同float*。Anint*应该指向一个int对象;afloat*应该指向一个float对象。您的编译器可能会让您混合使用它们,但这样做的结果是实现定义或未定义。C 语言,尤其是许多 C 编译器,会让你摆脱很多没有多大意义的事情。

它们是不同类型的原因是(试图)防止或至少检测它们使用中的错误。如果您声明一个类型为 的对象,int*则表示您打算让它指向一个int对象(如果它不是空指针)。float在对象中存储对象的地址int*几乎可以肯定是一个错误。强制类型安全允许尽早检测到此类错误(当您的编译器打印警告时,而不是当您的程序在一个重要客户端的演示期间崩溃时)。

很可能(但不能保证)int*并且float*大小相同并且具有相同的内部表示。但是对象的含义不是int*“包含虚拟地址的 32(或 64)位的集合”,而是“指向int对象的东西”。

于 2013-04-03T15:22:21.843 回答
8

你得到未定义的行为,因为你将错误的类型传递给printf. 当你告诉它期待一个浮点数时,它实际上期待一个double- 但你传递了一个int.

结果它打印了错误的信息,因为printf完全依赖于格式字符串来访问你传递给它的参数。

于 2013-04-03T15:12:14.857 回答
0

除了teppic所说的,

考虑,

int a = 5;
int *p = &a;

在这种情况下,我们向编译器指示p将指向一个整数。因此,众所周知,当我们*p在运行时执行类似的操作时,没有。int将读取等于大小的字节。

如果将占用x字节数的数据类型的地址分配给声明为保存字节数少于 的数据类型地址的指针,则x在使用间接运算符时会读取错误的字节数。

于 2013-04-03T15:20:48.680 回答