Cours gratuits » Cours informatique » Cours programmation » Cours langage C » Cours C 5 entrees sorties et fichiers ressource avec exemples

Cours C 5 entrees sorties et fichiers ressource avec exemples


Télécharger



★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Cours C 5 entrees sorties et fichiers ressource avec exemples

Retour de printf

  • retour négatif en cas d'erreur
  • très rare: sortie redirigée vers un fichier et plus de place sur le disque
  • le système gère les cas où:

– le support amovible est absent

– le programme n'a pas les droits pour écrire sur le fichier de redirection

Affichage des entiers

stify;">
  • %d : entier signé
  • %u : entier non signé
  • %o : entier non signé en octal
  • %x %X : entier non signé en hexadécimal
  • Affichage des réels

    • %f : standard, 6 décimales
    • %g : standard, sans les zéros finaux
    • %e %E : notation exponentielle

    Formats spéciaux

    • %p : affichage en hexadécimal des adresses mémoires
    • %n : stocke le nombre de caractères déjà Ecrits

    Le gabarit

    • entier après le % = nombre minimum de caractères à utiliser
    • printf complète avec des espaces si nécessaire, ou des zéros si %0 avant un Nombre

    Précision

    • %.3f : 3 décimales
    • règle d'arrondi
    • compatible avec un gabarit

    Gabarit et précision variables

    • si on ne les connaît pas à la compilation: * au lieu d'un entier + variable en argument de printf

    Signes des nombres

    • %+d : force l'affichage du signe
    • % d : met un espace si le signe est un + sprintf
    • le résultat est mis dans une chaîne de caractères supposée assez longue
    • attention aux débordements

    Getchar

    • int getchar();
    • équivalent à scanf("%c",&c);
    • renvoie le caractère lu ou EOF en cas d'erreur
    • plus lisible
    • plus rapide, car pas de format à analyser

    Qu'est-ce qu'un fichier ?

    • espace de stockage de données
    • opérations permises:

    – lire, écrire, tronquer

    • il n'est pas prévu de mécanisme pour enlever un morceau au milieu d'un fichier
    • tous les fichiers ne sont pas en random Access (ex: /dev/mouse)

    Les primitives

    • primitives systèmes:

    int open(const char* pathname,int flags,mode_t mode);

    int close(int fd);

    ssize_t read(int fd,void* buf,size_t count);

    ssize_t write(int fd,const void* buf,size_t count);

    • peu pratiques car ne manipulent que des octets
    • printf("%f",r); ⇔ truc très méchant si demandé à l'examen

    Ouvrir un fichier

    • options de fopen:

    "r" : lecture seule

    "w" : écriture écriture seule (fichier créé si nécessaire, écrasé si existant)

    "a" : ajout en fin (fichier créé si nécessaire)

    • par défaut, opérations en mode texte

    – différences pour les retours à la ligne suivants les systèmes

    • toujours tester la valeur de retour
    • opérations en mode binaire: "rb" "wb" "ab"
    • opérations en mode lecture et écriture: "r+" "w+" "a+"
    • combinaisons possibles: "rb+" "r+b" "wb+" "w+b" "ab+" "a+b"

    Ouvrir un fichier

    • si le nom du fichier est relatif, il l'est par rapport au répertoire courant
    • en cas de création, les droits dépendent du umask (-rw-r--r-- par défaut)

    Fermer un fichier

    • fclose(f);
    • f doit être non NULL
    • f doit représenter une adresse valide
    • f ne doit pas avoir déjà été fermé
    • tout fichier ouvert doit être fermé

    Cours C 5 Entrees sorties et Fichiers

    Les entrées-sorties : E/O

    Entrées/Sorties : Opérations d’échanges d’informations dans un système informatique.

    Les systèmes d’exploitations ont des mécanismes/fonctions d’entrées sorties, les langages de programmation aussi. Dans le langage C, la plupart de ces fonctionnalités se situent dans la librairie <stdio.h>. (stdio : standard input output).

    Sans entrées/sorties, il est impossible de produire des programmes évolués ayant de grands impacts sur l’environnement, le système et la mémoire.

    Les flux d’informations

    Toutes interactions avec l’environnement et la mémoire (et leurs modifications) nécessite de récupérer ou de constituer un flux d’informations.

    Flux classiques:

    I Texte tapéau clavier (entrée)

    I Mouvement de la souris et clic (entrée)

    I Fichiers sur le disque dur (entrée/sortie)

    I Position de la souris sur l’écran (entrée/sortie)

    I Texte affichésur l’écran (sortie)

    I Réseau (entrée/sortie)

    I Webcam (entrée)

    I ...

    Les fichiers dans le langage C

    Il est possible de manipuler (créer / lire / écrire / détruire) des fichiers du disque dur via des fonctions d’Entrées/Sorties de la librairie <stdio.h>.

    Dans le langage C, les fichiers sont manipulables via un pointeur sur une structure FILE.

    Procédéde manipulation de fichier:

    4 Ouverture du fichier, constitution de l’objet (FILE *) et placement du pointeur.

    4 Fonctions d’Entrées/Sorties du langage C pour modifier des caractères sur le pointeur et déplacer ce pointeur dans le fichier ouvert.

    4 Fermeture du fichier.

    Le dernier caractère d’un fichier ouvert est EOF pour (End Of File).

     Ouverture d’un fichier: fopen

    Avant toute opération sur un fichier, il est nécessaire d’obtenir un pointeur de type FILE *.

    FILE *fopen(const char *path, const char *mode);

    -path contient l’adresse du fichier à ouvrir, -mode précise le mode d’ouverture.

    4 "r": mode lecture, pointeur au début

    4 "w": mode écriture, pointeur au début, création du fichier si non existant, effacement sinon. (Chevron UNIR >)

    4 "r+": mode lecture-écriture, pointeur au début

    4 "w+": mode lecture-écriture, pointeur au début, création du fichier si non existant, effacement sinon.

    4 "a": mode écriture, pointeur à la fin, création du fichier si non existant. (Chevron UNIR >>)

    4 "a+": mode lecture-écriture, pointeur à la fin, création du fichier si non existant.

     Fermeture d’un fichier: fclose

    Une fois les modifications terminées, il convient de fermer les fichiers ouverts.

    int fclose(FILE *stream);

    retourne 0 en cas de succès et EOF sinon.

    Réouverture d’un fichier: freopen

    Ré-ouvre un fichier en fermant l’instance précédemment ouverte.

    FILE *freopen(const char *path, const char *mode, FILE *stream);

    A l’origine, cette fonction est conçue pour permettre les redirections. On l’utilisera rarement en pratique mais son recours est parfois contraint.

    Les flux standards

    Dans le langage C et pour UNIR (programméen C), il existe des flux standards qui se comportent comme des fichiers pour lesquels l’utilisateur n’a pas à se soucier de l’ouverture et fermeture.

    4 stdin: (standard input) est l’entrée standard. Tout caractère tapéau clavier durant l’exécution d’un programme se retrouve dans ce flux.

    4 stdout: (standard output) est la sortie standard. Tout caractère écrit dans ce flux sera affichédans la console lors de l’exécution d’un programme. ATTENTION A LA BUFFERISATION.

    4 stderr: (standard error) est la sortie d’erreur standard.

    Les fonctions d’Entrées/Sorties du langage C opérant sur les fichiers et flux standards sont très liées. (printf - fprintf, scanf - fscanf, ...).

     Fonctions d’Entrées/Sorties du langage C

    Les fonctions d’entrées/sorties servent à écrire et récupérer des données dans les fichiers ouverts et les flux standards.

    Les fonctions primitives systèmes sont très difficiles à utiliser (open, close, read, write). Notamment, elles ne font que de la lecture octet par octet (8 bits). On utilisera les fonctions E/S formatées de <stdio.h>.

    scanf : lecture formatée sur l’entrée standard

    int scanf(const char *format, ...);

    On remplace les ... par une liste d’adresses de conteneurs mémoires adaptés. Si on a une variable int i, l’adresse &i de i est un conteneur mémoire adaptéà la lecture d’un entier.

    Type Lettre

    int %d

    long %ld

    float - double %f - %lf

    char %c

    string (char*) %s

    1 char nom[ 5 0 ] ;

    2 int age;

    3 p r i n t f ( ” Saisissez votre nom, un espace, puis votre age” ) ;

    4 scanf ( ”%s %d” , nom, &age ) ;

    scanf retourne le nombre de variables affectées par la saisie, cela permet de vérifier le bon déroulement de la saisie.

     printf : écriture formatée sur la sortie standard

    int printf(const char *format, ...);

    On remplace les ... par une liste de variables adaptées aux différents types apparaissant dans le format. Encore une fois, il faut respectél’ordre de lecture de gauche à droite.

    Le texte formatéavec les bonnes substitutions est ensuite affichéà l’écran (modulo la bufferisation).

    1 float t =37.12;

    3 p r i n t f ( ”La temperature de %s est %f ” , ” Martin ” , f ) ;

    En cas de succès, printf retourne le nombre de caractères écrits sur la sortie standard (sans compter le caractère de fin de chaîne).

     fscanf : lecture formatée sur un flux

    int fscanf(FILE *stream, const char *format, ...);

    On remplace les ... par une liste d’adresses de conteneurs mémoires adaptés. On récupère ainsi des données dans le flux qui se place en valeur des adresses de variables données.

    1 char nom[ 8 0 ] ;

    2 int age;

    3 FILE ∗ fichier ent ree ;

    5 fichier entree = fopen ( ”nom age . t x t ” , ” r ” ) ;

    6 fscanf (fichier entree , ”%s %d” , nom, &f ) ;

    fscanf retourne le nombre de variables affectées par la saisie, cela permet de vérifier le bon déroulement de la saisie.

    Les flux standards se comportent comme des fichiers ouvert, ainsi : scanf(format, ...) est équivalent à fscanf(stdin, format, ...).

     fprintf : écriture formatée sur un flux

    int fprintf(FILE *stream, const char *format, ...);

    On remplace les ... par une liste de variables adaptées aux différents types apparaissant dans le format. Encore une fois, il faut respectél’ordre de lecture de gauche à droite.

    Le texte formatéavec les bonnes substitutions est ensuite écrit sur le flux.

    1 int age=12;

    2 FILE ∗ fichier sortie;

    4 fichier sortie = fopen ( ”nom age . t x t ” , ”w” ) ;

    5 fscanf (fichier sortie , ”%s %d” , ” Martin ” , age ) ;

    En cas de succès, fprintf retourne le nombre de caractères écrits sur le flux (sans compter le caractère de fin de chaîne).

    printf(format, ...) est équivalent à fprintf(stdout, format, ...).

     Il existe de nombreuse autre fonctions d’Entrées/Sorties.

    Lorsque l’on ne connaît pas/plus une fonction foo en langage C, LE SEUL RÉFLEXE: on tape man 3 foo dans un terminal.

    Autre fonctions: fgetc, fgets, getc, getchar, gets, ungetc, fputc, fputs, putc, putchar, puts, ...

    man 3 fgetc

    GETS(3) Linux Programmer’s Manual GETS(3)

    NAME

    fgetc, fgets, getc, getchar, gets, ungetc - input of characters and strings

    SYNOPSIS

    #include <stdio.h>

    int fgetc(FILE *stream);

     Soyez astucieux et perspicaces

    Les noms de fonctions n’ont pas étéchoisis au hasard.

    4 print-f : écrire, format

    4 f-scan-f : flux, analyser, format

    4 f-get-c : flux, obtenir, caractère

    4 put-char : placer, caractère

    4 f-put-s : flux, placer, chaîne de caractères

    4 Lorsque le nom ne commence pas par un f, la fonction affecte les flux standards, sinon elle aura un flux parmi ses arguments.

    4 En fin de nom, c et char désigne des caractères, s désigne une chaîne de caractères, f que la fonction peut prendre des écritures formatées (types différents).

    Des paramètres dans la fonction main

    Voici le prototype standard d’un main acceptant des arguments: int main(int argc, char* argv[])

    I argc est un entier, il donne le nombre d’arguments passés à l’exécutable (en comptant le nom de l’exécutable comme premier argument).

    I argv est un tableau de chaînes de caractères.

    I argv[0]: le nom de l’exécutable (dépend du nom donnéà la compilation).

    I argv[1]: le nom du premier argument.

    I argv[2]: le nom du second argument.

    I ...

    Similaritéavec le langage du bash:

    $# se comporte comme argc

    $0 se comporte comme argv[0]

    $1 se comporte comme argv[1]

    ... (et tout est, a priori, chaînes de caractères)

    Pour le programme suivant : test.c

    1 #include <stdio.h>

    3 int main ( int argc , char* argv [ ] ) j

    4 int i;

    6 for ( i =0 ; i <argc ; i ++)j

    7 p r i n t f ( ”%sin” , argv [ i ] ) ;

    9 return 0;

    nicolas@lancelot:˜/test$ gcc -o test test.c -Wall -ansi nicolas@lancelot:˜/test$ ./test fich1.txt fich2.txt 23 ./test

    fich1.txt

    fich2.txt

    Les arguments des exécutables passés par la console sont des chaînes de caractères. Toutefois, le langage C possède des fonctions de conversions entre ces types.

    int atoi(const char *nptr);

    retourne un entier à partir d’une chaîne de caractères.

    1 #include <stdio.h>

    2 #include <stdlib . h>

    4 int main ( void ) {

    5 char∗ nombre=” 12543 ” ;

    7 p r i n t f ( ”%d\n” , atoi (nombre ) ) ;

    8 return 0;

    9 }

    nicolas@lancelot:˜/test$ gcc -o test test.c -Wall -ansi nicolas@lancelot:˜/test$ ./test 12543

    Comment alors faire un exécutable en console qui attend des entiers en arguments et retourne la somme de ces derniers.

    1 #include <stdio.h>

    2 #include <stdlib.h>

    4 int main(int argc, char∗ argv[]){

     5 int i ,somme=0;

    7 for ( i =1 ; i<argc ; i ++){

     8 somme += atoi ( argv [ i ] ) ;

     9 )

     10 p r i n t f ( ”%d\n” , somme);

     11 return 0;

    12 )

    nicolas@lancelot:˜/test$ gcc -o test test.c -Wall -ansi

    nicolas@lancelot:˜/test$ ./test

    nicolas@lancelot:˜/test$ ./test 1 2

    nicolas@lancelot:˜/test$ ./test 1 2 5 5

    nicolas@lancelot:˜/test$ ./test foo bla 0

    L’œuf ou la poule, UNIX ou le langage C ?

    Le système d’exploitation UNIX et le langage C ont étéconçu de manière relativement conjointe. Notamment, les flux standards (stdin, stdout, stderr) SONT LES MÊMES!

    Un exécutable compiléà partir de source écrite en C bien programmépeut s’enchaîner dans des pipes UNIX à volonté.

    conséquences:

    Toutes les données récupérées sur l’entrée standard (scanf, getchar, ...) peuvent en fait être envoyéau programme via un chevron entrant < d’UNIX ou un pipe |.

     1 #include <stdio.h>

    3 int main(void){

     4 char nom[ 5 0 ] ;

     5 int age;

    7 p r i n t f ( ” Donner  votre nom et votre age !\ n” ) ;

     8 scanf ( ”%s %d” , nom, &age ) ;

     9 p r i n t f ( ”Ok,  vous etes %s et vous avez%d  ans\n” , nom, age ) ;

     10 return 0;

     11 }

    nicolas@lancelot:˜/test$ gcc -o test test.c -Wall -ansi

    nicolas@lancelot:˜/test$ echo "Dupont 45"

    Dupont 45

    nicolas@lancelot:˜/test$ echo "Dupont 45" | ./test

    Donner votre nom et votre age!

    Ok, vous etes Dupont et vous avez 45 ans

    nicolas@lancelot:˜/test$ ./test < nom_age.txt

    Donner votre nom et votre age!

    Ok, vous etes Durant et vous avez 78 ans

     1 #include <stdio.h>

    3 int main(void){

     4 int c=getchar();

    6 \* Recopiage de l entree standard sur la sortie standard *\

     7 while ( c != EOF) {

     8 putchar(c);

     9 c = getchar();

     10 }

     11 return 0;

    12 }

    nicolas@lancelot:˜/test$ gcc -o test test.c -Wall -ansi

    nicolas@lancelot:˜/test$ echo "pouet fou bla" > fichier

    nicolas@lancelot:˜/test$ echo "une seconde ligne" >> fichier

    nicolas@lancelot:˜/test$ ./test < fichier

    pouet fou bla

    une seconde ligne

    nicolas@lancelot:˜/test$ ./test < fichier | ./test

    pouet fou bla

    une seconde ligne

     Bufferisation

    La sortie standard est bufferisée: Les fonctions d’Entrées/Sortie de

    <stdio.h> n’envoient pas directement les éléments sur l’écran.

    UNIX incite à l’enchaînement de commandes ou exécutables via des pipes. Mais la communication entre les processus a un coût. Surtout si l’on perd son temps à communiquer sans arrêt des messages tout petits.

    printf écrit sur le buffer de la sortie standard (de taille 8192 Octets par défaut) et une fois le buffer plein (ou un retour à ligne, ou un flush, ou ...), on sollicite le processus d’affichage à l’écran.

    Note: La sortie d’erreur n’est pas bufferiséet affiche les caractères dès l’ajout dans le flux.

    1 #include <stdio.h>

    3 int main(void){

    4 char∗ nom=” Jean ” ;

    6 p r i n t f ( ”Ou est l’ erreur de segmentation ” ) ;

    7 nom[34] = 123;

    8 return 0;

    9 }

    Ce programme donne le comportement suivant

    nicolas@lancelot:˜/test$ gcc -o test test.c -Wall -ansi nicolas@lancelot:˜/test$ ./test Erreur de segmentation (core dumped)

    Où est passé le printf ? l’erreur de segmentation se trouve avant ?

    Solution 1:

    1 #include <stdio.h>

    3 int main(void){

    4 char* nom=” Jean ” ;

    6 / * Un saut de ligne force la vidange du buffer * /

    7 p r i n t f ( ”Ou est l’ erreur de segmentation\n” ) ;

    8 nom[34] = 123;

    9 return 0;

    10 1

    Solution 2:

    1 #include <stdio.h>

    3 int main(void){

    4 char* nom=” Jean ” ;

    5

    6 / * Drapeau de debogage sur la sortie d ’ erreur * /

    7 fprintf (stderr , ”Ou est l ’ erreur de segmentation ” ) ;

    8 nom[34] = 123;

    9 return 0;

    Les chaînes de caractères

    En langage C, on fait la distinction entre un tableau de caractères et une chaîne de caractères : une chaîne de caractères est un tableau de caractères dont la fin est indiquée par un caractère particulier ‘\0’.

    1. Déclaration et initialisation d’une chaîne de caractères

    Une chaîne de caractères peut être allouée de manière statique1 comme nous l’avons vu avec les tableaux :

    char ch[TAILLE]

    où TAILLE est la taille maximale de la chaîne de caractères (y compris le caractère ‘\0’).

    L’initialisation d’une chaîne de caractères peut se faire au moment de sa déclaration de deux façons différentes : soit comme une constante chaîne soit par énumération des caractères.

    Exemple :

    char ch[11] = “bonjour“ ;

    char ch[11] = {‘b’, ‘o’, ‘n’, ‘j’, ‘o’, ‘u’, ‘r’, ‘\0’} ;

    Ces deux déclarations sont équivalentes. Pour la seconde, il est important de noter qu’il faut ajouter le caractère ‘\0’ à la fin alors qu’il est ajouté automatiquement dans la première déclaration. Le résultat de cette initialisation est le suivant :

    b o n j o u r \0

    0 1 2 3 4 5 6 7 8 9 10

    1. Modification du contenu d’une chaîne de caractères

    Une chaîne de caractères peut être modifiée caractères par caractères (comme les cellules d’un tableau).

    Exemple : Transformer la chaîne « bonjour » en « bonsoir ».

    ch[3] = ‘s’;

    ch[5] = ‘i’;

    1. Manipulation de chaînes de caractères

    La bibliothèque string.h contient un ensemble de fonctions permettant de manipuler des chaînes de caractères :

     la fonction strlen() qui renvoie la longueur d’une chaîne de caractères ;

     la fonction strcpy() qui permet de copier une chaîne de caractères dans une autre ;

     la fonction strstr() qui permet de chercher la première occurrence d’un caractère dans une chaîne

     …

    Exercice

    1. Ecrire une fonction compterCaractere() qui compte le nombre de caractères d’une chaîne de caractères. Cette fonction prend en entrée un mot et retourne en sortie le nombre de lettres (évidemment sans compter le caractère ‘\0’).
    2. Ecrire une fonction affichagerEnHexadecimal() qui affiche à l’écran le mot en utilisant la valeur hexadécimale de chacune des lettres. Cette fonction prend en entrée un mot.
    3. Ecrire une fonction affichagerEnDecimal() qui affiche à l’écran le mot en utilisant la valeur décimale de chacune des lettres. Cette fonction prend en entrée un mot.
    4. Ecrire une fonction mettreEnMajuscule() qui transforme les caractères en minuscule en caractères en majuscule. Les autres caractères restent inchangés. Cette fonction prend en entrée une chaîne de caractères en minuscule et retourne une chaîne en majuscule.
    5. Ecrire une fonction mettreEnMinuscule() qui transforme les caractères en majuscule en caractères en minuscule. Les autres caractères restent inchangés. Cette fonction prend en entrée une chaîne de caractères en majuscule et retourne une chaîne en minuscule.
    6. Ecrire une fonction transformerMinMaj() qui change la casse des caractères. Les caractères en minuscule passent en majuscule et inversement. Cette fonction prend en paramètre une chaîne de caractères et retourne la chaîne de caractères modifiée.
    7. Ecrire une fonction retournerMot() qui renvoie un mot écrit à l’envers (exemple : oiseau\0 devient uaesio\0). Cette fonction prend en entrée une chaîne de caractères et retourne la chaîne de caractères modifiée.
    8. Ecrire une fonction rechercherCaractereG() qui renvoie la première occurrence d’un caractère dans une chaîne de caractères en partant de la gauche. Cette fonction prend en entrée la chaîne de caractères ainsi que le caractère recherché. Elle retourne la position dans la chaîne si le caractère est présent, -1 si le caractère n’a pas été trouvé.
    9. Ecrire une fonction rechercherCaractereD() qui renvoie la première occurrence d’un caractère dans une chaîne de caractères en partant de la droite. Cette fonction prend en entrée la chaîne de caractères ainsi que le caractère recherché. Elle retourne la position dans la chaîne si le caractère est présent, -1 si le caractère n’a pas été trouvé.
    10. Ecrire une fonction estPalindrome() qui détermine si le mot donné en argument est un palindrome. Cette fonction retourne la valeur 0 si c’est le cas, -1 sinon.
    11. Ecrire une fonction comparerChaine() qui permet d’effectuer une comparaison de deux chaînes. Elle prend en paramètre d’entrée deux chaînes de caractères et elle retourne :

     la valeur 0 en cas d’égalité : toto = toto ;

     une valeur positive si la première chaîne de caractères est supérieure alphabétiquement à la seconde : titi > toto ;

     une valeur négative si la première chaîne de caractères est inférieure alphabétiquement à la seconde : toto < titi.


    632