[Pour mémoire, j'ai modifié cette réponse de manière assez significative depuis qu'elle a été acceptée et mise aux voix. Cela dit toujours essentiellement les mêmes choses.]
Ce code est profondément, peut-être délibérément, déroutant. Il contient une instance étroitement évitée du comportement redouté non défini . Il est fondamentalement impossible de déterminer si la personne qui a construit cette question était très, très intelligente ou très, très stupide. Et la «leçon» que ce code pourrait prétendre vous enseigner ou vous interroger - à savoir que l'opérateur unaire plus ne fait pas grand-chose - n'est certainement pas assez importante pour mériter ce genre de mauvaise orientation subversive.
Il y a deux aspects confus du code, l'étrange condition:
while(+(+k--)!=0)
et la déclaration démente qu'il contrôle:
k=k++;
Je vais d'abord couvrir la deuxième partie.
Si vous avez une variable comme k
celle que vous souhaitez incrémenter de 1, C vous donne non pas une, pas deux, pas trois, mais quatre façons différentes de le faire:
k = k + 1
k += 1
++k
k++
Malgré cette générosité (ou peut-être à cause de cela), certains programmeurs sont confus et crachent des contorsions comme
k = k++;
Si vous ne pouvez pas comprendre ce que cela est censé faire, ne vous inquiétez pas: personne ne le peut. Cette expression contient deux tentatives différentes de modifier k
la valeur (la k =
partie et la k++
partie), et comme il n'y a pas de règle en C pour dire laquelle des tentatives de modification "gagne", une expression comme celle-ci est formellement indéfinie , ce qui signifie non seulement que il n'a pas de sens défini, mais que l'ensemble du programme qui le contient est suspect.
Maintenant, si vous regardez très attentivement, vous verrez que dans ce programme particulier, la ligne k = k++
n'est pas exécutée, car (comme nous allons le voir) la condition de contrôle est initialement fausse, donc la boucle s'exécute 0 fois . Donc , ce programme ne pourrait pas réellement être indéfini - mais il est toujours déroutant pathologiquement.
Voir également ces réponses SO canoniques à toutes les questions concernant le comportement indéfini de ce type.
Mais vous n'avez pas posé de questions sur la k=k++
partie. Vous avez posé des questions sur la première partie déroutante, la +(+k--)!=0
condition. Cela semble étrange, car il est étrange. Personne n'écrirait jamais un tel code dans un vrai programme. Il n'y a donc aucune raison d'apprendre à le comprendre. (Oui, c'est vrai, explorer les limites d'un système peut vous aider à en savoir plus sur ses subtilités, mais il y a une ligne assez claire dans mon livre entre les explorations imaginatives et suscitant la réflexion contre les explorations stupides et abusives, et cette expression est très clairement sur du mauvais côté de cette ligne.)
Quoi qu'il en soit, examinons +(+k--)!=0
. (Et après cela, oublions tout.) Toute expression comme celle-ci doit être comprise de l'intérieur. Je suppose que tu sais quoi
k--
Est-ce que. Il prend k
la valeur actuelle de 'et la "retourne" au reste de l'expression, et il diminue plus ou moins simultanément k
, c'est-à-dire qu'il stocke la quantité k-1
dans k
.
Mais alors qu'est-ce que ça +
fait? C'est un plus unaire , pas un plus binaire. C'est comme un moins unaire. Vous savez que le binaire moins fait la soustraction: l'expression
a - b
soustrait b de a. Et vous savez que le moins unaire nie les choses: l'expression
-a
vous donne le négatif d'un. Ce que fait unaire, +
c'est ... essentiellement rien. +a
vous donne a
la valeur après avoir changé les valeurs positives en valeurs positives et négatives en négatives. Donc l'expression
+k--
vous donne tout ce k--
qui vous a donné, c'est-à-dire k
l'ancienne valeur.
Mais nous n'avons pas fini, car nous avons
+(+k--)
Cela prend tout ce +k--
qui vous a été donné et s'applique +
de nouveau à lui. Donc, cela vous donne tout ce qui vous a +k--
donné, ce qui k--
vous a donné, qui était k
l'ancienne valeur.
Donc à la fin, la condition
while(+(+k--)!=0)
fait exactement la même chose que la condition beaucoup plus ordinaire
while(k-- != 0)
aurait fait. (Il fait également la même chose que l' while(+(+(+(+k--)))!=0)
aurait fait une condition d'apparence encore plus compliquée . Et ces parenthèses ne sont pas vraiment nécessaires; il fait également la même chose que l' while(+ + + +k--!=0)
aurait fait.)
Même comprendre ce que la condition "normale"
while(k-- != 0)
est un peu délicat. Il y a en quelque sorte deux choses qui se passent dans cette boucle: Comme la boucle s'exécute potentiellement plusieurs fois, nous allons:
- continuer à faire
k--
, pour faire de k
plus en plus petit, mais aussi
- continuez à faire le corps de la boucle, quoi que cela fasse.
Mais nous faisons la k--
partie tout de suite, avant (ou en train de) décider de faire un autre voyage à travers la boucle. Et rappelez-vous que k--
"renvoie" l'ancienne valeur de k
, avant de la décrémenter. Dans ce programme, la valeur initiale de k
est 0. Il k--
va donc "retourner" l'ancienne valeur 0, puis mettre k
à jour à -1. Mais le reste de la condition est != 0
- mais comme nous venons de le voir, la première fois que nous avons testé la condition, nous avons obtenu un 0. Donc, nous ne ferons aucun voyage dans la boucle, donc nous n'essaierons pas d'exécuter le déclaration problématique k=k++
du tout.
En d'autres termes, dans cette boucle particulière, même si j'ai dit "qu'il se passe en quelque sorte deux choses", il s'avère que la chose 1 se produit une fois, mais la chose 2 se produit zéro fois.
En tout cas, j'espère qu'il est maintenant suffisamment clair pourquoi cette mauvaise excuse pour un programme finit par imprimer -1 comme valeur finale de k
. Normalement, je n'aime pas répondre à des questions de quiz comme celle-ci - cela ressemble à de la triche - mais dans ce cas, comme je suis tellement bruyamment en désaccord avec le but de l'exercice, cela ne me dérange pas.