Adloun

Quatre façons de perdre ce qu'on a écrit

Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 8 — Mémoire, fichiers et entrées-sorties

Énoncé

Chacun de ces fragments perd des données ou en écrit moins qu'on ne croit. Dire ce qui est perdu, et pourquoi.


/* (a) */  FILE* f = fopen("sortie.txt", "w");
           for (int i = 0; i < 1000; i = i + 1) { fprintf(f, "ligne %d\n", i); }
           _exit(0);

/* (b) */  FILE* g = fopen("poeme.txt", "r");
           fprintf(g, "je m'ajoute\n");

/* (c) */  FILE* h = fopen("absent.txt", "r");
           fscanf(h, "%d", &x);

/* (d) */  FILE* k = fopen("journal.txt", "w");
           fprintf(k, "important\n");
           fclose(k);
           fprintf(k, "encore plus important\n");

Corrigé

(a) Les derniers octets, mesurés. Le fichier complet fait octets ; celui que produit ce fragment en fait exactement , soit ko — une tranche de tampon, pas un octet de plus. Les premières lignes sont écrites, la est coupée en son milieu — le fichier se termine sur les deux caractères li — et les dernières n'existent pas du tout. La cause : fprintf n'écrit pas sur le disque, il remplit un tampon, que fclose viderait. _exit court-circuite tout cela.

Remarquer que la faute est invisible en développement : avec dix lignes au lieu de mille, rien n'est perdu parce que le tampon n'a jamais été vidé et qu'un return depuis main le viderait de toute façon. Le défaut n'apparaît qu'au-delà de ko, et seulement si l'on quitte brutalement.

(b) Rien n'est écrit, et personne ne le sait. Le flux est ouvert en mode &quot;r&quot;. Mesure : fprintf rend et positionne ferror(g) à ; le fichier fait toujours octets. Or presque personne ne regarde ce que rend fprintf. C'est la faute la plus silencieuse des quatre.

(c) Une violation de segment. fopen rend NULL — mesuré, avec le message No such file or directory — et fscanf le déréférence aussitôt. Ici, paradoxalement, tout va bien : le programme meurt sur-le-champ, et le défaut est trouvé en une minute.

(d) Comportement indéfini. Après fclose, k ne désigne plus un flux : c'est le use after free du chapitre chap:langage-c, transposé aux fichiers. Selon les jours, la ligne est ignorée, écrite ailleurs, ou le programme plante. On ne mesure pas ce genre de chose : on ne l'écrit pas.

Ce que les quatre ont en commun. Aucune n'est détectée à la compilation, et trois sur quatre laissent le programme se terminer avec le code . La discipline qui les élimine tient en trois lignes, et c'est celle du cours :


FILE* f = fopen(chemin, mode);
if (f == NULL) { /* on renonce ICI, avant toute autre operation */ }
/* ... exactement un fclose, sur chaque chemin de sortie ... */

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.