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 :

Fonctionnement des pointeurs


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2012
    Messages : 83
    Par défaut Fonctionnement des pointeurs
    Bonjour à tous !

    Après avoir lu des articles sur les pointeurs, dont celui de developpez.com, j'aimerais mettre au clair quelques incompréhensions. Oui je suis un peu lent...
    Voici mes 3 questions:

    1. Est ce que ces 2 lignes d'instructions sont identiques ?
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      int *px = malloc(sizeof(int));
      //EST LA MEME CHOSE QUE:
      int *px;
      // ?
      Autrement dit, malloc ne trouve son utilité que lorsque nous souhaitons considérer la mémoire allouée autrement qu'une suite d'octets ? Ceci dans le but d'utiliser notre pointeur comme un tableau ?

      Donc lorsque je veux initialiser une chaîne de caractère, il est inutile d'utiliser un malloc ? Si je fais ceci:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      char *phrase= "Bonjour à tous.";
    2. La mémoire va prévoir un octet par caractère + 1 et cet emplacement ne risquera pas d'être effacé par l'initialisation d'une autre variable ?

    3. Aussi j'ai cru comprendre qu'un pointeur attendait une adresse, dans la ligne d'instruction ci-dessus je ne lui en ai pourtant pas donné... Est-ce une intervention du compilateur ?


    D'avance je vous remercie pour votre aide !

  2. #2
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Bonjour,
    Un pointeur vers un type T est une variable dont les valeurs sont des adresses mémoires de valeurs de type T.
    Il se déclare par T *p;Prenons int comme type T, ce sera plus explicite.
    int *p; est traductible par "cher compilateur, ce qui se trouve à l'adresse contenue par p est un int".

    Tu n'as toujours pas donné cette valeur.
    Pour ce faire, tu as deux possibilités: donner l'adresse d'un entier en mémoire, ou demander l'allocation au systeme.

    La première possibilité requiert l'usage de l'opérateur d'adressage ou d'un autre pointeur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int a;
    int *p1 = &a;
    int *p2 = p1;
    Techniquement, &a est une expression dont la valeur est l'adresse de a, c'est donc une valeur de type pointeur d'entier.

    La seconde possibilité utilise malloc, calloc ou realloc. (et requiert l'usage de free).
    Un programme dispose de plusieurs bloc mémoires, dont une pile et un tas.
    La pile contient les variables locales, le tas les allocations externes.

    malloc alloue un bloc mémoire, sans l'initialiser, et retourne son adresse.
    calloc alloue un bloc mémoire, en l'initialisant à 0 partout, et retourne son adresse.
    realloc sert à déplacer un bloc mémoire dans un nouveau, en général d'une autre taille.
    free libère ces blocs mémoire.

    Il n'y a pas de risque qu'une variable soit déclaré sur un bloc mémoire alloué, ni le contraire. Par contre, manipuler des pointeurs inconsidérément permet d'écrire n'importe où. Du moins, permet d'essayer, lorsque cela arrive, il peut survenir des segmentations faults (ou SEGFAULT)

    Un pointeur possède deux propriétés utiles à connaitre, et souvent pratiques:
    il peut valoir NULL, c'est à dire "pas de mémoire".
    si p est un pointeur vers un T, p+4 aussi et est l'adresse du T situé "4 T plus loin que " p.

    le nom d'un tableau peut être utilisé quasiment comme un pointeur.
    supposons int tab[4];. alors &tab[2] == tab+2 et *(tab+2) == tab[2] == 2[tab].

    Plus amusant, ce code affiche vrai:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    int tab[4]={0,7,42,23};
    int *p = &tab[0];
    if (*(p+2)==42) printf("vrai");
    J'espère que cela te sera utile.

    PS: pour les char*, je répondrais une autre fois, je n'ai pas le temps…

  3. #3
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    1) Pas exactement.
    Dans les 2 cas tu as une variable "px" qui est une adresse vers un int.
    Dans le 1er cas : un malloc va demander au système de lui donner un espace mémoire de taille "sizeof (int)", et de placer l'adresse de cet espace dans "px".
    Dans le 2e cas : "px" contient une valeur inconnue, et n'a aucun espace alloué.

    Pour ta chaîne de caractères, comme tu dis au compilo d'associer une chaîne en dur, ton char* contiendra une adresse vers le texte.
    Cependant, ce texte est dans une partie "read only" de la mémoire, tu ne pourras donc pas le modifier.
    Pour initialiser "dynamiquement" un char* avec du texte, il faut utiliser strdup.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char *phrase = strdup("ma phrase");
    Celui là fera appel à malloc et sera modifiable !

    2) Dans le cas de l'initialisation SANS strdup, un '\0' sera ajouté.
    Mais si tu malloc tout seul, tu DOIS ajouter le + 1 !

    3) C'est le compilo qui va en effet placer les valeurs d'initialisation dans les variables.
    Ton char* va obtenir une adresse vers l'espace de ton texte.
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  4. #4
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2012
    Messages : 83
    Par défaut
    Merci pour vos réponses très compètes !

    Il n'y a pas de risque qu'une variable soit déclaré sur un bloc mémoire alloué, ni le contraire. Par contre, manipuler des pointeurs inconsidérément permet d'écrire n'importe où. Du moins, permet d'essayer, lorsque cela arrive, il peut survenir des segmentations faults (ou SEGFAULT)
    Il est donc dangereux de ne pas allouer de la mémoire ? J'entends par là de n'utiliser ni allocation système, ni même fournir une adresse qui pointe déjà sur une variable initialisée, au risque que de nouvelles données écrasent les précédentes "non allouées".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *(tab+2) == tab[2] == 2[tab]
    Par simple précaution, ne serait-ce pas 2+[tab] au lieu de 2[tab] ? (Je préfère demander pour être sûr, bien que j'imagine que c'est une faute de frappe.)

    2) Dans le cas de l'initialisation SANS strdup, un '\0' sera ajouté.
    Mais si tu malloc tout seul, tu DOIS ajouter le + 1 !
    Je suppose qu'il faut ajouter +1 avec un malloc pour placer le \0 ? Ça signifie que AVEC strdup il n'y aura pas de '\0' à la fin de la chaîne ? strdup utilise pourtant un malloc non ?

  5. #5
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 392
    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 392
    Par défaut
    Citation Envoyé par stoner Voir le message
    Il est donc dangereux de ne pas allouer de la mémoire ? J'entends par là de n'utiliser ni allocation système, ni même fournir une adresse qui pointe déjà sur une variable initialisée, au risque que de nouvelles données écrasent les précédentes "non allouées".
    Oui. Un pointeur doit toujours être initialisé soit à une adresse valide, soit à NULL (adresse invalide, mais reconnaissable).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *(tab+2) == tab[2] == 2[tab]
    Par simple précaution, ne serait-ce pas 2+[tab] au lieu de 2[tab] ? (Je préfère demander pour être sûr, bien que j'imagine que c'est une faute de frappe.)
    Non, c'est bien 2[tab].
    Par contre, on pourrait rajouter ceci à la fin de la ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    *(tab+2) == tab[2] == 2[tab] == *(2+tab)
    Je suppose qu'il faut ajouter +1 avec un malloc pour placer le \0 ? Ça signifie que AVEC strdup il n'y aura pas de '\0' à la fin de la chaîne ? strdup utilise pourtant un malloc non ?
    strdup() fait automatiquement un malloc(strlen(chaine)+1) avant d'y copier la chaîne. Attention par contre, cette fonction n'est pas disponible partout (elle n'est pas dans le standard C).
    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.

  6. #6
    Membre confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2012
    Messages
    83
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2012
    Messages : 83
    Par défaut
    Super merci !

    Cependant une question me vient à l'esprit. Lorsque je fais ceci, je provoque un segmentation fault.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    char *c = "tip";
    char *tab = c;
    tab[1] = 'o';
    Comme vous me l'avez expliqué, c'est parce que "tip" est écrit en "read only" et qu'une donnée tente de l'écraser. (Si j'ai bien compris. )

    J'ai donc voulu essayer en allouant de la mémoire avec malloc pour observer ce qu'il se passe:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    char *c = malloc(4 * sizeof(char));
    *c = "tip"; //Erreur.
    char *tab = c;
    tab[1] = 'o';
    Je reçois un assignment makes integer from pointer without a cast à la ligne 2.

    Pourtant *c représente bien la zone mémoire pointée par mon malloc (pouvant accueillir 3 chars) ? Et je tente de lui affecter justement 3 chars.
    Je ne comprends pas très bien ce qu'il se passe... ^^

  7. #7
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    char *c = malloc(4 * sizeof(char));
    *c = "tip"; //Erreur
    .
    "tip" est une chaine littérale de caractères, donc un tableau (non modifiable) d'éléments de type char (donc qui sont des entiers).
    Dans ce contexte d'utilisation, l'évaluation de l'expression "tip" donnera l'adresse du premier élément de la chaine donc un type char *.

    Par contre, comme c est un char *, *c est un entier de type char.
    la deuxième ligne correspond donc à entier = adresse ce qui correspond au message d'erreur.

    La cause de cette confusion est liée sans doute au fait que tu croyais copier la chaine dans la zone allouée avec cette assignation (=). Mais on ne peut copier un tableau par une simple assignation.
    Dans ton cas, tu peux faire strcpy(c,"tip");.

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

Discussions similaires

  1. Probleme avec des pointeurs...
    Par barucca dans le forum C++
    Réponses: 5
    Dernier message: 23/08/2005, 21h05
  2. Libérer des pointeurs dans une std::map
    Par GaldorSP dans le forum SL & STL
    Réponses: 2
    Dernier message: 09/07/2005, 14h42
  3. Fonctionnement des fichiers.
    Par phoenix440 dans le forum Autres Logiciels
    Réponses: 7
    Dernier message: 29/05/2005, 15h36
  4. à propos des pointeurs
    Par salseropom dans le forum C++
    Réponses: 20
    Dernier message: 24/03/2005, 09h37
  5. [langage] fonctionnement des Processus
    Par GMI3 dans le forum Langage
    Réponses: 3
    Dernier message: 19/09/2003, 11h12

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