IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Exercice : Sauvegarde de chaîne


Sujet :

C

  1. #1
    Nouveau Candidat au Club
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2015
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 29
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2015
    Messages : 1
    Points : 1
    Points
    1
    Par défaut Exercice : Sauvegarde de chaîne
    Bonjour tout le monde,

    J'ai vraiment besoin de votre aide!!!

    Je dois faire un programme qui réponds à cette consigne

    Chaque chaine doit être stockée dans une zone de mémoire allouée exprès pour la chaine.
    Si la chaine est de longueur n, la zone allouée sera de longueur n+1 et pas plus. On ne tolère plus le gaspillage de mémoire.

    Améliorez votre programme pour permettre la saisie d'un nombre illimité de chaine. Lorsque l'utilisateur aura saisi la dernière, il devra frapper ctrl-d, vous pouvez utiliser la fonction feof (????? ) pour sortir de la boucle de saisie. Le tableau des adresses des chaines saisies sera ralloué par tranche de 10 en utilisant la fonction realloc.

    Voilà c'est la deuxième question de mon exercice.... La première je l'ai faites et elle fonctionne, il fallait que la longueur de la chaine n'excède pas 127 caractères (j'ai choisi de mettre 7 caractères ). Si l'utilisateur essaie de saisir une chaine plus longue, la chaine sera tronquee. Il fallait utiliser la fonction fgets en mettant stdin comme dernier argument.

    Je n'attend pas des réponses complète (ça serait trop facile...) mais juste des explications qui m'aideront à y voir plus claire! D'avance merci beaucoup !!!

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par Ash95 Voir le message
    Je n'attend pas des réponses complète (ça serait trop facile...)
    De toute façon ici ce n'est pas notre politique...

    Citation Envoyé par Ash95 Voir le message
    vous pouvez utiliser la fonction feof (????? )
    T'as raison d'être étonné. Je ne sais pas quel est le débile qui a écrit ce conseil car il est complètement à l'ouest. feof ne sert pas à détecter une fin de saisie mais à indiquer, une fois que la saisie ne se fait plus, si la fin est due à une fin normale ou à une fin anormale (erreur disque, etc...).

    La fin de saisie se détecte via la fonction de saisie elle-même qui renvoie une valeur particulière quand le flux se termine. Donc typiquement, ce sera un truc du style
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while (fonction_de_saisie() != valeur_particuliere)
    {
        faire traitement
    }

    Ensuite, si tu veux utiliser feof, alors ce sera de cette façon
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    while (fonction_de_saisie() != valeur_particuliere)
    {
        faire traitement
    }
     
    if feof(stdin)
    {
        fin_de_saisie_normale
    }
    else
    {
        fin_de_saisie_due_a_une_erreur
    }

    Ensuite pour le realloc, c'est tout simple: tu définis 3 éléments
    • ton tableau lui-même
    • sa taille réellement allouée (qui variera dans ton cas de 10 en 10)
    • l'indice de remplissage

    Et tout ça initialisé à 0

    Ensuite, tu fais ta boucle de saisie. Mais (dans la boucle), avant de remplir le tableau, tu regardes si l'indice de remplissage a atteint la taillle allouée (ce qui est obligatoirement le cas lors de la première itération puisque ces deux valeurs sont à 0). Si c'est le cas, alors tu augmentes la taille allouée de 10 puis tu fais un realloc de la taille allouée. Et si le tableau est à NULL (ce qui est aussi le cas à la première itération), alors realloc se comporte comme un malloc.
    Et ensuite, une fois cette étape d'allocation terminée, dans tous les cas, tu remplis la case du tableau située à l'indice de remplissage puis tu augmentes celui-ci de 1.
    Tu peux dérouler cet algo à la main, tu verras que jamais les éléments stockés ne dépassent le tableau qui les contient...

  3. #3
    Membre chevronné
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Points : 1 753
    Points
    1 753
    Par défaut
    Bonjour
    Citation Envoyé par Ash95 Voir le message
    Bonjour tout le monde,
    J'ai vraiment besoin de votre aide!!!
    Je dois faire un programme qui réponds à cette consigne
    .......
    Améliorez votre programme pour permettre la saisie d'un nombre illimité de chaine. Lorsque l'utilisateur aura saisi la dernière, il devra frapper ctrl-d, vous pouvez utiliser la fonction feof (????? ) pour sortir de la boucle de saisie. Le tableau des adresses des chaines saisies sera ralloué par tranche de 10 en utilisant la fonction realloc.
    Je n'attend pas des réponses complète (ça serait trop facile...) mais juste des explications qui m'aideront à y voir plus claire! D'avance merci beaucoup !!!
    Avez-vous bien lu et compris l'énoncer du sujet et ce que l'on vous demande de faire ?

    Citation Envoyé par Sve@r Voir le message
    Bonjour

    De toute façon ici ce n'est pas notre politique...
    T'as raison d'être étonné. Je ne sais pas quel est le débile qui a écrit ce conseil car il est complètement à l'ouest. feof ne sert pas à détecter une fin de saisie mais à indiquer, une fois que la saisie ne se fait plus, si la fin est due à une fin normale ou à une fin anormale (erreur disque, etc...).

    La fin de saisie se détecte via la fonction de saisie elle-même qui renvoie une valeur particulière quand le flux se termine. Donc typiquement, ce sera un truc du style
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while (fonction_de_saisie() != valeur_particuliere)
    {
        faire traitement
    }

    Ensuite, si tu veux utiliser feof, alors ce sera de cette façon
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    while (fonction_de_saisie() != valeur_particuliere)
    {
        faire traitement
    }
     
    if feof(stdin)
    {
        fin_de_saisie_normale
    }
    else
    {
        fin_de_saisie_due_a_une_erreur
    }
    Je ne pense pas que l'enseignent soit complètement à l'ouest je dirais même qu'il est un très bon professeur et qu'il vous donne de très bon exercice au final il est vrai qu'il a une vision de vous comme étant des futures professionnelles.

    Personnellement je trouve que c'est t'un très bon exercice et bien conçu de façon à exploiter de manière astucieuse et intelligente les entrées sorties.
    Ce que vous avez énoncé est correcte pour la fonction elle renvoie bien une valeur non nulle si la fin de fichier est atteint. Il fait mieux encore en vous mettons sur la piste (il est généreux) en précisant que l'utilisateur doit taper CTRL-D pour fermer le flot en clair la fonction de saisie qui est tout simplement bloquante car lors de la lecture du clavier ( du stdin ) il n'y a à pas de fin de fichier donc on se retrouve dans une lecture constante ( lecture bloquante) ce qui permet à l'utilisateur de taper des caractères comme bon lui semble et la seule façon d'arrêter cette saisie est la combinaison des touches CTRL-D (Unix) ou CTRL-Z (Windows)
    Ce qui donne au final le code source ci-dessous qui pourrait répondre a ces attentes et qui est à adapter, optimiser et corriger.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define SIZE	10
     
    int main( void ){
     
    	int er_write = 0;
    	char *p = (char*)calloc( SIZE, sizeof(char) );
    	if( (NULL) == p ){
    		fprintf( stderr, "(%d)\n Erreur Allocation\n>>\t%s\n",
    				errno, strerror(errno) );
    		return( EXIT_FAILURE );
    	}
     
    	do{
    		p = fgets( p, SIZE, stdin ); 	/* Lecture du fichier 			*/
    		er_write = feof( stdin );		/* Controle  fin de fichier 	*/
    		fprintf( stdout, "%s", p ); 	/* Print du résultat			*/
    	}while( !er_write );				/* Fin de boucle CTRL-D/CTRL-Z	*/
     
    	free( p );
    	p = NULL;
     
    	return( EXIT_SUCCESS );
    }
    à bientôt

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Ce que vous avez énoncé est correcte pour la fonction elle renvoie bien une valeur non nulle si la fin de fichier est atteint.
    Ce qui justement ne permet pas de détecter qu'on est sur le dernier enregistrement. Si le fichier contient 3 enregistrements, il faudra lire 4 fois pour que feof() soit activé.

    Citation Envoyé par sambia39 Voir le message
    Il fait mieux encore en vous mettons sur la piste (il est généreux) en précisant que l'utilisateur doit taper CTRL-D pour fermer le flot en clair la fonction de saisie qui est tout simplement bloquante car lors de la lecture du clavier ( du stdin ) il n'y a à pas de fin de fichier donc on se retrouve dans une lecture constante ( lecture bloquante) ce qui permet à l'utilisateur de taper des caractères comme bon lui semble et la seule façon d'arrêter cette saisie est la combinaison des touches CTRL-D (Unix) ou CTRL-Z (Windows)
    Oui mais les fonctions de lecture savent interpréter ce "CTRL-D" et dans ce cas, renvoient la valeur attribuée à l'info "je ne lis plus rien, j'ai terminé".

    Citation Envoyé par sambia39 Voir le message
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	do{
    		p = fgets( p, SIZE, stdin ); 	/* Lecture du fichier 			*/
    		er_write = feof( stdin );		/* Controle  fin de fichier 	*/
    		fprintf( stdout, "%s", p ); 	/* Print du résultat			*/
    	}while( !er_write );				/* Fin de boucle CTRL-D/CTRL-Z	*/
    	free(p);
    Et que se passe-t-il si stdin est vide à la première lecture ??? fgets ne lit rien, indique qu'il n'y a rien à lire mais ce renseignement n'est pas traité et on tente d'afficher quand-même p. Dans ce cas précis ça va quand-même car afficher NULL fonctionne mais si on effectue un traitement plus complexe, c'est le crash !!!

    PS: je ne sais pas si fgets() fait un malloc pour qu'il y ait ce free derrière. Mais s'il en fait un, alors autant d'itération dans la boucle, autant de malloc non libérés. Fuite mémoire en plus...

    Une première correction serait alors de vérifier feof() avant de traiter. Et d'utiliser un tableau destinataire des infos lues au lieu de ce malloc non controlé (surtout qu'on a la taille connue !!!)
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    	char p[SIZE];
    	do{
    		fgets( p, SIZE, stdin ); 	/* Lecture du fichier 			*/
    		er_write = feof( stdin );		/* Controle  fin de fichier 	*/
                    if (er_write) break;		/* Si lecture inutile sortie de boucle */
    		fprintf( stdout, "%s", p ); 	/* Print du résultat			*/
    	}while( !er_write );				/* Fin de boucle CTRL-D/CTRL-Z	*/
    Mais on teste alors 2 fois la même chose, ce qui est contre productif. Accessoirement, appeler une variable "er_write" pour indiquer une erreur de "lecture"... On va alors supprimer le second test et cette variable au nom si mal choisi...
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	while (1) {
    		fgets( p, SIZE, stdin ); 	/* Lecture du fichier 			*/
                    if (feof( stdin )) break;		/* Si lecture inutile sortie de boucle */
    		fprintf( stdout, "%s", p ); 	/* Print du résultat			*/
    	}	/* Fin de boucle CTRL-D/CTRL-Z	*/
    Alors là ça devient ok et robuste. Mais bon, outre le fait que certains puristes n'aiment pas l'utilisation d'interruptions impromptues, c'est quand-même dommage d''utiliser une seconde fonction pour redemander une info que la première avait déjà donnée. Autant alors rester simple et tester directement le retour de la lecture elle-même. Après-tout, si cette info existe, c'est peut-être pour quelque chose...

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    	while (fgets( p, SIZE, stdin ) != NULL) 	/* Lecture du fichier 			*/
    		fprintf( stdout, "%s", p ); 	/* Print du résultat			*/
    	}	/* Fin de boucle CTRL-D/CTRL-Z	*/
    Et voilà - Fonctionne pareil mais avec moitié-moins de code et sans cette variable si mal nommée et qui s'avéra finalement si inutile...

  5. #5
    Membre chevronné
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Points : 1 753
    Points
    1 753
    Par défaut
    (+1)Très bonne analyse & correction
    Citation Envoyé par Sve@r Voir le message
    PS: je ne sais pas si fgets() fait un malloc pour qu'il y ait ce free derrière. Mais s'il en fait un, alors autant d'itération dans la boucle, autant de malloc non libérés. Fuite mémoire en plus...
    Peut-être confus de mon côté, mais il me semble bien que la fonction fgets n'alloue pas de mémoire mais stocke les caractères dans le buffer qui doit être une zone mémoire préalablement allouée soit un tableau de caractère ou une allocation dynamique.
    et le free vient du
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    char *p = (char*)calloc( SIZE, sizeof(char) );
    	if( (NULL) == p ){
    		fprintf( stderr, "(%d)\n Erreur Allocation\n>>\t%s\n",
    				errno, strerror(errno) );
    		return( EXIT_FAILURE );
    	}
    J'avoue avoir une mauvaise analyse sur ce coup.
    Merci pour tes remarques et à bientôt.

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Peut-être confus de mon côté, mais il me semble bien que la fonction fgets n'alloue pas de mémoire mais stocke les caractères dans le buffer qui doit être une zone mémoire préalablement allouée soit un tableau de caractère ou une allocation dynamique.
    et le free vient du
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    char *p = (char*)calloc( SIZE, sizeof(char) );
    Ok, j'avais pas fait attention. Mais dans ce cas, surtout ne pas perdre p donc ne pas écrire ensuite p=fgets(...). C'est lui qui m'a fait tilter sans que je lise ce qu'il y avait au dessus...

Discussions similaires

  1. [DarkBasic Pro] Peut-on parler de langage ?
    Par gamerome dans le forum Basic
    Réponses: 13
    Dernier message: 19/05/2014, 05h18
  2. Devenir PRO en MERISE
    Par miss_kamelia dans le forum Merise
    Réponses: 5
    Dernier message: 23/06/2010, 11h37
  3. Comment devenir pro en développement Java
    Par tabitarh dans le forum Général Java
    Réponses: 6
    Dernier message: 22/12/2008, 15h37
  4. [PRO*C] Langage c et requete base oracle
    Par manucha dans le forum Interfaces de programmation
    Réponses: 7
    Dernier message: 15/06/2007, 14h11
  5. Apprendre un moteur 3D pour devenir pro
    Par Riki dans le forum Moteurs 3D
    Réponses: 11
    Dernier message: 08/02/2007, 08h01

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo