打印数组元素

3
以下C程序的预期输出是打印数组元素。但实际运行时,它并未打印出来。
#include<stdio.h>

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))

int array[] = {23,34,12,17,204,99,16};

int main()
{
    int d;

    for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
        printf("%d\n",array[d+1]);

    return 0;
}

什么是原因?

为什么不直接使用 for (d = 0; d < TOTAL_ELEMENTS; ++d) 呢? - fredoverflow
2
也许这是一个很好的教材例子,说明在C语言中编写正确的程序有多么困难。因此,它确实是一个非常好的例子。 - Roland Illig
这个问题是Gowri Korumar的C谜题的一部分,这是50个非常有教育意义的C问题的汇编。我回答了前25个问题,既从过去的知识中也进行了研究,以防有所帮助:C puzzles answered - JoseV
6个回答

6

TOTAL_ELEMENTS 是无符号的。-1 转换成无符号数后,变成一个非常大的数值,至少不小于 6。因此,你的循环永远不会执行。


是的...你不应该在没有充分理由的情况下混合使用有符号/无符号赋值或比较,这种情况下需要进行显式转换。此外,如果设置了适当的警告级别,大多数编译器都应该发出警告。 - smichak

5
当您进行比较d <= (TOTAL_ELEMENTS-2)时,会执行类型转换。其中d是有符号整数类型,而(TOTAL_ELEMENTS-2)是无符号类型size_t。C语言规定,当操作符具有有符号和无符号参数,并且无符号参数的大小大于等于有符号参数时,那么有符号参数将被转换为无符号参数。也就是说,比较最终变成了:
(size_t) d <= (TOTAL_ELEMENTS-2)

由于size_t是无符号的,所以(size_t) -1不再是-1,而是一个非常大的数字。对于32位的size_t来说,它将是2的32次方减1,即4,294,967,295。

要解决这个问题,你可以将右边的值显式地转换为有符号整数:

d <= (int) (TOTAL_ELEMENTS-2)

或者更好的方法是,摆脱奇怪的负索引等。

以后参考,尽可能打开所有可用的编译器警告。例如,如果您打开-Wall -Wextra,gcc将打印警告:

$ gcc -o arrayprint -Wall -Wextra -ansi arrayprint.c 
arrayprint.c: In function ‘main’:
arrayprint.c:11: warning: comparison between signed and unsigned

除了将宏的结果转换为“int”之外,从一开始就使用“size_t”作为“d”,并使用适当的边界“0”作为起始点和“d < TOTAL_ELEMENTS”作为条件会更简单。 - Jens Gustedt

3

起初,我并不知道。但当我使用GCC编译它时,显然很明显:

$ gcc -Wall -Wextra -Os a.c
a.c: In function `main':
a.c:11: warning: comparison between signed and unsigned

所以你有以下比较:

(int) -1 <= (size_t) 5

由于其中一种类型是有符号的,另一种类型是无符号的,因此它们需要先转换为一个通用类型。在这种情况下,它是 size_t。这使得它变成了:

(size_t) -1 <= (size_t) 5

现在,无法用无符号类型表示-1。因此,将2^32(或size_t具有的位数)加到它上面,这使得它变成了4294967295。因此,比较实际上是:

4294967295 <= 5

这是false,因此循环体永远不会执行。


1

原因是循环从未执行。这是因为TOTAL_ELEMENTS返回一个无符号类型的size_t。

您可以通过将(TOTAL_ELEMENTS-2)强制转换为int来解决此问题。


0
你需要做以下事情:
for(d=0;d < TOTAL_ELEMENTS;d++)
    printf("%d\n",array[d]);

由于sizeof(...)生成的是无符号值,因此...


0

只需简单更改

#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))

使用

#define TOTAL_ELEMENTS (int)(sizeof(array)/sizeof(array[0]))-2

你真的把它搞错了。数组索引应该始终只是“size_t”。他只需要将“d”更改为“size_t”,进行适当的索引,所有混乱都会消失... - Jens Gustedt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接