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

Réseau C Discussion :

Problème avec redimensionnement tableau


Sujet :

Réseau C

  1. #1
    Membre habitué Avatar de PoZZyX
    Inscrit en
    Août 2005
    Messages
    426
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 426
    Points : 154
    Points
    154
    Par défaut Problème avec redimensionnement tableau
    Bonjour,
    je suis pas trop expert en C mais j'ai quand meme des connaissances de bases et j'essaie de me perfectionner. Je me suis attaqué au redimensionnement de tableau.

    J'ai donc une structure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    typedef struct
    {
            SOCKET socket;
            SOCKADDR_IN sin;
            char nom[255];
            int connexion; 
            int position_x;
            int position_y;       
    } client;
    une fonction pour m'aggrandir mon tableau de cette structure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int aggrandir_tableau(client * clients, long nombre)
    {
        clients = realloc(clients, nombre * sizeof(client));
        if (clients == NULL)
        {
            return 0;            
        } 
        else
        {
            return 1;
        }
    }
    et une boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    client *clients;
    long nombre_clients = 0;
    while(1)
        {
          nombre_clients++;
          aggrandir_tableau(clients, nombre_clients);
          printf("tableau aggrandi...\n");
          strcpy(clients[nombre_clients-1].nom,"test");
          printf("%s", clients[nombre_clients-1].nom);
          getch();
        }
    Mon problème, c'est qu'après 4 ou 5 passage dans la boucle, windows me fait l'erreur : le programme a généré des erreurs...

    Savez-vous d'ou cela peut venir ??? est-ce que je redimensionne correctement ?

    Merci d'avance

  2. #2
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    Salut !

    realloc (arretez-moi si je dis une bêtise) réalloue de la mémoire à une adresse précise...

    comme en l'occurence, tu demandes de plus en plus de mémoire, je pense qu'au bout d'un certain nombre d'itérations la mémoire allouée dépasse sur l'objet suivant le tableau, d'où l'erreur...

    une des solutions serait peut-être de stocker en fait des client* que tu recopierais (très rapide car que des pointeurs) en faisant une nouvelle allocation pour agrandir... enfin, ça vaut ce que ça vaut
    Rédacteur "éclectique" (XML, Cours PHP, Cours JavaScript, IRC, Web...)
    Les Règles du Forum - Mon Site Web sur DVP.com (Développement Web, PHP, (X)HTML/CSS, SQL, XML, IRC)
    je ne répondrai à aucune question technique via MP, MSN ou Skype : les Forums sont là pour ça !!! Merci de me demander avant de m'ajouter à vos contacts sinon je bloque !
    pensez à la balise [ code ] (bouton #) et au tag (en bas)

  3. #3
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PoZZyX
    jJe me suis attaqué au redimensionnement de tableau.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int aggrandir_tableau(client * clients, long nombre)
    {
        clients = realloc(clients, nombre * sizeof(client));
        if (clients == NULL)
        {
            return 0;            
        } 
        else
        {
            return 1;
        }
    }
    Mon problème, c'est qu'après 4 ou 5 passage dans la boucle, windows me fait l'erreur : le programme a généré des erreurs...
    Il faut bien comprendre le fonctionnement de realloc().

    On lui passe l'adresse du bloc à modifier et la taille demandée. Elle retourne l'adresse du nouveau bloc (ou NULL en cas d'échec). Donc la nouvelle valeur doit être récupérée et conservée. Or ta fonction int aggrandir_tableau(client * clients, long nombre) ne retourne pas la nouvelle valeur du pointeur, ce qui fait que vu de l'appelant, on continue à utiliser la valeur initiale et c'est le drame (comportement indéfini, tout peut arriver).

    Il faut donc absolument que la valeur du pointeur de l'appelant soit mise à jour. La fonction aggrandir_tableau() doit se comporter comme realloc(), c'est à dire recevoir l'ancienne valeur (OK, c'est fait) et retourner la nouvelle ou NULL (ça, ça manque). On pourrait aussi passer l'adresse du pointeur, mais c'est tordu.

    D'autre part, il faut faire attention que la réallocation peut échouer. Il faut donc faire la réallocation en 2 temps :
    • demander un nouveau bloc
    • si il est non NULL, remplacer l'ancienne adresse par la nouvelle
    • sinon, prendre des mesures :
      • soit conserver l'ancienne valeur (l'ancien bloc reste valide avec l'ancienne taille).
      • soit libérer le bloc.
    • dans les deux cas, remonter l'information (message, arrêt de l'application...) selon l'importance.
    http://emmanuel-delahaye.developpez.com/notes.htm#realloc

    Enfin, je dirais qu'en conséquence, la fonction aggrandir_tableau() est inutile (surtout avec 2 'g' !). Il faudrait travailler sur le tableau avec un niveau d'abstraction un peu plus haut comme ceci :

    http://emmanuel-delahaye.developpez.com/clib.htm
    Module FARR (Flexible Array)
    Pas de Wi-Fi à la maison : CPL

  4. #4
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Swoög
    ça vaut ce que ça vaut
    Pas grand chose malheureusement. Relire la doc de realloc()...
    Pas de Wi-Fi à la maison : CPL

  5. #5
    Membre habitué Avatar de PoZZyX
    Inscrit en
    Août 2005
    Messages
    426
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 426
    Points : 154
    Points
    154
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    while(1)
        {
          nombre_clients++;
          clients = realloc(clients, nombre_clients * sizeof(client));
          printf("tableau aggrandi...\n");
          strcpy(clients[nombre_clients-1].nom,"test");
          printf("%s", clients[nombre_clients-1].nom);
          getch();
        }
    donc ça serait simplement comme ça (sans la gestion des erreurs que je vais faire ensuite) ??? merci de ton aide

  6. #6
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par PoZZyX
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    while(1)
        {
          nombre_clients++;
          clients = realloc(clients, nombre_clients * sizeof(client));
          printf("tableau aggrandi...\n");
          strcpy(clients[nombre_clients-1].nom,"test");
          printf("%s", clients[nombre_clients-1].nom);
          getch();
        }
    donc ça serait simplement comme ça (sans la gestion des erreurs que je vais faire ensuite) ??? merci de ton aide
    Moui, mais faire un realloc() à chaque fois, c'est carrément lourdingue... Il vaut mieux doubler la taille dès que nécessaire, ça converge plus vite... et puis ta gymastique ++, -1 etc. , c'est du délire... Il faut rester simple.

    Tu n'as pas regardé mon FARR (Flexible ARRay) ? Ca fonctionne comme ça...
    Pas de Wi-Fi à la maison : CPL

  7. #7
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Il y a quelque chose qui me travaille dans ce que tu dis:

    Citation Envoyé par Emmanuel Delahaye
    soit conserver l'ancienne valeur (l'ancien bloc reste valide avec l'ancienne taille). Faux. voir ci-dessous.
    Or la page man dit bien:

    Si realloc() échoue, le bloc mémoire original reste intact, il n'est ni libéré ni déplacé.
    D'ailleurs je suis retourné voir ton flexible array... J'ai remarqué que si ton realloc échoue, tu ne gères pas l'erreur du tout... Tu continues ta fonction comme si de rien était... Tu attends le segmentation fault pour savoir que cela a planté?

    Fonction farr_add:
    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
    if (this->w == this->nb_elem)
          {
             /* grow by 2 */
             size_t const nb_elem = this->nb_elem * 2;
             size_t const size = this->elem_size * nb_elem;
     
             char *const arr = realloc (this->arr, size);
     
    /*fy - ok tu testes si arr != NULL mais si arr==NULL alors
    tu n'as toujours pas de place dans ton tableau*/
             if (arr != NULL) 
             {
                /* clean the end of the array */
                memset (arr + this->elem_size * this->nb_elem
                        ,0
                        ,this->elem_size * this->nb_elem);
     
                /* record the new information */
                this->nb_elem = nb_elem;
                this->arr = arr;
             }
          }
     
    /*fy - Or ici tu vas déborder...*/
          /* record the data into the array */
          {
             size_t const ndx = this->w * this->elem_size;
             memcpy (this->arr + (ndx)
                     ,p_data
                     ,this->elem_size);
          }
          this->w++;
    J'ai dû louper un virage...
    Jc

  8. #8
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    <delestage>
    Pas de Wi-Fi à la maison : CPL

  9. #9
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    Euh, les gars, il faudrait lire la norme jusqu'a la fin. Emmanuel repond lui-meme a sa question:
    If memory for the new
    object cannot be allocated, the old object is not deallocated and its value is unchanged.
    C'est logique, puisque realloc() ne doit pas modifier la valeur de l'ancien emplacement memoire. Elle ne peut pas commencer par faire un free()!

  10. #10
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par DaZumba
    Euh, les gars, il faudrait lire la norme jusqu'a la fin. Emmanuel repond lui-meme a sa question:

    C'est logique, puisque realloc() ne doit pas modifier la valeur de l'ancien emplacement memoire. Elle ne peut pas commencer par faire un free()!
    Ouf, sauvé ! Merci, je vais laisser les gourous dormir.

    FAUSSE ALERTE, Tout va bien, Peace and Love !
    Pas de Wi-Fi à la maison : CPL

  11. #11
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Ahhhh ouffff.... Je commençais à avoir peur...

  12. #12
    Membre habitué Avatar de PoZZyX
    Inscrit en
    Août 2005
    Messages
    426
    Détails du profil
    Informations forums :
    Inscription : Août 2005
    Messages : 426
    Points : 154
    Points
    154
    Par défaut
    Ok merci de votre aide.

    Je n'ai pas consulté des fonctions FARR car je voulais faire par moi-même histoire d'apprendre le fonctionnement.

    Merci (le bouton résolu a disparu ???)

  13. #13
    Expert éminent
    Avatar de Swoög
    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    6 045
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2003
    Messages : 6 045
    Points : 8 339
    Points
    8 339
    Par défaut
    en haut dans outils de la discussion
    Rédacteur "éclectique" (XML, Cours PHP, Cours JavaScript, IRC, Web...)
    Les Règles du Forum - Mon Site Web sur DVP.com (Développement Web, PHP, (X)HTML/CSS, SQL, XML, IRC)
    je ne répondrai à aucune question technique via MP, MSN ou Skype : les Forums sont là pour ça !!! Merci de me demander avant de m'ajouter à vos contacts sinon je bloque !
    pensez à la balise [ code ] (bouton #) et au tag (en bas)

  14. #14
    Membre éclairé Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Ouf, sauvé ! Merci, je vais laisser les gourous dormir.
    Bon ben moi je n'ai toujours pas saisi...(va falloir que je me fasse greffer un cerveau plus rapide).
    En fait je reviens sur les commentaires de Fearyourself concernant la fonction "farr_add".
    Je suis d'accord que dans le cas où "realloc" échoue, l'ancienne zone mémoire reste valide. Or comme dit Fearyourself, le cas "arr == NULL" n'est pas traité, et malgré tout tu continus à ajouter des élements à ton tableau.
    Je ne vois pas où est caché la subtilité dans le code pour ce cas précis...
    Bon je continu quand même de regarder le code pour voir si je trouve.
    Software Failure. Press left mouse button to continue.
    Guru Meditation #0100000C.000FE800

  15. #15
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par crocodilex
    En fait je reviens sur les commentaires de Fearyourself concernant la fonction "farr_add".
    Je suis d'accord que dans le cas où "realloc" échoue, l'ancienne zone mémoire reste valide. Or comme dit Fearyourself, le cas "arr == NULL" n'est pas traité, et malgré tout tu continus à ajouter des élements à ton tableau.
    Je ne vois pas où est caché la subtilité dans le code pour ce cas précis...
    Bon je continu quand même de regarder le code pour voir si je trouve.
    Il faut envisager le cas 'ce code est buggé'.

    "Tout est possible, tout est envisageable".

    Dès que j'ai un peu de temps, je le passe au détecteur de mensonges...
    Pas de Wi-Fi à la maison : CPL

  16. #16
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par crocodilex
    Bon ben moi je n'ai toujours pas saisi...(va falloir que je me fasse greffer un cerveau plus rapide).
    En fait je reviens sur les commentaires de Fearyourself concernant la fonction "farr_add".
    Je suis d'accord que dans le cas où "realloc" échoue, l'ancienne zone mémoire reste valide. Or comme dit Fearyourself, le cas "arr == NULL" n'est pas traité, et malgré tout tu continus à ajouter des élements à ton tableau.
    Je ne vois pas où est caché la subtilité dans le code pour ce cas précis...
    Bon je continu quand même de regarder le code pour voir si je trouve.
    Non ce problème est toujours d'actualité, mon "ouf" était pour le problème sur le realloc, pas le code d'Emmanuel.

    Jc

  17. #17
    Membre éclairé Avatar de crocodilex
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    697
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 697
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par fearyourself
    mon "ouf" était pour le problème sur le realloc
    Pour moi j'ai l'impression que vois dites la meme chose, je cite :
    Citation Envoyé par Emmanuel Delahaye
    soit conserver l'ancienne valeur (l'ancien bloc reste valide avec l'ancienne taille).
    Citation Envoyé par fearyourself
    Si realloc() échoue, le bloc mémoire original reste intact, il n'est ni libéré ni déplacé.
    Citation Envoyé par DaZumba
    If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.
    Donc où est le problème ?
    Software Failure. Press left mouse button to continue.
    Guru Meditation #0100000C.000FE800

  18. #18
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par crocodilex
    Pour moi j'ai l'impression que vois dites la meme chose, je cite :

    Donc où est le problème ?
    Y a pas de problèmes. Simplement, il est possible que mon code (FARR) soit buggé... C'est tout. C'est dans ma TODO-list...

    Hum effectivement, il y a un bug...
    Pas de Wi-Fi à la maison : CPL

  19. #19
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Hum effectivement, il y a un bug...
    Suffit de retouner un FARR_ERR_REALLOCNULL...

    Jc

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

Discussions similaires

  1. un problème avec un tableau d'objet, erreur bete ?
    Par Heero_2040 dans le forum C++
    Réponses: 12
    Dernier message: 13/07/2006, 14h20
  2. Réponses: 5
    Dernier message: 24/05/2006, 09h59
  3. Problème avec un tableau et saut de ligne
    Par ero-sennin dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 08/03/2006, 19h48
  4. Problème avec un tableau de tableau
    Par SubZero2 dans le forum Langage
    Réponses: 4
    Dernier message: 07/12/2005, 16h25
  5. problème avec un tableau dans un insert ...
    Par vbcasimir dans le forum Langage
    Réponses: 3
    Dernier message: 02/11/2005, 15h31

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