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 :

Problèmes avec les pointeurs


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2007
    Messages : 3
    Par défaut Problèmes avec les pointeurs
    Bonjour à tous.

    Un exercice de codage en C m'a été proposé:

    Ecrire un programme qui lit 10 phrases d'une longueur maximale de 200 caractères au clavier et qui les mémorise dans un tableau de pointeurs sur char en réservant dynamiquement l'emplacement en mémoire pour les chaînes. Ensuite, l'ordre des phrases est inversé en modifiant les pointeurs et le tableau résultant est affiché.
    J'ai un petit problème en ce qui concerne la modification de l'ordre des phrases en modifiant les pointeurs.

    Voici mon code actuel:

    Code : 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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    #include <stdio.h>
    #include <stdlib.h>
     
    #define NB_PHRASES 10
    #define CARACT_MAX 200
     
    char** creer_tableau (int, int);
    void entrer_phrases (char**, int);
    void imprimer_phrases (char**, int);
    void modif_pointeurs (char**, int);
     
    int main (void) {
    	char** tableau=creer_tableau(NB_PHRASES, CARACT_MAX);
    	entrer_phrases (tableau, NB_PHRASES);
    	printf ("\n");
    	imprimer_phrases (tableau, NB_PHRASES);
    	modif_pointeurs (tableau, NB_PHRASES);
    	printf ("\n");
    	imprimer_phrases (tableau, NB_PHRASES);
    	return 0;
    }
     
    char** creer_tableau (int l, int c) {
    	int i;
    	char** M;
    	M=(char**) malloc (sizeof(char*)*l);
    	for (i=0; i<l; i++)
    		M[i]=(char*) malloc (sizeof(char)*c);
    	return M;
    }
     
    void entrer_phrases (char** M, int l) {
    	int i;
    	for (i=0; i<l; i++) {
    		printf ("Introduisez une phrase:\n");
    		gets (M[i]);
    	}
    }
     
    void imprimer_phrases (char** M, int l) {
    	int i, j;
    	for (i=0; i<l; i++) {
    		for (j=0; M[i][j]!='\0'; j++)
    			printf ("%c", M[i][j]);
    		printf ("\n");
    	}
    }
     
    void modif_pointeurs (char** M, int l) {
    	int i;
    	char** tmp;
    	for (i=0; i<l; i++) {
    		tmp=&M[i];
    		M[i]=M[l-1-i];
    		M[l-1-i]=*tmp;
    	}
    }
    Toutes les procédures et les fonctions fonctionnent sauf celle appelée modif_pointeurs.

    Je crée donc un pointeur sur une chaine de caractères (c'est tmp).
    Je place l'adresse de M[i] dans tmp mais, lors de l'assignation M[i]=M[l-1-i], la valeur de tmp change (ce qui est normal).
    Pouvez-vous m'aider à mieux comprendre ce problème de pointeur, parceque au delà de l'exercie, je pense que c'est vraiment un problème de compréhension des pointeurs.
    Je vous remercie d'avance.

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    131
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 131
    Par défaut
    Evite d utiliser gets, utlise fgets.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ...
    fgets(M[i], CARACT_MAX, stdin);
    ...
    Ensuite pour l affichage tu peut faire plus simplement : Afficher une string plutot que de faire caractere par caractere.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
     void imprimer_phrases (char** M, int l) {
         int i, j;
         for (i=0; i<l; i++) {
             printf ("%s", M[i]);
         }
     }
    Et le meilleur pour la fin
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     void modif_pointeurs (char** M, int l) {
         int i;
         char* tmp;
         for (i=0; i<l/2; i++) {
             tmp=M[i];
             M[i]=M[l-1-i];
             M[l-1-i]=tmp;
         }
     }

    Je rajoute quand meme une petite explication sur la derniere fonction ^^.

    Ton erreur etait d utiliser tmp comme un pointeur de pointeur. Car a la ligne suivante du dis que la valeur se trouvant a l adresse &M[i] (donc tmp) a pour valeur M[l-1-i].

    Il se fait tard .... J espere que j ai ete assez clair ^^ .

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 52
    Par défaut
    Petites remarques constructives :

    Tel quel, ton programme permet de saisir des phrases de 199 caractères maximum et non 200.
    Les chaînes en C étant toujours terminées par un 0 dont il faut tenir compte dans les manipulations des chaînes.

    Dans un deuxième temps, il faudrait se soucier des valeurs retournées par les appels à la fonction malloc.

    Le plus important étant qu'il manque a la fin de ton programme la fonction la plus importante à long terme :
    liberer_tableau(char**, int);

    Bon apprentissage.

  4. #4
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2007
    Messages : 3
    Par défaut
    Citation Envoyé par berg Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     void modif_pointeurs (char** M, int l) {
         int i;
         char* tmp;
         for (i=0; i<l/2; i++) {
             tmp=M[i];
             M[i]=M[l-1-i];
             M[l-1-i]=tmp;
         }
     }

    Je rajoute quand meme une petite explication sur la derniere fonction ^^.

    Ton erreur etait d utiliser tmp comme un pointeur de pointeur. Car a la ligne suivante du dis que la valeur se trouvant a l adresse &M[i] (donc tmp) a pour valeur M[l-1-i].
    J'ai déjà essayé comme ça, mais ça ne fonctionne pas. En fait, char* tmp c'est un pointeur sur un caractère. En créant char** tmp, je créais un pointeur sur une chaine de caractères. (Enfin, je pense que c'est comme ça)...
    En écrivant la procédure comme tu me le dis, les phrases ne sont pas dans l'ordre inversé...
    Pour toutes tes autres remarques, j'en prends bonne note afin d'améliorer mes futurs programmes.

    Citation Envoyé par Fred83 Voir le message
    Petites remarques constructives :

    Tel quel, ton programme permet de saisir des phrases de 199 caractères maximum et non 200.
    Les chaînes en C étant toujours terminées par un 0 dont il faut tenir compte dans les manipulations des chaînes.

    Dans un deuxième temps, il faudrait se soucier des valeurs retournées par les appels à la fonction malloc.

    Le plus important étant qu'il manque a la fin de ton programme la fonction la plus importante à long terme :
    liberer_tableau(char**, int);

    Bon apprentissage.
    Merci aussi Fred83 pour tes remarques. En effet, petite bêtise en oubliant de compter le '\0' à la fin des chaînes => #define CARACT_MAX 201.
    Pour les malloc, il est vrai que je devrait vérifier si tout se passe bien.
    Et le plus important, comment ai-je pu oublier de faire la désallocation de mémoire???

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void liberer_tableau (char** M, int l) {
    	int i;
    	for (i=0; i<l; i++)
    		free (M[i]);
    	free (M);
    }

  5. #5
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    ... En fait, char* tmp c'est un pointeur sur un caractère. En créant char** tmp, je créais un pointeur sur une chaine de caractères. (Enfin, je pense que c'est comme ça)...
    Ce n'est pas comme ca. char * est un pointeur sur un caractère ou sur un tableau de caractères , on ne sait pas à priori
    La solution de Berg semble correcte. Peut être n'as-tu pas observé la bonne limite
    for (i=0; i<l/2; i++)
    Si tu prends comme borne l au lieu de l/2, tu permutes deux fois et tu te retrouves dans l'état d'origine.

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2007
    Messages : 3
    Par défaut
    En effet... Je n'avais pas vu le l/2. J'en suis désolé...
    Effectivement, ça fonctionne comme ça...
    Donc mon char* tmp, c'est un pointeur sur un tableau...
    Il faudra vraiment que je relise mon chapitre sur les pointeurs...

    En tout cas, merci à tous pour votre aide.
    J'espère m'améliorer et pouvoir à mon tour vous aider lorsque vous aurez besoin d'aide.

    A très bientôt et encore merci.

  7. #7
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par dlaumor Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    char** creer_tableau (int l, int c) {
    	int i;
    	char** M;
    	M=(char**) malloc (sizeof(char*)*l);
    	for (i=0; i<l; i++)
    		M[i]=(char*) malloc (sizeof(char)*c);
    	return M;
    }
    Toutes les procédures et les fonctions fonctionnent sauf celle appelée modif_pointeurs.
    Pas toutes, non. Par exemple, creer_tableau ne gère pas le cas où l'appel à malloc échoue. Dans ton code ci-dessus, tu obtiens une erreur de segmentation si le premier appel à malloc() renvoie NULL, car tu cherche à déréférencer un pointeur NULL. Aïe!

    Le code minimal pour la fonction creer_tableau() est, à mon avis, quelque chose qui ressemble à:

    Code : 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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    #include <stdlib.h>
    #include <string.h>
     
    /* evite les identificateur tels que l qu'on confond facilement avec 1 */
    char **creer_tableau(size_t nlig, size_t ncols)
    {
        char **pp_self = NULL;
     
        /* on verifie la validite des arguments passes a la fonction */
        if (nlig > 0 && ncols > 0)
        {
            pp_self = malloc((nlig + 1) * sizeof *pp_self);
            /* on verifie TOUJOURS la valeur retournee par malloc() */
            if (pp_self != NULL)
            {
                size_t i;
                int err = 0;
     
                for (i = 0; err == 0 && i < nlig; i++)
                {
                    pp_self[i] = malloc(ncols * sizeof *pp_self[i]);
                    if (pp_self[i] == NULL)
                    {
                        /* Si l'allocation a echoue, on signale l'erreur et on arrete la 
                            boucle*/
                        err = 1;
                    }
                    else
                    {
                        /* on initialise les case du tableau a zero */
                        memset(pp_self[i], 0, ncols * sizeof **pp_self);
                    }
                }
                /* terminer un tableau de tableau de char avec NULL est parfois
                    bien pratique */
                pp_self[i] = NULL;
     
                /* Si il y a une erreur d'allocation, on fait le menage */
                if (err == 1)
                {
                    /* on libere toute la memoire allouee auparavant */
                    while (i > 0)
                    {
                        i--;
                        free(pp_self[i]);
                    }
                    free(pp_self), pp_self = NULL;
                }
            }
        }
     
        /* on retourne le tableau ou NULL si l'allocation a echoue */
        return pp_self;
    }
    Ici, creer_tableau() renvoie NULL en cas d'échec de l'allocation et fait le ménage si nécessaire. La dernère ligne du tableau vaut NULL (comme pour argv). Cette sentinelle de réécrire imprimer_phrases() de la manière suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void imprimer_phrases(char **M)
    {
        if (M != NULL)
        {
            int i;
            for (i = 0; M[i] != NULL; i++)
            {
                printf("%s", M[i]);
            }
            /* purge de tampon de la sortie standard */
            fflush(stdout)
        }
    }

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

  8. #8
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Trop compliqué pour l'allocation d'une matrice.
    Voici un exemple avec moins d'allocations (ici, avec des doubles, mais on peut facilement remplacer par des char) :
    http://www.developpez.net/forums/sho...70&postcount=7
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Expert confirmé
    Avatar de Thierry Chappuis
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Mai 2005
    Messages
    3 499
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Suisse

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Mai 2005
    Messages : 3 499
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Trop compliqué pour l'allocation d'une matrice.
    Voici un exemple avec moins d'allocations (ici, avec des doubles, mais on peut facilement remplacer par des char) :
    http://www.developpez.net/forums/sho...70&postcount=7
    Entièrement d'accord avec toi. J'aurais pu procéder comme tu le propose. Je trouve cette technique moins clair à enseigner à quelqu'un qui débute même si, au final, cela simplifie pas mal la vie pour gérer les erreurs d'allocation de mémoire ainsi que la libération de cette dernière.

    +1, donc. Merci!

    Thierry
    "The most important thing in the kitchen is the waste paper basket and it needs to be centrally located.", Donald Knuth
    "If the only tool you have is a hammer, every problem looks like a nail.", probably Abraham Maslow

    FAQ-Python FAQ-C FAQ-C++

    +

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème avec les pointeurs intelligents de boost.
    Par Le Barde dans le forum Boost
    Réponses: 2
    Dernier message: 05/09/2007, 12h47
  2. Petit problème avec les pointeurs et variable
    Par mitherkiller dans le forum C
    Réponses: 5
    Dernier message: 09/03/2007, 22h05
  3. problème avec les pointeurs en c
    Par dialloma dans le forum C
    Réponses: 14
    Dernier message: 01/01/2007, 21h22
  4. probléme avec les pointeurs
    Par killer_instinct dans le forum C++
    Réponses: 6
    Dernier message: 11/12/2006, 11h37
  5. [TTreeView] Problème avec les pointeurs d'objet
    Par BlackWood dans le forum Composants VCL
    Réponses: 2
    Dernier message: 02/07/2004, 14h31

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