1

我正在从“理解 C 中的指针”一书中做一些练习。这本书给了你一段代码,并询问你在输出中得到了什么。

其中之一如下:

#include <stdio.h>

int main(int argc, char* argv[])
{
    char c, *cc;
    int i;
    long l;
    float f;

    c = 'Z';
    i = 15;
    l = 77777;
    f = 3.14;
    cc = &c;
    printf("c=%c cc=%u\n", *cc, cc);
    cc = &i;
    printf("i=%d cc=%u\n",*cc,cc);
    cc=&l;
    printf("l=%ld cc=%u\n",*cc,cc);
    cc=&f;
    printf("f=%f cc=%u\n",*cc,cc);
    return 0;
}

输出是:

c=Z cc=1946293623
i=15 cc=1946293616
l=4294967249 cc=1946293608
f=0.000000 cc=4294967235

我不明白为什么 l并且f不打印为77777and 3.14

我检查了 The C Programming Language 一书,看看printf' 的控制字符是否正确,它们是否正确。

4

5 回答 5

3

正如 Bryan 的回答所说,传递给的参数类型printf需要与格式字符串指定的类型相匹配。

打印指针值的格式是"%p"-- 并且它需要一个void*参数;另一种类型的指针应显式转换为void*.

由于类型不匹配,您的程序具有未定义的行为。它也有约束冲突,因为它试图在没有强制转换的情况下分配不兼容的指针类型;cc = &i;是非法的(但如果编译器选择,它只能警告它)。你应该已经从你的编译器那里得到了几个警告。

希望该计划的目的是展示该做什么。return让我们只考虑语句之前的最后两行:

cc=&f;
printf("f=%f cc=%u\n",*cc,cc);

cc = &f;违反约束并需要诊断(恕我直言,一个好的编译器应该给您一个致命错误并拒绝该程序)。&f是 类型float*, 并且cc是 类型char*; 这些类型不是赋值兼容的。

大多数接受该语句的编译器都假定它意味着隐式转换,使其等效于合法但棘手的:

cc = (char*)&f;

这导致cc指向float对象的第一个字节f

printf("f=%f cc=%u\n",*cc,cc);

这声称打印 的值f,但事实并非如此;它打印指向的char对象的值cc,它恰好是f. 它使用该对象的%f格式,该char对象具有未定义的行为。结果是垃圾。

我打算编写该程序的“更正”版本,但它有很多问题,我无法弄清楚它打算做什么。

我检查了 The C Programming Language 一书,看看 printf 的控制字符是否正确,它们是否正确。

不,他们不是。"%f"打印一个floatordouble参数是正确的(在这种情况下float被提升为double),但你正在传递一个char参数。

这是正确的:

printf("*cc = %d, cc = %p\n", *cc, (void*)cc);

但它不会做同样的事情;它将指向的 char 打印cc为 an int(您可以使用%c将其打印为字符,但它可能无法打印),然后将 的值打印cc为指针。

看看这本书对这个程序的描述会很有趣。

于 2013-04-22T15:04:09.363 回答
2

printf(更糟糕的是)的格式说明符scanf必须匹配作为参数传递的类型。如果您正在使用,请gcc使用该-Wall选项,它也会对此发出警告。您的代码应如下所示:

printf("c=%c cc=%u\n", *cc, (unsigned int)cc);
cc = &i;

将地址i带入char*解释不再有意义,对于下面的其他人也没有意义。通过分配指针,您强制执行对相同位表示的错误解释。

于 2013-04-22T14:42:11.077 回答
1
printf("l=%ld cc=%u\n",*(long*)cc,cc);
printf("f=%f cc=%u\n",*(float*)cc,cc);

这有效,但是

printf("l=%ld cc=%u\n",*cc,cc);
printf("f=%f cc=%u\n",*cc,cc);

由于以下原因,这并不像预期的那样。

每个指针都是 4 个字节(取决于操作系统而不是它指向的位置。)所以即使是 float 的地址也可以存储到 char * 中。但是当我们进行指针运算或读取指针的值时,*cc它会根据指针的类型读取字符数...

假设一个字符有 2 个字节,那么*cc将只读取 2 个字节,cc其中的地址为浮点数或长整数已存储在 4 个字节(或更多)中。所以它会显示无效数据。

当我们对它进行类型转换时,它会被转换*(long*)cc为带有显式类型转换的长指针。

于 2013-04-22T14:59:00.450 回答
1

你的程序有很多问题!!!

首先,不要将%u格式说明符用于指针。unsigned integers并且pointers不需要本质上具有相同的大小。始终%p用于pointers.Eg

printf("c=%c cc=%p\n", *cc, cc);

第二个最重要的事情——永远不要使用 YK 的那本书“Understanding pointers in C”(由于显而易见的原因,我不能完整地命名作者)。他的另一本书是臭名昭著的“void main”书。

第三,回到您的程序,我很惊讶您在将整数和浮点变量的地址分配给字符指针时没有收到任何警告,而没有进行强制转换。.这必然会产生错误,因为您的程序将无法知道要从指定位置解释多少字节。int, float, 并且char大小不一。您可能想知道为什么当时没有出错int?正确的?这是因为您的计算机的小端架构,其中最不重要的字节首先存储。

所以这是你的更正:

cc =(char*) &i;
printf("i=%d cc=%p\n",*(int*)cc,cc);
cc=(char*)&l;
printf("l=%ld cc=%p\n",*(long*)cc,cc);
cc=(char*)&f;
printf("f=%f cc=%p\n",*(float*)cc,cc);
于 2013-04-22T14:59:11.860 回答
0

尝试这个

printf("l=%ld cc=%u\n",*(long*)cc,cc);
printf("f=%f cc=%u\n",*(float*)cc,cc);
于 2013-04-22T14:41:14.877 回答