Pour chaque personnage que vous lisez, vous avez deux choses à faire:
- Vérifiez si c'est EOF.
- Sinon, écrivez-le en sortie.
Votre problème est que vous faites ces deux choses dans le mauvais ordre.
Il existe potentiellement plusieurs façons de résoudre ce problème. Lequel vous choisissez dépend de combien vous vous souciez de votre programme en regardant bien, par opposition à simplement travailler.
Un. En commençant par le code que vous avez écrit, nous pourrions changer pour:
while (curr_char != EOF)
{
curr_char = getc(original_file);
if(curr_char == EOF) break;
putc(curr_char, second_file);
}
Ici, nous testons explicitement si le caractère est EOF, immédiatement après l'avoir lu, avant de l'écrire. Si c'est EOF, nous sortons de la boucle tôt. Cela marchera, mais c'est moche: il y a deux endroits différents où nous testons EOF, et l'un d'entre eux ne "tire" jamais. (Aussi, comme un commentateur m'a rappelé, il y a le problème que la première fois à travers la boucle, nous testons curr_char
avant que nous ne l'ayons jamais défini.)
Deux. Vous pouvez réorganiser comme ceci:
curr_char = getc(original_file);
while (curr_char != EOF)
{
putc(curr_char, second_file);
curr_char = getc(original_file);
}
Ici, nous lisons un caractère initial, et tant qu'il est EOF pas, nous l'écrire et lire une autre. Cela fonctionnera très bien, mais c'est encore un peu moche, car cette fois il y a deux endroits différents où l'on lit le personnage.
Trois. Vous pouvez réarranger comme ceci:
while ((curr_char = getc(original_file)) != EOF)
{
putc(curr_char, second_file);
}
C'est la façon classique d'écrire une boucle de caractère copie en C. L'appel à getc
et l'affectation à curr_char
sont enterrés à l'intérieur de l'expression de contrôle de la boucle while
. Cela dépend du fait que dans C, une expression d'affectation a une valeur comme n'importe quelle autre expression. C'est-à-dire que la valeur de l'expression a = b
est la valeur que nous venons d'attribuer à a
(c'est-à-dire la valeur de b
). Donc, la valeur de l'expression curr_char = getc(original_file)
est le caractère que nous venons de lire. Donc, quand nous disons while ((curr_char = getc(original_file)) != EOF)
, ce que nous sommes en train de dire est, "Appelez getc
, affectez le résultat à curr_char
, et si ce n'est pas égal à EOF
, faites un autre tour de la boucle."
(Si vous rencontrez toujours des difficultés à voir, je l'ai écrit d'autres explications dans these notes et this writeup.)
Ce code est à la fois bon et mauvais. C'est bien parce que nous avons exactement un endroit où nous lisons des caractères, un endroit où nous testons des personnages et un endroit où nous écrivons des caractères. Mais c'est un peu mauvais parce que, admettons-le, c'est un peu énigmatique au début.Il est difficile de penser à cette affectation-enterré-dans-while
-condition. C'est un code comme celui-ci qui donne à C une réputation d'être plein de gobbledegook obscur. Mais, au moins dans ce cas, il vaut la peine d'apprendre l'idiome, et devenir à l'aise avec elle, parce que les réductions à un seul lire et un test et une écriture vraiment sont vertus. Cela n'a pas tellement d'importance dans un cas trivial comme celui-ci, mais dans de vrais programmes qui sont compliqués pour d'autres raisons, s'il y a une fonctionnalité clé qui se produit à deux endroits différents, il est extrêmement facile d'ignorer ce fait. un changement à l'un d'entre eux, mais oubliez de le faire à l'autre.
(En fait, cela m'est arrivé la semaine dernière au travail.J'essayais de corriger un bug dans le code de quelqu'un d'autre.J'ai finalement compris que lorsque le code a fait X, il a été par inadvertance Y.J'ai trouvé la endroit où il a fait X, et j'ai ajouté un nouveau code pour recréer correctement Y. Mais quand j'ai testé mon correctif, cela n'a pas fonctionné! Il s'est avéré qu'il y avait deux endroits séparés où le code X, et j'ai trouvé et réparé . le mauvais)
Enfin, voici une façon non conventionnelle, mais minimale équivalente d'écrire la boucle:
while (1)
{
curr_char = getc(original_file);
if(curr_char == EOF) break;
putc(curr_char, second_file);
}
C'est un peu comme le numéro 1, mais il supprime la condition redondante dans la boucle while
et la remplace par la constante 1
, qui est "true" en C. Cela fonctionnera très bien aussi, et il partage la vertu d'avoir une lecture, un test, et on écrit. Il finit par faire exactement les mêmes opérations et exactement dans le même ordre que le numéro 3, mais en étant disposé linéairement, il peut être plus facile à suivre.
Le seul problème avec le numéro 4 est qu'il s'agit d'une boucle non conventionnelle "break in the middle". Personnellement, je n'ai pas de problème avec les boucles break-in-the-middle, et je trouve qu'elles apparaissent de temps en temps, mais si j'en écris une et que quelqu'un dit: "Steve, c'est moche, ce n'est pas un idiot ça va embrouiller les gens ", je suis d'accord.
P.S. J'ai remplacé vos appels à fgetc
et fputc
avec les plus classiques getc
et putc
. Je ne sais pas qui vous a dit d'utiliser fgetc
et fputc
, et il y a des circonstances obscures où vous en avez besoin, mais elles sont si rares que, à mon avis, on pourrait aussi bien oublier que les variantes "f" existent, et utilisent toujours getc
et putc
.
Eh bien, c'est assez évident, vous avez stocké l'EOF, arrêtez de le faire. – harold
Vous devriez tester EOF après avoir lu un personnage et avant de l'écrire. Ici, vous lisez un personnage, l'écrivez, et * puis * testez EOF. –
'while ((c = fgetc (fpin))! = EOF) fputc (c, fpout);' – user3386109