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 :

Quelques soucis avec un tableau de structures


Sujet :

C

  1. #1
    Membre actif

    Inscrit en
    mars 2003
    Messages
    241
    Détails du profil
    Informations forums :
    Inscription : mars 2003
    Messages : 241
    Points : 235
    Points
    235
    Par défaut Quelques soucis avec un tableau de structures
    Bonjour, une erreur s'est glissée dans mon code, saurez vous la retrouver.

    En fait, je cherche à gérer un tableau de structures de façon dynamique (malloc). Chaque structure représente les informations d'une connexion FTP. Mon code plante lorsque je souhaite ajouter une deuxième structure, la première insertion se déroule sans soucis.

    Ci après le code incriminé :
    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
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    struct connexionftp *resize_connexion(struct connexionftp *p_conn,
                                          int *curr_size, int new_size)
    {
        if (p_conn == NULL) return p_conn;
        if (curr_size == NULL) return p_conn;
     
     
        if (new_size  < 0) return p_conn;
        if (new_size == 0)
        {
            p_conn = free_connexion(p_conn);
            if (p_conn == NULL)
            {
                *curr_size = 0;
     
     
                return NULL;
            }
            return p_conn;
        }
     
        p_conn = (struct connexionftp *) realloc(p_conn, new_size * sizeof(struct connexionftp));
        if (p_conn == NULL)
        {
            *curr_size = 0;
     
     
            return NULL;
        }
        *curr_size = new_size;
     
     
        return p_conn;
    }
     
    void copy_connexion(struct connexionftp **p_dest,
                        const struct connexionftp * const p_src,
                        const int index)
    {
        strcpy(p_dest[index]->host, p_src->host);
        strcpy(p_dest[index]->username, p_src->password);
        strcpy(p_dest[index]->password, p_src->password);
        p_dest[index]->port = p_src->port;
    }
     
    short add_connexion(struct connexionftp **p_list, int *size, struct connexionftp *p_ftp)
    {
        if (p_ftp  == NULL) return false;
        if (p_list == NULL) return false;
        if (size   == NULL) return false;
     
     
        if (*p_list == NULL)
        {
            *p_list = get_connexion(1);
            if (*p_list == NULL) return false;
     
            *size = 1;
        } else {
            /** Partie qui pose problème **/
            *p_list = resize_connexion(*p_list, size, *size + 1);
            if (*p_list == NULL) return false;
        }
        copy_connexion(p_list, p_ftp, *size - 1);
     
     
        return true;
    }
    Le problème se situe à la sortie de la fonction resize_connexion() qui est censée modifier la taille du tableau. Quand on est dans la fonction, le tableau a bien la taille désirée, cependant, une fois ressorti on retrouve l'ancienne taille.

    Une exécution du programme à l'aide de GDB pourra vous aider à comprendre :
    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
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    (gdb) r
    Starting program: main 
    
    	Que voulez-vous faire ?
    
    [C] Consulter la liste
    [A] Ajouter une connexion
    [M] Modifier une connexion
    [S] Supprimer une connexion
    
    [E] Enregistrer
    [Q] Quitter
    > a
    Ajout d'une connexion
    	Hôte : fg
    	Nom d'utilisateur : fg
    	Mot de passe : fg
    	Port : 21
    
    Breakpoint 2, add_connexion (p_list=0xbffff6e8, size=0xbffff6e4, 
        p_ftp=0x804b008) at ftp.c:76
    76	    copy_connexion(p_list, p_ftp, *size - 1);
    (gdb) c
    Continuing.
    
    	Que voulez-vous faire ?
    
    [C] Consulter la liste
    [A] Ajouter une connexion
    [M] Modifier une connexion
    [S] Supprimer une connexion
    
    [E] Enregistrer
    [Q] Quitter
    > a
    Ajout d'une connexion
    	Hôte : fg
    	Nom d'utilisateur : fg
    	Mot de passe : fg
    	Port : 21
    
    Breakpoint 1, add_connexion (p_list=0xbffff6e8, size=0xbffff6e4, 
        p_ftp=0x804b008) at ftp.c:73
    73	        *p_list = resize_connexion(*p_list, size, *size + 1);
    (gdb) p *p_list
    $1 = (struct connexionftp *) 0x804b310
    (gdb) p *p_list[0]
    $3 = {host = "fg", '\000' <repeats 252 times>, 
      username = "fg", '\000' <repeats 252 times>, 
      password = "fg", '\000' <repeats 252 times>, port = 21}
    (gdb) s
    resize_connexion (p_conn=0x804b310, curr_size=0xbffff6e4, new_size=2)
        at mem.c:28
    28	    if (p_conn == NULL) return p_conn;
    (gdb) s
    29	    if (curr_size == NULL) return p_conn;
    (gdb) s
    32	    if (new_size  < 0) return p_conn;
    (gdb) s
    33	    if (new_size == 0)
    (gdb) s
    46	    p_conn = (struct connexionftp *) realloc(p_conn, new_size * sizeof(struct connexionftp));
    (gdb) s
    47	    if (p_conn == NULL)
    (gdb) p p_conn
    $4 = (struct connexionftp *) 0x804b310
    (gdb) p p_conn[0]
    $5 = {host = "fg", '\000' <repeats 252 times>, 
      username = "fg", '\000' <repeats 252 times>, 
      password = "fg", '\000' <repeats 252 times>, port = 21}
    (gdb) p p_conn[1]
    $6 = {host = "\361\t\002", '\000' <repeats 251 times>, 
      username = '\000' <repeats 254 times>, 
      password = '\000' <repeats 254 times>, port = 0}
    (gdb) s
    54	    *curr_size = new_size;
    (gdb) s
    57	    return p_conn;
    (gdb) p *curr_size
    $7 = 2
    (gdb) c
    Continuing.
    
    Breakpoint 2, add_connexion (p_list=0xbffff6e8, size=0xbffff6e4, 
        p_ftp=0x804b008) at ftp.c:76
    76	    copy_connexion(p_list, p_ftp, *size - 1);
    (gdb) p *p_list
    $8 = (struct connexionftp *) 0x804b310
    (gdb) p *p_list[0]
    $9 = {host = "fg", '\000' <repeats 252 times>, 
      username = "fg", '\000' <repeats 252 times>, 
      password = "fg", '\000' <repeats 252 times>, port = 21}
    (gdb) p *p_list[1]
    Cannot access memory at address 0x3
    (gdb) p *size
    $10 = 2
    (gdb) c
    Continuing.
    
    Program received signal SIGSEGV, Segmentation fault.
    0xb7ee6884 in strcpy () from /lib/libc.so.6
    (gdb)
    On peut dire que la fonction add_connexion() est appelée de cette façon :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    struct connexionftp *p_list = NULL;
    struct connexionftp *p_conn = NULL;
    int size = 0;
     
    p_conn = new_connexion();
    add_connexion(&p_list, &size, p_conn);
    p_conn = free_connexion(p_conn);
    Celle-ci est censée copier les champs de p_conn dans une nouvelle case de p_list.

    La fonction new_connexion() demande juste à l'utilisateur de saisir les infos et retourne une pointeur sur la structure connexionftp.

    Je n'arrive pas à trouver à quoi cela peut-être dû...

  2. #2
    Expert éminent sénior
    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
    Points : 13 724
    Points
    13 724
    Par défaut
    D'après ce que je comprend :

    - resize_connexion() :
    dit que p_conn est l'adresse d'un tableau de structure connexionftp

    - add_connexion() :
    plist est l'adresse de l'adresse du tableau de structure.

    - copy_connexion() :
    p_dest est l'adresse de l'adresse du tableau de structure. Alors, qu'est-ce que p_dest[index]->xxxx ? p_dest n'est pas l'adresse d'un tableau de pointeurs sur structure connexionftp.

    On attend (*pdest)[index].xxxx

    D'ailleurs, pourquoi passer l'adresse de l'adresse plutôt que l'adresse à cette fonction ?

    - Sur resize_connexion(), le realloc en cas d'échec est curieusement géré :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        p_conn = (struct connexionftp *) realloc(p_conn, new_size * sizeof(struct connexionftp));
        if (p_conn == NULL)
        {
            *curr_size = 0;
            return NULL;
        }
    En cas d'échec, du realloc(), on perd l'adresse de la mémoire précédemment allouée (et en plus, on prétend que la taille allouée est nulle) -> fuite mémoire
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Membre actif

    Inscrit en
    mars 2003
    Messages
    241
    Détails du profil
    Informations forums :
    Inscription : mars 2003
    Messages : 241
    Points : 235
    Points
    235
    Par défaut
    Alors, j'explique un peu mon code.

    - resize_conexion() :

    Cette fonction attend que l'on lui passe une tableau de structures et change la taille de ce tableau avec la nouvelle taille voulue.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    p_conn = (struct connexionftp *) realloc(p_conn, new_size * sizeof(struct connexionftp));
    if (p_conn == NULL)
    {
        *curr_size = 0;
     
     
        return NULL;
    }
    J'avoue ne pas trop savoir comment gérer ici mais si p_conn (le tableau) est NULL en sortie du realloc, c'est bien que l'on a plus de tableau donc la taille revient à 0.

    - add_conexion() :

    Ajoute une connexion au tableau. Si le tableau est vide, on demande juste un pointeur de structure (get_connexion()), sinon on change la taille du tableau.

    Alors pourquoi passer par l'adresse de l'adresse ? Tout simplement parce que je dois pouvoir modifier l'adresse de la première case du tableau. En effet, comme je l'ai dit, ma fonction main initialise son pointeur de la façon suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    struct connexionftp *p_list = NULL;
    Or si je passe directement ce pointeur, je peux agir sur le contenu pointé mais pas sur l'adresse pointée. Du coup si le réalloc change l'adresse de départ du tableau, je dois pourvoir dire à ce pointeur de pointer ailleurs et donc changer l'adresse vers laquelle il pointe.

    Exemple :

    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
    #include <stdio.h>
     
    void change_adresse(int *p)
    {
      p = NULL;
      printf("Mon pointeur (change_adresse) : 0x%x\n", p);
    }
     
    void change_adresse2(int **p)
    {
      *p = NULL;
      printf("Mon pointeur (change_adresse2) : 0x%x\n", *p);
    }
     
    int main()
    {
      int a = 8;
      int *mon_pointeur = &a;
     
      printf("Adresse de a (main) : 0x%x\n", &a);
     
      change_adresse(mon_pointeur);
      printf("Mon pointeur (main) : 0x%x\n", mon_pointeur);
     
      change_adresse2(&mon_pointeur);
      printf("Mon pointeur (main) : 0x%x\n", mon_pointeur);
    }
    A l'exécution :

    Adresse de a (main) : 0x22cd60
    Mon pointeur (change_adresse) : 0x0
    Mon pointeur (main) : 0x22cd60
    Mon pointeur (change_adresse2) : 0x0
    Mon pointeur (main) : 0x0
    Voilà pourquoi je passe l'adresse de l'adresse.

    - copy_connexion() :

    A l'aide de GDB, on peut voir :

    (gdb) p p_dest[index]
    $7 = (struct connexionftp *) 0x804b310
    (gdb) p p_dest[index]->host
    $6 = "fg", '\000' <repeats 252 times>
    Et si je passe tout le temps l'adresse de l'adresse c'est une question d'harmonisation de la forme des fonctions.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    short add_connexion(struct connexionftp **, int *, struct connexionftp *);
    short del_connexion(struct connexionftp **, int *, const int);
    short modify_connexion(struct connexionftp **, int *, const int);
     
    void copy_connexion(struct connexionftp **, const struct connexionftp * const, const int);
     
    void list_connexions(struct connexionftp **, int *, const short);
    Ainsi je n'ai pas à me rappeler où je dois enlever un pointeur et où je dois le garder, bref toutes les fonctions du fichier ont la même forme.

  4. #4
    Expert éminent sénior
    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
    Points : 13 724
    Points
    13 724
    Par défaut
    Mes remarques du début sur resize_conexion() et add_connexion() n'étaient pas une critique, mais des remarques pour bien situer ce que représentaient ces paramètres dans le but d'arriver à commenter copy_connexion().

    Pour cette dernière, je réitère :
    diogene :
    p_dest est l'adresse de l'adresse du tableau de structure. Alors, qu'est-ce que p_dest[index]->xxxx ? p_dest n'est pas l'adresse d'un tableau de pointeurs sur structure connexionftp.

    On attend (*pdest)[index].xxxx
    diogene :
    D'ailleurs, pourquoi passer l'adresse de l'adresse plutôt que l'adresse à cette fonction ?
    Cette remarque ne s'appliquait qu'à copy_connexion().

    J'avoue ne pas trop savoir comment gérer ici mais si p_conn (le tableau) est NULL en sortie du realloc, c'est bien que l'on a plus de tableau donc la taille revient à 0.
    Non, le tableau existe toujours, à la même adresse que précédemment, et avec les données antérieures au realloc()
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

Discussions similaires

  1. Petit soucis avec un tableau de structures
    Par OVpex dans le forum Débuter
    Réponses: 4
    Dernier message: 22/04/2013, 16h51
  2. Jeu Othello et quelque soucis avec une structure
    Par AliFirat91 dans le forum C
    Réponses: 4
    Dernier message: 26/04/2012, 20h27
  3. quelques soucis avec l'url rewriting
    Par romain_paris dans le forum Apache
    Réponses: 10
    Dernier message: 17/09/2006, 17h51
  4. Quelques soucis avec un lecteur MP3
    Par Guesh13 dans le forum Audio
    Réponses: 3
    Dernier message: 20/02/2006, 15h57
  5. quelques soucis avec word 2000
    Par ramchou dans le forum Word
    Réponses: 3
    Dernier message: 06/09/2004, 19h13

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