2016-05-04 1 views
-3

Lorsque je copie le contenu d'un fichier dans un autre en C à la fin du fichier de sortie, j'ai ce caractère ÿ. Je comprends grâce à ce forum que c'est l'indicateur EOF mais je ne comprends pas quoi faire pour s'en débarrasser dans le fichier de sortie.Résoudre ÿ la fin du fichier en C

Ceci est mon code:

second_file = fopen(argv[2], "w+"); 
while (curr_char != EOF) 
{ 
    curr_char = fgetc(original_file); 
    fputc(curr_char, second_file); 
} 
printf("Your file has been successfully copy\n"); 
fclose(second_file); 
fclose(original_file); 
+5

Eh bien, c'est assez évident, vous avez stocké l'EOF, arrêtez de le faire. – harold

+2

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. –

+6

'while ((c = fgetc (fpin))! = EOF) fputc (c, fpout);' – user3386109

Répondre

4

Pour chaque personnage que vous lisez, vous avez deux choses à faire:

  1. Vérifiez si c'est EOF.
  2. 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.

+0

Votre méthode n ° 1 est * dangereuse * car elle vérifie 'curr_char' avant d'être initialisée! – usr2564301

+0

Merci beaucoup, mais pouvez-vous expliquer dans l'exemple 3 pourquoi si je mets l'appel de getc et l'assignation à curr_char dans l'expression de contrôle de la boucle while c'est comme si je faisais (curr_char == EOF); –

+0

@RonyCohen Le résultat d'une affectation est la valeur qui lui est affectée. Le résultat de l'affectation dans ce cas est 'getc (original_file)'. Ensuite, vous comparez cela à EOF. –