« Exercices en langage C/Fonctions » : différence entre les versions

Un livre de Wikilivres.
Contenu supprimé Contenu ajouté
Thierry46 (discussion | contributions)
Ajout Exercice majuscules
Thierry46 (discussion | contributions)
→‎Solution proposée : Simplification malloc -> realloc(NULL, suppresion tabulation.
Ligne 265 : Ligne 265 :


===Solution proposée===
===Solution proposée===
<div style="width:70%">{{Boîte déroulante|titre=Voir la solution|contenu =
<div style="width:80%">{{Boîte déroulante|titre=Voir la solution|contenu =
<source lang="c">
<source lang="c">
/**
/**
* Fonction .. : lire_ligne
* Fonction .. : lire_ligne
* Role ...... : tente de lire une ligne entiere depuis le flux.
* Role ...... : tente de lire une ligne entiere depuis le flux.
* - Le caractere de saut de ligne '\n' final est enleve.
* - Le caractere de saut de ligne '\n' final est enleve.
* - L'appellant doit se charger de la desallocation de la chaine retournee.
* - L'appellant doit se charger de la desallocation de la chaine retournee.
*
*
* Parametres :
* Parametres :
* - pChaine : adresse de retour de la chaine
* - pChaine : adresse de retour de la chaine
* - tailleBufferLecture : taille du buffer de lecture,
* - tailleBufferLecture : taille du buffer de lecture,
* dans la pratique on pourra choisir _POSIX_MAX_INPUT (ref limits.h).
* dans la pratique on pourra choisir _POSIX_MAX_INPUT (ref limits.h).
* - flux : un pointeur sur le descripteur du fichier a lire.
* - flux : un pointeur sur le descripteur du fichier a lire.
*
*
* - Valeur retournee :
* - Valeur retournee :
* - Si OK : EXIT_SUCCESS.
* - Si OK : EXIT_SUCCESS.
* - Si Fin de fichier atteinte sans rencontrer \n : EOF,
* - Si Fin de fichier atteinte sans rencontrer \n : EOF,
* - la chaine retournée contient le debut de la ligne longue.
* - la chaine retournée contient le debut de la ligne longue.
* - Si rien a lire, retour d'un pointeur NULL pour la chaine.
* - Si rien a lire, retour d'un pointeur NULL pour la chaine.
* - En cas de probleme : Le code d'erreur systeme utilisable par perror.
* - En cas de probleme : Le code d'erreur systeme utilisable
* et retour d'un pointeur NULL pour la chaine.
* par perror et retour d'un pointeur NULL pour la chaine.
*
*
* Auteur ...... : Thierry46
* Auteur ...... : Thierry46
* Version ..... : 1.0 du 30/1/2008
* Version ..... : 1.1 du 4/2/2008
* Licence ..... : GNU GPL.
* Licence ..... : GNU GPL.
lire_ligne : Lecture d'une ligne longue dans un fichier texte
lire_ligne : Lecture d'une ligne longue dans un fichier texte
Copyright (C) 2008 Thierry46
Copyright (C) 2008 Thierry46

This program is free software: you can redistribute it and/or modify
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
(at your option) any later version.

This program is distributed in the hope that it will be useful,
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <http://www.gnu.org/licenses/>.
Ligne 310 : Ligne 310 :
*
*
* Remarques :
* Remarques :
* Beaucoup de commentaires sont présents pour un usage didactique.
* - Beaucoup de commentaires sont présents pour un usage didactique.
* Ce programme utilise une syntaxe specifique C99.
* - Ce programme utilise une syntaxe specifique C99.
* Ce programme a ete controle avec l'outil de verification statique
* - Ce programme a ete controle avec l'outil de verification statique
* Splint v3.1.2 du 19 Jan 2008 : <http://www.splint.org/>
* - Splint v3.1.2 du 19 Jan 2008 : <http://www.splint.org/>
*/
*/

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
Ligne 323 : Ligne 323 :
#include <errno.h>
#include <errno.h>
#include "lire_ligne.h"
#include "lire_ligne.h"

/*@null@*/ char *lire_ligne(size_t tailleBufferLecture,
/*@null@*/ char *lire_ligne(size_t tailleBufferLecture,
FILE * restrict flux, int *pCodeRetour)
FILE * restrict flux, int *pCodeRetour)
{
{
// Declarations
// Declarations
char *chaineRetour = NULL;
char *chaineRetour = NULL;
bool litEncore = true;
bool litEncore = true;
bool rienLu = true;
bool rienLu = true;
int codeRetour = EXIT_SUCCESS;
int codeRetour = EXIT_SUCCESS;

// Controle rapide des parametres.
// Controle rapide des parametres.
// Si quelque chose ne va pas, cela ne sert à rien d'aller plus loin.
// Si quelque chose ne va pas, arret.
assert(tailleBufferLecture > 0);
assert(tailleBufferLecture > 0);
assert(flux != NULL);
assert(flux != NULL);

// On reinitialise errno
// On reinitialise errno
errno = 0;
errno = 0;

// Boucle de lecture d'une ligne eventuellement longue
// Boucle de lecture d'une ligne eventuellement longue
do
do
{
{
size_t positionEcriture;
size_t positionEcriture;
char *nouvelleChaine;
litEncore = false;
litEncore = false;
// Si 1ere lecture : demande d'une nouvelle zone memoire
// Demande d'une nouvelle zone memoire
if (chaineRetour == NULL)
positionEcriture =
{
(chaineRetour == NULL) ? 0 : strlen(chaineRetour);
positionEcriture = 0;
nouvelleChaine = realloc(chaineRetour,
chaineRetour = malloc(tailleBufferLecture);
positionEcriture + tailleBufferLecture);
if (chaineRetour == NULL)
if (nouvelleChaine == NULL) // Si probleme d'allocation
{
{
codeRetour = errno;
codeRetour = errno;
}
free(chaineRetour);
}
chaineRetour = NULL;
else // Pour les lectures suivantes : extension de la zone memoire
}
{
else // Si le systeme a accorde la memoire
char *nouvelleChaine;
{
positionEcriture = strlen(chaineRetour);
chaineRetour = nouvelleChaine;
nouvelleChaine = realloc(chaineRetour, positionEcriture + tailleBufferLecture);
if (fgets(chaineRetour+positionEcriture,
if (nouvelleChaine == NULL)
(int)tailleBufferLecture, flux)
{
!= NULL)
codeRetour = errno;
{
free(chaineRetour);
// Recherche si un \n a ete lu en fin de chaine.
chaineRetour = NULL;
char *positionNewLine = strrchr(chaineRetour, '\n');
}
rienLu = false;
else
if (positionNewLine != NULL)
{
{
chaineRetour = nouvelleChaine;
// Suppression du caractere de fin de ligne \n,
}
*positionNewLine = '\0';
} // if (chaineRetour == NULL)
}

else // fgets n'a pas pu lire la ligne complete.
// Si le systeme a accorde la memoire, lecture d'une chaine par fgets
{
if (chaineRetour != NULL)
litEncore = true;
{
}
if (fgets(chaineRetour+positionEcriture, (int)tailleBufferLecture, flux)
} else if (ferror(flux) != 0)
!= NULL)
{
{
codeRetour = errno;
// Recherche si un \n a ete lu en fin de chaine.
char *positionNewLine = strrchr(chaineRetour, '\n');
free(chaineRetour);
chaineRetour = NULL;
rienLu = false;
if (positionNewLine != NULL)
} else if (feof(flux) != 0)
{
{
codeRetour = EOF;
// Suppression du caractere de fin de ligne \n,
if (rienLu)
*positionNewLine = '\0';
{
}
free(chaineRetour);
else // fgets n'a pas pu lire la ligne complete.
chaineRetour = NULL;
{
}
litEncore = true;
}
}
} // else if (nouvelleChaine == NULL)
}
} while (litEncore);
else if (ferror(flux) != 0)
{
// Retour des resultats.
codeRetour = errno;
*pCodeRetour = codeRetour;
free(chaineRetour);
return chaineRetour;
chaineRetour = NULL;
} else if (feof(flux) != 0)
{
codeRetour = EOF;
if (rienLu)
{
free(chaineRetour);
chaineRetour = NULL;
}
}
} // if (chaineRetour != NULL)
} while (litEncore);
// Retour des resultats.
*pCodeRetour = codeRetour;
return chaineRetour;
} // char *lire_ligne(...
} // char *lire_ligne(...
</source>
</source>

Version du 4 février 2008 à 23:08

Ces exercices concernent l'utilisation des fonctions de la bibliothèque standard du langage C.

Filtre qui passe le texte en majuscule

Problème à résoudre

Ecrivez un programme majuscule.c qui lit des données sur le flux stdin et écrits sur stdout après avoir transformé les caractères lus en majuscules. Vous utiliserez les fonctions getchar, putchar (stdio.h) et toupper (ctypes.h).

Vous testerez votre programme en lui faisant convertir son propre fichier source majuscule.c.

majuscule.exe < majuscule.c

Solution proposée


Lire une ligne longue avec fgets

Problème à résoudre

La fonction fgets de la bibliothèque standard du langage C permet de lire une chaine de caractère de longueur limitée dans un flux.

Vous allez compléter une fonction lire_ligne répondant au spécifications suivantes :

  • Retour d'une ligne lue dans un flux texte passé en paramètre.
  • Vous éliminerez les caractères de saut de ligne lus.
  • La longueur des lignes lues n'est pas limitée.
  • Contrôle des paramètres et retour des codes d'erreurs systèmes, détection de la fin du fichier.
  • Vous utiliserez au maximum les fonctions de la bibliothèque standard du langage C : allocation mémoire, chaines de caractères...
  • Son prototype est donné par lire_ligne.h.
  • Vous utiliserez le programme de main_lire_ligne.c pour lire_ligne.
  • Vous devrez traiter le fichier test_lire_ligne.txt fourni.
  • Les instructions de compilation et d'édition de lien sont dans les commentaires des fichiers fournis.

Éléments fournis

Solution proposée

Remarques sur l'exercice

  • Le test des paramètres dans la solution est expéditif.
  • Pour obtenir des programmes robustes, le langage C oblige à une gestion pénible des erreurs. Avec le langage Java par exemple, les mécanismes d'exception facilitent la tâche du programmeurs.
  • L'utilisation de l'allocation dynamique de mémoire est risquée : fuite mémoire. Avec le langage Java par exemple, le ramasse miettes (Garbage collector) facilite la tâche du programmeurs.
  • En Java des classes comme String et StringBuffer prennent en charge les chaines de caractères longues.