Cours C 5 entrees sorties et fichiers ressource avec exemples


Télécharger Cours C 5 entrees sorties et fichiers ressource avec exemples

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

Télécharger aussi :


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

  • %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;

[email protected]:˜/test$ gcc -o test test.c -Wall -ansi [email protected]:˜/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 }

[email protected]:˜/test$ gcc -o test test.c -Wall -ansi [email protected]:˜/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 )

[email protected]:˜/test$ gcc -o test test.c -Wall -ansi

[email protected]:˜/test$ ./test

[email protected]:˜/test$ ./test 1 2

[email protected]:˜/test$ ./test 1 2 5 5

[email protected]:˜/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 }

[email protected]:˜/test$ gcc -o test test.c -Wall -ansi

[email protected]:˜/test$ echo "Dupont 45"

Dupont 45

[email protected]:˜/test$ echo "Dupont 45" | ./test



Donner votre nom et votre age!

Ok, vous etes Dupont et vous avez 45 ans

[email protected]:˜/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 }

[email protected]:˜/test$ gcc -o test test.c -Wall -ansi

[email protected]:˜/test$ echo "pouet fou bla" > fichier

[email protected]:˜/test$ echo "une seconde ligne" >> fichier

[email protected]:˜/test$ ./test < fichier

pouet fou bla

une seconde ligne

[email protected]:˜/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

[email protected]:˜/test$ gcc -o test test.c -Wall -ansi [email protected]:˜/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.



1019