2010-08-01 4 views
3

La sortie attendue du programme C suivant est d'imprimer les éléments du tableau. Mais quand il est réellement exécuté, il ne le fait pas.Impression des éléments d'un tableau

#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; 
} 

Quelle est la raison?

+0

Pourquoi ne pas simplement 'pour (d = 0; d fredoverflow

+2

Peut-être est-ce un exemple instructif de la difficulté de programmer correctement en C. Et à ce titre, c'est en effet un très bon exemple. –

+0

Cette question fait partie de [C puzzles de Gowri Korumar] (http://www.gowrikumar.com/c/), une compilation de 50 questions C très éducatives. J'ai répondu aux 25 premières questions à la fois des connaissances et des recherches passées, au cas où cela aiderait: [C puzzles répondu] (http://codeitdown.com/c-puzzles-answered/). – JoseV

Répondre

5

Lorsque vous effectuez la comparaison d <= (TOTAL_ELEMENTS-2), une conversion de type est effectuée. d est de type signed int tandis que (TOTAL_ELEMENTS-2) est de type size_t, qui est un type non signé. Les règles de C indiquent que lorsqu'un opérateur a un argument signé et un argument non signé, et que l'argument non signé est de taille supérieure ou égale à l'argument signé, alors l'argument signé est converti en unsigned.

C'est, la comparaison se termine comme:

(size_t) d <= (TOTAL_ELEMENTS-2) 

Et parce que size_t est non signé, (size_t) -1 est un nombre vraiment, vraiment grand, pas -1 plus. Pour un size_t 32 bits, ce serait 2 - 1 = 4,294,967,295.

Pour résoudre ce problème, vous pouvez convertir explicitement le côté droit de signé int:

d <= (int) (TOTAL_ELEMENTS-2) 

Ou, mieux, simplement se débarrasser de l'indexation négative bizarre et tel.

Pour référence ultérieure, activez tous les avertissements du compilateur vous pouvez. gcc, par exemple, affichera un avertissement si vous activez -Wall -Wextra:

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

autre que de convertir le résultat de la macro en 'int', il serait beaucoup plus simple d'utiliser' size_t' pour 'd' depuis le début et d'utiliser les limites appropriées' 0' pour le début et 'd

6

TOTAL_ELEMENTS est non signé. -1, lorsqu'il est converti en unsigned, est un nombre vraiment énorme, qui n'est pas inférieur à 6. Ainsi, votre boucle ne s'exécute jamais.

+0

Oui ... vous ne devez jamais mélanger des assignations signées/non signées ou des comparaisons sans raison valable et dans ce cas, un casting explicite est en place. En outre, la plupart des compilateurs devraient avoir émis un avertissement à ce sujet si le niveau d'avertissement approprié a été défini. – smichak

1

La raison est que la boucle n'est jamais exécutée. En effet, TOTAL_ELEMENTS renvoie un size_t, un type non signé.

Vous pouvez résoudre ce problème en lançant (TOTAL_ELEMENTS-2) dans un int.

0

Vous devez effectuer les opérations suivantes:

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

comme sizeof(...) produit une valeur non signée.

3

Au début, je ne savais pas. Mais quand je compilé en utilisant GCC, il était évidemment apparente:

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

Vous avez donc une comparaison comme suit:

(int) -1 <= (size_t) 5 

Comme l'un des types est signé et l'autre est non signé, ils ont d'abord besoin d'être converti en un type commun. Dans ce cas, il s'agit de size_t. Cela en fait:

(size_t) -1 <= (size_t) 5 

Maintenant -1 ne peut pas être représenté dans un type non signé.Par conséquent, 2^32 (ou cependant de bits size_t HAS) est ajouté, ce qui le rend 4294967295. donc la comparaison est vraiment:

4294967295 <= 5 

Et c'est false, donc le corps de la boucle est jamais exécutée.

0

changer simplement

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

Avec

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

vous le prenez vraiment du mauvais côté. Les index de tableau doivent toujours être 'size_t'. Il devrait juste changer 'd' pour être de' size_t' et faire une indexation correcte et tout le fuzz s'en va ... –