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 :

Probleme avec realloc et free


Sujet :

C

  1. #1
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut Probleme avec realloc et free
    Bonjour tout le monde, je suis lycéen et en stage, au cours de ce stage, j ai été chargé de développer un petit programme, qui doit ouvrir un fichier (.wbp), récupérer certaines valeurs inscrites dedans, et les recopier a la suite dans un autre fichier (.keyframe).
    Le tout devant être le plus flexible possible.

    Puisque je ne sais pas combien de valeurs je vais récupérer, j'ai appris sur le tas (en lisant les docs) a utiliser malloc, calloc, realloc et free, et je pense avoir compris le concept.

    Cependant, lorsque je test mon programme, realloc me renvoie systématiquement un pointeur NULL, ce qui me bloque en plein milieu, et quand je passe les realloc, c'est free qui refuse de me renvoyer un pointeur NULL

    Voici le code:
    Mes declarations de variables et define:
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MP "MarkerPosition" 
    #define tcache 64           
    #define tnom 50             
     
    __________________
     
    int main (int argc, char *argv[])
    {
        /*
        int *:
        -tabPos: Tableau Positions, tableau dynamique contenant les positions (MarkerPositions)
        -argv:Nom complet des fichiers wbp a la suite
        -argc:Nombre de fichiers a ouvrir +1
     
        unsigned int:
        -pkmn: touche perso & compteur de .wbp fini (pour la boucle principale)
        -nbrPos: Compteur de positions trouvées
        -end : Sert lors de la recuperation des positions, a detecter quand les chaines recupérées ne sont plus valide afin de sortir de la boucle.
     
        char:
        -nom[]: Nom du fichier .wbp a ouvrir, puis du .keyframe a creer
        -cache[]: Sert pour retrouver les "MarkerPositionX" dans le .wbp
     
        FILE*:
        -wbp: Fichier wbp
        -kf: Fichier KeyFrame
        */
     
        int *tabPos=NULL;
        unsigned int pkmn=1, nbrPos=0, end = 0, curseur=0;
        char nom[tnom]={0}, cache[tcache]={0};
        FILE* wbp=NULL;
        FILE* kf=NULL;
    Ici mon utilisation de calloc (seule fonction fonctionnant):

    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
     
    int * memoryCreate ()       //Allouer la memoire
    //VARIABLES
         //I: /
         //O: tabPos (tableau dynamique)
    {
        int * tabPos = NULL;
        int bcl=0;
        //Allouer tabPos (une case de memoire) avec calloc (pour la mettre a 0)
        printf("-Creation du tableau de memoire...");
        do
        {
            tabPos = calloc (sizeof(int),1);
            bcl=bcl+1;
            if (tabPos==NULL && bcl>3)  //Si tabPos n'a toujours pas été alloué au bout de trois tentatives
            {
                printf("FAIL\nAllocation de mémoire impossible\nErreur %d\n__________\n", errno);
                exit(EXIT_FAILURE); //Indiquer l erreur et sortir du programme
            }
        }while (tabPos == NULL);  //Tant que la memoire n'a pas été alloué
        printf("OK\n");
        return tabPos;
    }
    Ici la fonction utilisant realloc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int * tabUp (int* tabPos, int nbrPos)
    {
        int * save=NULL;
        printf("Reallocation...");
        //Reallouer tabPos avec une case de plus
        do
        {
            save = (int *) realloc (tabPos, nbrPos * sizeof(int));
        }while (save == NULL);
        printf("OK\n");
        return (int *) save;
    }
    Et mon free:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    //Liberer la memoire
                printf("Liberation de la memoire...");
                while (tabPos!=NULL)
                {
                    free(tabPos);
                }
                printf("OK\n");
    Je travaille sous Windows avec Code::Blocks, les seuls messages d'erreurs sont deux bout de codes déclaré inatteignable, mais n'ayant aucun lien avec ces fonctions (l'un est le return 0; precedé de exit(EXIT_SUCCESS);, vu que C::B rale sans son return 0;, et l'autre est dans une tout autre fonction, un if suivant une boucle, je ne vois pas pourquoi il me le déclare inatteignable, mais cette partie la fonctionnant, ce n'est pas ma priorité...

    TLR: Je n'arrive pas a utiliser realloc correctement, j'ai beau comparer a la doc je ne trouve pas mon erreur: que faire?

  2. #2
    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
    Sur le free() :
    free(tabPos);ne peut pas modifier tabPos, donc à fortiori le mettre à NULL. Donc simplement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    //Liberer la memoire
      printf("Liberation de la memoire...");
      free(tabPos);
      tabPos = NULL ; // si besoin
      printf("OK\n");
    Sur memoryCreate () :
    - Si l'allocation a échoué, il n'y a pratiquement aucune chance qu'elle réussisse ensuite presque immédiatement, donc la boucle n'a pas franchement d'efficacité.

    Sur tabUp() :
    - Même remarque que pécédemment.
    - Il n'y a aucune raison que le realloc() échoue pour des tailles raisonnables. Il faut donc vérifier que
    * le paramètre tabPos correspond bien à une valeur retournée par malloc()/calloc()/realloc()
    * le paramètre nbrPos est strictement positif et de valeur "raisonnable".
    - Note : les cast en (int*) sont superflus.

  3. #3
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    J'ai testé ta fonction memorycreate, elle est en sortie en succès. idem pour tabUp.

    Free ne met pas le pointeur à NULL, il libère juste l'espace mémoire. C'est à toi de le remettre à NULL.

    Si malloc / calloc / realloc échoue, c'est en général parce qu'il n'y a plus de mémoire disponible. Ca ne sert donc à rien de les appeler en boucle puisqu'il y a peu de chance que de la mémoire se libère aussi rapidement que cela. Il faudrait éventuellement attendre un peu.

    Je travaille sous Windows avec Code::Blocks, les seuls messages d'erreurs sont deux bout de codes déclaré inatteignable, mais n'ayant aucun lien avec ces fonctions (l'un est le return 0; precedé de exit(EXIT_SUCCESS);, vu que C::B rale sans son return 0;, et l'autre est dans une tout autre fonction, un if suivant une boucle, je ne vois pas pourquoi il me le déclare inatteignable, mais cette partie la fonctionnant, ce n'est pas ma priorité...
    Je n'ai pas compris grand chose à ce paragraphe. Il faut savoir que exit() quitte le programme donc si un return suit un exit(), il ne sert à rien et ne sera jamais exécuté.

  4. #4
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Bonjour,

    Realloc ne s'utilise pas comme ca :
    Le mettre dans une boucle ne sert a rien
    En general, on re-utilise le meme buffer en cas de succes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    save = realloc (tabPos, ...)
     
    if (save != NULL)
    {
      tabPos = save;
    }
    else
    {
      traitement de l'erreur;
    }
    Bien sur, pour cela, il faut pouvoir modifier le pointeur, et donc passer en parametre a ta fonction un int **.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  5. #5
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Citation Envoyé par diogene Voir le message
    Sur le free() :
    free(tabPos);ne peut pas modifier tabPos, donc à fortiori le mettre à NULL. Donc simplement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    //Liberer la memoire
      printf("Liberation de la memoire...");
      free(tabPos);
      tabPos = NULL ; // si besoin
      printf("OK\n");
    Arg le con, effectivement free ne retourne aucune valeur
    Est ce qu il y a un moyen de verifier que la libération a été effectué?

    Citation Envoyé par diogene Voir le message
    Sur memoryCreate () :
    - Si l'allocation a échoué, il n'y a pratiquement aucune chance qu'elle réussisse ensuite presque immédiatement, donc la boucle n'a pas franchement d'efficacité.
    Tellement évident que je n y avait pas pensé >_>
    Je vais modifier ca et renvoyer une valeur d'erreur si l allocation ne marche pas

    Citation Envoyé par diogene Voir le message
    Sur tabUp() :
    - Même remarque que précédemment.
    - Il n'y a aucune raison que le realloc() échoue pour des tailles raisonnables. Il faut donc vérifier que
    * le paramètre tabPos correspond bien à une valeur retournée par malloc()/calloc()/realloc()
    * le paramètre nbrPos est strictement positif et de valeur "raisonnable".
    - Note : les cast en (int*) sont superflus.
    Je viens de verifier, je peux certifier qu'il s'agit bien d'une valeur de retour de calloc
    nbrPos est égal au nombres de valeur déjà recupéré +1, et lorsque le programme tombe dans une boucle infinie, il est égal a 2

    Citation Envoyé par Bktero Voir le message
    Je n'ai pas compris grand chose à ce paragraphe. Il faut savoir que exit() quitte le programme donc si un return suit un exit(), il ne sert à rien et ne sera jamais exécuté.
    En fait, C::B se met a hurler si le main ne se finit pas par return 0;, donc pour éviter de le mettre et l'enlever sans arrêt, je le laisse et me prend donc un warning, j'ai juste dit ca pour montrer quelles sont les erreur renvoyé par le compilateur

    Citation Envoyé par gangsoleil Voir le message
    En general, on re-utilise le meme buffer en cas de succes :
    Bon, je vais refaire mes fonction, je vois que mes boucles posent toutes problèmes

    Citation Envoyé par gangsoleil Voir le message
    Bien sur, pour cela, il faut pouvoir modifier le pointeur, et donc passer en parametre a ta fonction un int **.
    int ** --> Tableau de pointeur?
    Si j a bien compris on ne les utilise que lorsque l'on veux faire des tableaux dynamique a deux dimension nan?

  6. #6
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    (Je sais que le double post c'est mal, mais je pense qu un edit ne fera qu'agrandir inutilement un post déjà très (trop?) grand)

    Bon, j'ai corrigé mon code grâce a vous (les boucles sont remplacé par des renvoi de code d'erreur, j'ai adapté le main pour les traiter, j'ai résolu les warnings de code inatteignable...) et je vous remercie déjà pour cela

    Je viens de tester, mes reallocations successives se font sans problème pendant 3/4 tour de boucle, et d'un coup me saute a la gueule, est-ce que errno contient quelque chose en cas d'erreur sur realloc?

    Autre problème, mon free(tabPos) me fait planter le programme et Windows m'affiche son habituel message inutile, j'avoue être perdu.

    Voici les nouvelles fonctions et les parties utile de mon main:
    La partie utilisant tabUp:
    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
     
    //Incrementer nbrPos
                            nbrPos=nbrPos+1;
     
                            //Augmenter la taille de tabPos
                            save=tabUp(tabPos, nbrPos);
                            //Si la reallocation se passe sans probleme
                            if (save!=NULL && save!= (int *)-1)
                            {
                                //Valider la reallocation et continuer
                                tabPos=save;
                            }
                            //Sinon
                            else
                            {
                                printf("/!\\Une erreur dans l'allocation s'est produite, les données acquises sont gardees, mais il peut manquer les données suivantes\n");
                                //Sortir de la boucle sans modifier tabPos, et en remettant nbrPos a sa valeur precedente pour eviter des erreurs
                                nbrPos=nbrPos-1;
                                end=-1;
                            }
    La partie contenant le free, le premier printf s'affiche, le second n'en a pas le temps, ce qui me laisse penser que c'est le free qui fait tout planter.
    Pour quelles raisons un free peut faire planter un programme?
    :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    //Liberer la memoire
            printf("Liberation de la memoire...");
            free(tabPos);
            //Vraiment aucun moyen de verifier si tout c'est bien passé?
            tabPos=NULL;
            printf("OK\n");
    tabUp, fonctionne environ 4 fois avant de ne plus reallouer, et je suis sur que tabPos correspond bien a mon allocation par calloc, je vais verifier en continu toute les valeurs de nbrPos, mais ce serait surprenant qu il dépasse (nombre de valeurs recupéré + 1):
    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
     
    int * tabUp (int* tabPos, int nbrPos)
    {
        int * save=NULL;
        printf("Reallocation...");
        //Reallouer tabPos avec une case de plus
        save = (int *) realloc (tabPos, nbrPos * sizeof(int));
        if (save == NULL)
        {
            printf("FAIL\n");
            return (int *) -1;
        }
        printf("OK\n");
        return (int *) save;
    }
    TL: DR:
    -Mon free(tabPos) me fait planter le programme et afficher un message d'erreur windows sans informations, pourtant je crois respecter la doc
    -Mes realloc plantes abruptement après avoir réussi plusieurs fois
    -Est ce qu il y a moyen de verifier que free() a fonctionné?
    -Est ce que realloc () inscrit quelque chose d utilisable dans errno? (La doc me laisse perplexe vu qu elle ne mentionne pas du tout errno)
    -Meme question pour free

  7. #7
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Que penses-tu du code suivant :
    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
     
    int tabUp (int** tabPos, int nbrPos)
    {
        int * save=NULL;
        int return_value;
     
        printf("Reallocation...");
        //Reallouer tabPos avec une case de plus
        errno = 0;
        save = realloc (*tabPos, nbrPos * sizeof(int));
     
        if (save == NULL)
        {
            printf("Realloc failure. Errno : %d, %s\n", errno, strerror(errno) );
            return_value = -1;
        }
        else
        {
            printf("OK\n");
            *tabPos = save;
            return_value = 0; /* Je ne sais pas ce que tu veux comme valeur de retour */
        }
     
        return return_value;
    }

    Citation Envoyé par DrakaSAN Voir le message
    -Est ce qu il y a moyen de verifier que free() a fonctionné?
    -Est ce que realloc () inscrit quelque chose d utilisable dans errno? (La doc me laisse perplexe vu qu elle ne mentionne pas du tout errno)
    free ne peut pas ne pas fonctionner.
    En cas d'erreur de malloc, la valeur retournee est NULL, mais la zone memoire prealablement allouee est toujours valide. Pour errno, je ne sais pas, mais dans le doute, tu peux toujours l'afficher.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  8. #8
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Que penses-tu du code suivant :
    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
     
    int tabUp (int** tabPos, int nbrPos)
    {
        int * save=NULL;
        int return_value;
     
        printf("Reallocation...");
        //Reallouer tabPos avec une case de plus
        errno = 0;
        save = realloc (*tabPos, nbrPos * sizeof(int));
     
        if (save == NULL)
        {
            printf("Realloc failure. Errno : %d, %s\n", errno, strerror(errno) );
            return_value = -1;
        }
        else
        {
            printf("OK\n");
            *tabPos = save;
            return_value = 0; /* Je ne sais pas ce que tu veux comme valeur de retour */
        }
     
        return return_value;
    }
    Je ne comprend pas pourquoi tu met int** et non int*?
    int ** c'est un tableau a deux dimensions, ce que je veux est juste un tableau contenant une suite de valeur, donc une seule dimension
    (Ou alors faut que je reprenne toute les docs que j ai trouvé a zero et tout relire et tester)

    Je test ça dès que j'ai le temps (je ne fais malheureusement pas que du code) et j'edit pour te dire ce que ça donne

    EDIT: Pour la valeur de retour, tu a bien fait de me faire remarquer que je ne l'ai pas indiqué
    tabUp doit renvoyer tabPos réaloué

    Citation Envoyé par gangsoleil Voir le message
    free ne peut pas ne pas fonctionner.
    Bon bah comme ca je suis fixé x)
    Mais dans ce cas pourquoi windows plante après entre un free et un printf?

    Citation Envoyé par gangsoleil Voir le message
    En cas d'erreur de malloc, la valeur retournee est NULL, mais la zone memoire prealablement allouee est toujours valide. Pour errno, je ne sais pas, mais dans le doute, tu peux toujours l'afficher.
    Je suppose que tu voulais dire realloc et non malloc, et j'arrive déja a recuperer le fait qu il y ait une erreur, ce que je voudrait, c'est un moyen de savoir quel est l'erreur.

    Je vais voir si il y a une doc sur errno, ils doivent bien dire par quelles fonctions il est modifié.

  9. #9
    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
    free(p) peut faire planter si
    - p est une valeur non NULL qui n'a pas été obtenue par malloc() et compagnie (ou a été modifiée ensuite évidemment)
    - la zone pointée par p a déjà été libérée par un free()

    La fonction tabUp() ne semble pas en cause, mais pourquoi pas simplement
    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
    int * tabUp (int* tabPos, int nbrPos)
    {
       return realloc (tabPos, nbrPos * sizeof *tabPos);
    }
     
    ....
       //Augmenter la taille de tabPos
       printf("Reallocation...");           // pour tester
       save=tabUp(tabPos, nbrPos+1);
       //Si la reallocation se passe sans probleme
       if (save!=NULL)
       {
          //Valider la reallocation et continuer
          tabPos=save;
          nbrPos++;
          printf("Reallocation OK\n");      // pour tester
       }
       //Sinon
       else
       {
           printf("/!\\Une erreur dans l'allocation s'est produite, les données acquises sont gardees, mais il peut manquer les données suivantes\n");
           //Sortir de la boucle sans modifier tabPos, et en remettant nbrPos a sa valeur precedente pour eviter des erreurs
           end=-1;
       }
    L'erreur est sans doute ailleurs. Donc, il faudrait plutôt montrer plus de code dans la partie du programme qui utilise ces fonctions.

  10. #10
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Citation Envoyé par diogene Voir le message
    free(p) peut faire planter si
    - p est une valeur non NULL qui n'a pas été obtenue par malloc() et compagnie (ou a été modifiée ensuite évidemment)
    - la zone pointée par p a déjà été libérée par un free()
    Bon bah ca me donne des pistes de recherche, mais je sais déja qu'il n y a pas d'autre free dans mon main

    Citation Envoyé par diogene Voir le message
    La fonction tabUp() ne semble pas en cause, mais pourquoi pas simplement
    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
    int * tabUp (int* tabPos, int nbrPos)
    {
       return realloc (tabPos, nbrPos * sizeof *tabPos);
    }
     
    ....
       //Augmenter la taille de tabPos
       printf("Reallocation...");           // pour tester
       save=tabUp(tabPos, nbrPos+1);
       //Si la reallocation se passe sans probleme
       if (save!=NULL)
       {
          //Valider la reallocation et continuer
          tabPos=save;
          nbrPos++;
          printf("Reallocation OK\n");      // pour tester
       }
       //Sinon
       else
       {
           printf("/!\\Une erreur dans l'allocation s'est produite, les données acquises sont gardees, mais il peut manquer les données suivantes\n");
           //Sortir de la boucle sans modifier tabPos, et en remettant nbrPos a sa valeur precedente pour eviter des erreurs
           end=-1;
       }
    Je vais tester aussi

    Citation Envoyé par diogene Voir le message
    L'erreur est sans doute ailleurs. Donc, il faudrait plutôt montrer plus de code dans la partie du programme qui utilise ces fonctions.
    Voici le main entier, s'il y a une fonction que tu veux voir, demande la:

    Main:
    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
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
     
    int main (int argc, char *argv[])
    {
        /*
        int *:
        -tabPos: Tableau Positions, tableau dynamique contenant les positions (MarkerPositions)
        -argv:Nom complet des fichiers wbp a la suite
        -argc:Nombre de fichiers a ouvrir +1
     
        unsigned int:
        -pkmn: touche perso & compteur de .wbp fini (pour la boucle principale)
        -nbrPos: Compteur de positions trouvées
        -end : Sert lors de la recuperation des positions, a detecter quand les chaines recupérées ne sont plus valide afin de sortir de la boucle.
     
        char:
        -nom[]: Nom du fichier .wbp a ouvrir, puis du .keyframe a creer
        -cache[]: Sert pour retrouver les "MarkerPositionX" dans le .wbp
     
        FILE*:
        -wbp: Fichier wbp
        -kf: Fichier KeyFrame
        */
     
        int *tabPos=NULL, *save=NULL;
        unsigned int pkmn=1, nbrPos=0, end = 0, curseur=0;
        char nom[tnom]={0}, cache[tcache]={0};
        FILE* wbp=NULL;
        FILE* kf=NULL;
     
        fileValid(argv, argc);
     
        //Boucle principale
        printf("Debut de la boucle principale\n");
        do
        {
            if (nameValid(argv[pkmn])==0 && argc > 1)
            {
     
                printf("Recuperation du nom...");
                //Recuperation du nom du fichier .wbp
                strcpy(nom, argv[pkmn]);
                printf("OK\n");
     
                tabPos = memoryCreate();
                if (tabPos != ((int *) -1))
                {
                    //Reperage de MP et placage du curseur a cet endroit
                    curseur = findMP(nom);
                    if (curseur != -1)
                    {
                        wbp = wbpOpen(nom);
                        fseek(wbp, curseur, SEEK_SET);
     
                        printf("\nDebut des operations\n");
                        //Boucle
                        do
                        {
                            //Initialiser end
                            end = 0;
     
                            fscanf (wbp, "%s", cache);
                            printf("%s\n", cache);
     
                            //Si la chaine est du type MP=...
                                //strncmp compare uniquement MP
                            if (strncmp(cache, MP, strlen(MP)) == 0)
                            {
                                printf("Chaine MPX\n");
        //DEBUG_PAUSE
        getchar();
                                tabPos[nbrPos]=ChainMPX(cache);
                            }
                            //Sinon si la chaine est un chiffre
                            else if (isInt(cache)==0)
                            {
                                printf("Chaine INT\n");
                                tabPos[nbrPos]= (int) ChainINT(cache);
                                printf("tabPos[nbrPos] = %d\n", tabPos[nbrPos]);
                            }
                            else
                            {
                                printf("Fin des acquisitions\n");
        //DEBUG_PAUSE
        getchar();
                                end=1;
                            }
        //DEBUG_PAUSE
        getchar();
                            //Incrementer nbrPos
                            nbrPos=nbrPos+1;
     
                            //Augmenter la taille de tabPos
                            save=tabUp(tabPos, nbrPos);
                            //Si la reallocation se passe sans probleme
                            if (save!=NULL)
                            {
                                //Valider la reallocation et continuer
                                tabPos=save;
                            }
                            //Sinon
                            else
                            {
                                printf("/!\\Une erreur dans l'allocation s'est produite, les données acquises sont gardees, mais il peut manquer les données suivantes\n");
                                //Sortir de la boucle sans modifier tabPos, et en remettant nbrPos a sa valeur precedente pour eviter des erreurs
                                nbrPos=nbrPos-1;
                                end=-1;
                            }
     
        //DEBUG_PAUSE
        getchar();
                            //Sortir de la boucle si la chaine n est pas MP et n est pas un chiffre
                        }while (end == 0);
                        printf("Fin des operations\n");
                        printf("Fermeture du .wbp...");
                        //Fermer le .wbp
                        fclose(wbp);
                        printf("OK\n");
        //DEBUG_PAUSE
        getchar();
                        //Trier les positions par ordre croissant
                        tri(tabPos, nbrPos);
        //DEBUG_PAUSE
        getchar();
                        //Changer le nom pour .keyframe
                        KeyName(nom);
        //DEBUG_PAUSE
        getchar();
     
                        printf("Ouverture du .keyframe...");
                        //Ouvrir un .keyframe avec le meme nom
                        kf = fopen(nom, "w");
                        printf("OK\n");
                        //Placer les positions separée par '\n'
     
                        writeVal(kf, tabPos, nbrPos);
     
                        printf("Fermeture du .keyframe...");
                        //Fermer le .keyframe
                        fclose (kf);
                        printf("OK\n");
                    }
                }
            }
            //Liberer la memoire
            printf("Liberation de la memoire...");
            free(tabPos);
            tabPos=NULL;
            printf("OK\n");
     
            //Incrementer pkmn (un wbp fini)
            pkmn=pkmn+1;
            //Sortir de la boucle si il n y a plus d autres .wbp
        } while (pkmn <= (argc -1) );
        //Fin
        printf("\nwbp transforme: %d/%d\nend", pkmn-1, argc-1);
    //DEBUG_PAUSE
    getchar();
        exit(EXIT_SUCCESS);
    }

  11. #11
    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
    int ** c'est un tableau a deux dimensions, ce que je veux est juste un tableau contenant une suite de valeur, donc une seule dimension
    C'est un cas particulier. int** est un pointeur sur un pointeur sur int. Il peut donc contenir aussi bien l'adresse d'un pointeur sur int que l'adresse du premier élément d'un tableau de pointeur sur int (cas que tu évoques).
    Ici, dans le code de gangsoleil, il permet de modifier dans le programme appelant l'adresse de départ de la zone allouée : *tabPos = save; .

    c'est un moyen de savoir quel est l'erreur.
    Avec realloc(), il n'y a pas 36 possibilités : ou la réallocation a réussi (et le retour est différent de NULL) ou elle a échoué (et le retour est NULL). Donc la valeur de retour suffit pour savoir ce qui s'est passé.

  12. #12
    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
    Je soupçonne un problème avec nbrPos : en fin de la boucle principale, la mémoire est libérée, tabPos est remis à NULL, mais nbrPos n'est pas remis à 0 pour la boucle suivante.

    Alors ensuite le tabPos[nbrPos]= ... suivant (et qui est avant la reallocation) sort du tableau de 1 élément alloué par memoryCreate()

  13. #13
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Citation Envoyé par diogene Voir le message
    C'est un cas particulier. int** est un pointeur sur un pointeur sur int. Il peut donc contenir aussi bien l'adresse d'un pointeur sur int que l'adresse du premier élément d'un tableau de pointeur sur int (cas que tu évoques).
    Ici, dans le code de gangsoleil, il permet de modifier dans le programme appelant l'adresse de départ de la zone allouée : *tabPos = save; .
    Je viens de tester le code de GangSoleil, et effectivement je comprend bien mieux ce qu il fait

    Citation Envoyé par diogene Voir le message
    Avec realloc(), il n'y a pas 36 possibilités : ou la réallocation a réussi (et le retour est différent de NULL) ou elle a échoué (et le retour est NULL). Donc la valeur de retour suffit pour savoir ce qui s'est passé.
    Mais on a aucune explication quand au pourquoi l'allocation echoue, c'est ce qui me perturbe.

    Bon, j'ai testé les codes en même temps, en montant nbrPos jusqu’à 1000 (valeur que je ne pense pas atteindre), et tout se passe sans problème, je vais voir en intégrant complètement dans mon programme

    EDIT

    Envoyé par diogene Voir le message
    Je soupçonne un problème avec nbrPos : en fin de la boucle principale, la mémoire est libérée, tabPos est remis à NULL, mais nbrPos n'est pas remis à 0 pour la boucle suivante.

    Alors ensuite le tabPos[nbrPos]= ... suivant (et qui est avant la reallocation) sort du tableau de 1 élément alloué par memoryCreate()
    Et tu a parfaitement raison, heureusement que je ne suis que stagiaire >_>
    Mais ce problème n'apparait que lors d'un changement de fichier.

    Bon, je viens de mettre le code de GangSoleil, et réadapter mon main, et la reallocation recommence a planter au bout de quelques tours de boucles...

    Le problème ne doit donc pas venir de tabUp

    Je vais voir les valeurs qui y entrent a chaque tours pour voir s'il y a quelque chose d'anormal

    EDIT bis:
    Bon, les valeurs de nbrPos sont bonnes, aucune incrémentation caché avant tabUp, mais il plante systématiquement a nbrPos=3...
    Et après, c est lors du free qu'il plante trois fois sur quatre en une vingtaine d'essai Oo

    Je vais voir en mettant deux fichier a convertir, si j'arrive a passer le premier free

  14. #14
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Bonjour tout le monde

    J'ai beau chercher une explication, les résultats de mon code sont tellement étrange que je suis complètement perdu.
    Les reallocation plantent systématiquement quand nbrPos=3, sur tout les essais que j'ai fait, pas moyen d'avoir autre chose

    Et mes free me lancent des erreurs windows aléatoirement, et les messages d' "aide" sont parfaitement inutile ("windows cherche une solution a votre problème").

    Le plus étrange, c'est que le programme peux marcher jusqu'au bout sans problème comme planter dès le premier free, quelque soit le nombre de fichier.

    Pourtant j'ai bien vérifié que tabPos ne reçoit aucune valeur d'adresse sans passer par un realloc ou un calloc, et que ce sont bien les cases qui reçoivent les valeurs récupérées

    De plus, le dernier fichier ouvert a sa dernière valeur acquise de remplacé par une valeur aléatoire --> j'accède a une case non alloué, pourtant l'algo reste le même...

    Je suis a peu près sur que j'ai une erreur toute bête quelque part, mais je ne la vois pas, pourtant ça fait bien une dizaine de fois que je relis mon code ligne par ligne en suivant l'ordre d'execution et en notant toute les valeurs successives et que je ne trouve rien X(

    Je poste mon code en entier, je pense que ça doit venir d'une autre fonction que main ou tabUp...

    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
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MP "MarkerPosition" //A changer si les wbp ne presente se presentes plus sous la forme "MarkerPositionX=Y"
    #define tcache 64           //Taille du cache, doit etre egal a la taille de nom + strlen(MP)
    #define tnom 50             //Taille de nom, a changer si les noms des fichiers sont trop importants
     
    //_____________________________________________________________________________________________________________________________FONCTIONS:
     
    void fileValid (char *argv[], int argc)     //Affiche tout les fichiers a traiter, pas d interet majeur dans l'algo
    //VARIABLES
         //In:
            //argv: Nom des fichier
            //argc: Nombre de fichier +1
    {
        int pkmn=1;     //Initialisation a 1 pour ne pas afficher argv[0] qui correspond au programme lui meme
     
        printf("Fichiers a ouvrir:\n");
        do
        {
            printf("%s\n", argv[pkmn]); //Afficher le nom du fichier
            pkmn=pkmn+1;                //Passer au fichier suivant
        }while (pkmn<argc);             //Jusqu a avoir fait tout les fichiers
    }
     
    int nameValid( char argv[])                   //Verifie que le nom ne va pas declencher un overflow
    //VARIABLES
         //In:
            //argv: Nom du fichier
     
         //Out: 0 si le nom est valide, -1 sinon
    {
        printf("-Verification du nom...");
        //Si la taille ne depasse pas la taille de nom
        if (strlen(argv)+1<tnom)
        {
            printf("OK\n");
            return 0;   //Retourner 0 (fonctionnement normal)
        }
        printf("Nom invalide, passage au fichier suivant\n\n");
        return -1;      //Sinon retourner -1 (trop long)
    }
     
    FILE * wbpOpen (char nom [])                   //Ouvre le fichier .wbp (en mode lecture, aucune modification n est a faire dessus)
    //VARIABLES
         //I: nom
         //O: pointeur vers wbp
    {
        FILE * wbp;
        int bcl=0;
        printf("-Ouverture du fichier %s...", nom);
     
        do
        {
            wbp = fopen (nom, "r"); //Ouvrir le .wbp
            bcl=bcl+1;
            //Si le fichier n' a pas été ouvert apres 3 tentatives
            if (wbp == NULL && bcl>=3)
            {
                printf("FAIL\nImpossible d ouvrir %s\nErreur %d\n__________\n", nom, errno);
                exit(EXIT_FAILURE); //Au bout de trois erreurs successives, afficher l'echec et sortir du programme
            }
        }while (wbp==NULL); //Tant que le .wbp n'a pas été ouvert
        printf("OK\n");
        return wbp;         //Retourner le wbp
    }
     
    int * memoryCreate ()       //Allouer la memoire
    //VARIABLES
         //I: /
         //O: tabPos (tableau dynamique)
    {
        int * tabPos = NULL;
        //Allouer tabPos (une case de memoire) avec calloc (pour la mettre a 0)
        printf("-Creation du tableau de memoire...");
        tabPos = calloc (sizeof(int),1);
        if (tabPos==NULL)  //Si tabPos n'a toujours pas été alloué au bout de trois tentatives
            {
                printf("FAIL\nAllocation de mémoire impossible\nErreur %d\n__________\n", errno);
                return (int *) -1; //Indiquer l erreur et sortir du programme
            }
        printf("OK\n");
        return tabPos;
    }
     
    int findMP(char nom[])      //Repere MP dans le .wbp et retourne sa position
    //VARIABLES
         //I: nom
         //O: nombre de caracteres avant les premieres valeures a recuperer
    {
        char cache [strlen(MP)+2]={0};
        int pkmn=0;
        FILE * wbp=NULL;
        wbp=wbpOpen(nom);
     
        printf("-Recherche de %s...", MP);
        //Boucle
     
        do
        {
            //Lire le nombre de caractere neccessaire pour MP
            pkmn= (int) fgets ( cache, strlen(MP)+1, wbp );
            //Comparer cette chaine a MP et sortir de la boucle quand la comparaison est bonne
    /*
    Puisque fgets s arrete de lire lors d un '\n', on est assuré de
    passer tout le texte avant de tomber sur le premier MP
    */
     
            //Si la fin du fichier a été récupéré avant de trouver MP
            if (pkmn == (int) NULL)
            {
                printf("FAIL\nImpossible de trouver %s dans %s\nErreur %d\n__________\n",MP, nom, errno);
                return -1; //Indiquer l absence de MP et quitter le programme
            }
        }while (strcmp(cache, MP)!=0);
     
        //Passer les caracteres jusqu'a =
        while (fgetc(wbp) != '=');
        printf("OK\n");
        pkmn=ftell(wbp);//Recuperer la position de MP directement là ou la lecture sera faite
        fclose (wbp);   //Fermer le fichier
        return pkmn;    //Retourner la position de MP
    }
     
    int MPXGetEqual (char cache[])
    //VARIABLES
         //I: cache
         //O: egal
    {
    //Supprimer "MarkerPositionX=" en decalant les cases de cache[]
        //Recuperation de l emplacement du =
        int egal;
        printf("--Detection de '='...");
        //Comparer chaque caractere de cache jusqu a trouver '=' ou depasser la taille du cache
        do
        {
            egal=egal+1;
        }while (cache[egal]!='=' && egal < tcache);
        //Si la taille du cache a été dépassé
        if (egal>=tcache)
        {
            printf("FAIL\nErreur dans la detection");
            exit(EXIT_FAILURE);
        }
        egal=egal+1;
        printf("OK\n");
        return egal;
    }
     
    char * MPXSuppr (int egal, char cache[])
    //VARIABLES
         //I: egal, cache
         //O: cache
    {
            int bcl = 0;
        //Suppression de MarkerPosition
        printf("--Suppression de MP...");
     
        //Decaler le contenu de cache tant que l on ne depasse pas de cache
        do
        {
            cache[bcl]=cache[bcl+egal];
            bcl=bcl+1;
        }while (bcl < (tcache - (2*egal)));
        printf("OK\n---\"%s\"\n", cache);
        return cache;
     
    }
     
    int MPXGetVal (char cache[])
    //VARIABLES
         //I: cache
         //O: tabPos[nbrPos]
    {
        int pkmn=0;
        printf("--Recuperation de la valeur...");
        //Recuperer Y
        pkmn = (atoi(cache))/1200;
        printf("OK\n");
        printf("---\"%d\"\n", pkmn);
        return pkmn;
    }
     
    int ChainMPX (char cache [])
    //VARIABLES
         //I: tabPos, nbrPos, cache
         //O: pkmn
    {
        int pkmn = 0;
        cache = MPXSuppr(MPXGetEqual (cache),cache);
     
        pkmn=MPXGetVal(cache);
        return pkmn;
    }
     
    int isInt (char cache[])
    //VARIABLES
         //I: cache
         //O: 0 si le cache est un int, -1 sinon
    {
        int bcl=0;
        //Pour toute la chaine
        printf("--IsInt...");
        do
        {
            //Si le caractere n'est pas un chiffre
            if ((cache[bcl]<'0')||(cache[bcl]>'9'))
            {
                printf("FAIL\n");
                //Sortie de la fonction et code d erreur
                return -1;
            }
            bcl=bcl+1;
        }while (cache[bcl] != '\0');
        //S il n y a pas eu d erreur jusqu a la fin de la chaine, retourner le code de validation
        printf("OK\n");
        return 0;
    }
     
    int ChainINT (char cache[])
    //VARIABLES
         //I: cache
         //O: pkmn
    {
        int pkmn = 0;
        printf("--Recuperation de la valeur...");
        //Le convertir et l enregistrer dans tabPos
        printf("\n---Avant conversion: %s\n", cache);
        pkmn=atoi(cache);
        printf("---Apres conversion: %d\n", pkmn);
        pkmn=pkmn/1200;
        printf("---Apres division : %d\n", pkmn);
        //Indiquer que la chaine etait bonne
        printf("OK\n");
        printf("---\"%d\"\n", pkmn);
        return pkmn;
    }
     
    /*
    //VERSION DrakaSAN:
    int * tabUp (int* tabPos, int nbrPos)
    //VARIABLES
         //I: tabPos, nbrPos
         //O: Pointeur vers tabPos réalloué
    {
        int * save=NULL;
        printf("Reallocation...");
        //Reallouer tabPos avec une case de plus
        save = (int *) realloc (tabPos, nbrPos * sizeof(int));
        if (save == NULL)
        {
            printf("FAIL\n");
            return NULL;
        }
        printf("OK\n");
        return (int *) save;
    }
    */
     
    //VERSION GANGSOLEIL (http://www.developpez.net/forums/d1240484/c-cpp/c/debuter/probleme-realloc-free/#post6782805)
    int tabUpGS (int** tabPos, int nbrPos)
    {
        int * save=NULL;
        int return_value;
     
        printf("Reallocation...");
        //Reallouer tabPos avec une case de plus
        save = realloc (*tabPos, nbrPos * sizeof(int));
     
        if (save == NULL)
        {
            printf("Fail\n");
            return_value = -1;
        }
        else
        {
            printf("OK\n");
            *tabPos = save;
            return_value = 0;
        }
     
        return return_value;
    }
     
    void tri (int * tabPos, int nbrPos)
    //VARIABLES
         //I: tabPos, nbrPos
         //O: /
    {
        //VARIABLES
        //cache: Sert a deplacer les variables a trier
        int cache=0, bcl=0;
        //Trier tabPos
        printf("-Tri des valeurs...");
        printf("\n");
        do
        {
            if (tabPos[bcl] > tabPos[bcl+1])
            {
                cache = tabPos[bcl+1];
                tabPos[bcl+1] = tabPos[bcl];
                tabPos[bcl] = cache;
                bcl=bcl-2;
                if (bcl<0)
                {
                    bcl=0;
                }
            }
            bcl=bcl+1;
        }while (bcl < nbrPos);
        printf("OK\n");
    }
     
     
    void KeyName (char nom[])
    //VARIABLES
         //I: nom
         //O: /
    {
        //Supprimer l extension en placant \0 apres le .
        nom[strlen(nom)-3]='\0';
        strcat(nom, "keyframe");
    }
     
    void writeVal (FILE * kf, int * tabPos, int nbrPos)
    //VARIABLES
         //I: kf, tabPos, nbrPos
         //O: /
    {
            int bcl=0;
        printf("-Ecriture des valeurs...");
        printf("\n");
        do
        {
            fprintf(kf, "%d\n", tabPos[bcl]);
            printf("%d\n", tabPos[bcl]);
            bcl=bcl+1;
        }while (bcl < nbrPos);
        printf("OK\n");
    }
     
    //**************************************************************************************************************************************
     
    int main (int argc, char *argv[])
    {
        /*
        int *:
        -tabPos: Tableau Positions, tableau dynamique contenant les positions (MarkerPositions)
        -argv:Nom complet des fichiers wbp a la suite
        -argc:Nombre de fichiers a ouvrir +1
     
        unsigned int:
        -pkmn: touche perso & compteur de .wbp fini (pour la boucle principale)
        -nbrPos: Compteur de positions trouvées
        -end : Sert lors de la recuperation des positions, a detecter quand les chaines recupérées ne sont plus valide afin de sortir de la boucle.
     
        char:
        -nom[]: Nom du fichier .wbp a ouvrir, puis du .keyframe a creer
        -cache[]: Sert pour retrouver les "MarkerPositionX" dans le .wbp
     
        FILE*:
        -wbp: Fichier wbp
        -kf: Fichier KeyFrame
        */
     
        int *tabPos=NULL, save=0;
        unsigned int pkmn=1, nbrPos=0, end = 0, curseur=0;
        char nom[tnom]={0}, cache[tcache]={0};
        FILE* wbp=NULL;
        FILE* kf=NULL;
     
        fileValid(argv, argc);
     
        //Boucle principale
        printf("Debut de la boucle principale\n");
        do
        {
            if (nameValid(argv[pkmn])==0 && argc > 1)
            {
     
                printf("Recuperation du nom...");
                //Recuperation du nom du fichier .wbp
                strcpy(nom, argv[pkmn]);
                printf("OK\n");
     
                tabPos = memoryCreate();
                if (tabPos != ((int *) -1))
                {
                    //Reperage de MP et placage du curseur a cet endroit
                    curseur = findMP(nom);
                    if (curseur != -1)
                    {
                        wbp = wbpOpen(nom);
                        fseek(wbp, curseur, SEEK_SET);
     
                        printf("\nDebut des operations\n");
                        //Boucle
                        do
                        {
                            //Initialiser end
                            end = 0;
     
                            fscanf (wbp, "%s", cache);
                            printf("%s\n", cache);
     
                            //Si la chaine est du type MP=...
                                //strncmp compare uniquement MP
                            if (strncmp(cache, MP, strlen(MP)) == 0)
                            {
                                printf("Chaine MPX\n");
                                tabPos[nbrPos]=ChainMPX(cache);
                            }
                            //Sinon si la chaine est un chiffre
                            else if (isInt(cache)==0)
                            {
                                printf("Chaine INT\n");
                                tabPos[nbrPos]= (int) ChainINT(cache);
                                printf("tabPos[nbrPos] = %d\n", tabPos[nbrPos]);
                            }
                            else
                            {
                                printf("Fin des acquisitions\n");
    //DEBUG_PAUSE
    getchar();
                                end=1;
                            }
     
                            //Incrementer nbrPos
                            nbrPos=nbrPos+1;
     
                            //Augmenter la taille de tabPos
    printf("nbrPos:%d\n", nbrPos);
                            save=tabUpGS(&tabPos, nbrPos);
                            //Si la reallocation se passe sans probleme
                            if (save==-1)
                            {
                                printf("/!\\Une erreur dans l'allocation s'est produite, les donnees acquises sont gardees, mais il peut manquer les données suivantes\n");
                                //Sortir de la boucle sans modifier tabPos, et en remettant nbrPos a sa valeur precedente pour eviter des erreurs
                                nbrPos=nbrPos-1;
                                end=-1;
                            }
     
                            //Sortir de la boucle si la chaine n est pas MP et n est pas un chiffre
                        }while (end == 0);
                        printf("Fin des operations\n");
                        printf("Fermeture du .wbp...");
                        //Fermer le .wbp
                        fclose(wbp);
                        printf("OK\n");
     
                        //Trier les positions par ordre croissant
                        tri(tabPos, nbrPos);
     
                        //Changer le nom pour .keyframe
                        KeyName(nom);
     
                        printf("Ouverture du .keyframe...");
                        //Ouvrir un .keyframe avec le meme nom
                        kf = fopen(nom, "w");
                        printf("OK\n");
                        //Placer les positions separée par '\n'
     
                        writeVal(kf, tabPos, nbrPos);
     
                        printf("Fermeture du .keyframe...");
                        //Fermer le .keyframe
                        fclose (kf);
                        printf("OK\n");
                    }
                }
            }
    //DEBUG_PAUSE
    //getchar();
            //Liberer la memoire
            printf("Liberation de la memoire et reinitialisation des variables...");
            free(tabPos);
            tabPos=NULL;
            nbrPos=0;
            curseur=0;
            strcpy(nom, " ");
            strcpy(cache, " ");
            printf("OK\n");
     
            //Incrementer pkmn (un wbp fini)
            pkmn=pkmn+1;
            //Sortir de la boucle si il n y a plus d autres .wbp
        } while (pkmn <= (argc -1) );
        //Fin
        printf("\nwbp transforme: %d/%d\nend", pkmn-1, argc-1);
    //DEBUG_PAUSE
    getchar();
        exit(EXIT_SUCCESS);
    }
    Voici mon fichier de test (pour les test a plusieurs fichier, je reprend le même avec des noms différents):

    test.wbp:
    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
     
    [Head]
    Signature=Womble Multimedia, Inc.
    Version=MVW-DVD 5.0
    Platform=WIN32
    VersionID=5.0.1.104
    VersionDate=Update Release (12-12-2011)
     
    [Project]
    TrackNumber=4
    TotalClip=21
    TVSystem=NTSC
    Comment=Womble MPEG Video Wizard DVD
     
    [Ruler]
    EditTime=88660801
    ScaleIndex=28
    RulerLeftOffset=0
    WorkArea=1 300001
    FrameRate=750000
    DropFlags=1
    SizeID=0
    Width=352
    Height=240
    FastWidth=352
    FastHeight=240
    MarkerNo=18
    MarkerPosition0=0 5821200 11743200 14103600 17239200
    ProgramLength=94155600
     
    [Track0]
    Type=1
    State=4112
    ClipNumber=19
    NB: Il ne s'agit pas du fichier entier, mais de toute la partie du début, le reste n'etant jamais lu je ne pense pas qu'il puisse y avoir un rapport, sinon la suite est un c/c de Track 0, mais avec 1, 2, 3... et des valeurs différentes

    NB2: A relire mon fichier de test, je me pose la question de si les valeures de MarkerPositions ne sont pas tout simplement trop grosse pour un int?
    Je vais essayer en remplacant par unsigned long int...

    EDIT: En remplacant le type de tabPos, je n'ai plus l'erreur de la valeur étrange, mais tout autant de plantage

  15. #15
    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
    Le problème est quand même sur nbrPos :
    - Au début, il vaut 0
    memoryCreate() alloue 1 int. Alors nbrPos est l'indice du dernier élément valide du tableau alloué.
    - Les tabPos[nbrPos]=... sont alors correct.
    - On incrémente nbrPos qui vaut alors 1
    - On réalloue nbrPos élément donc 1 élément. Maintenant nbrPos est l'indice du dernier élément valide du tableau alloué +1
    - Les tabPos[nbrPos]=... sont alors faux et sortent du tableau alloué.
    Cela finit par se manifester par un plantage lorsqu'on écrit hors du tableau à un endroit sensible.

    Ou TU décides que nbrPos est le nombre d'éléments alloués et tu l'initialises à 1 et tu fais des tabPos[nbrPos-1]=...
    Ou TU décides que nbrPos est l'indice du dernier élément alloué et tu realloc nbrPos+1 éléments.

    Quelques généralités pour améliorer le code :

    - Il y a trop de code fonctionnant de façon marginale : il faut le sécuriser un peu. Par exemple fileValid() (et nameValid()) va planter si on ne met pas d'arguments dans la ligne de commande.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void fileValid (char *argv[], int argc)     //Affiche tout les fichiers a traiter, pas d interet majeur dans l'algo
    //VARIABLES
         //In:
            //argv: Nom des fichier
            //argc: Nombre de fichier +1
    {
        int pkmn;     //Initialisation a 1 pour ne pas afficher argv[0] qui correspond au programme lui meme
        printf("Fichiers a ouvrir:\n");
        for(pkmn = 1 ; pkmn<argc, pkmn++) printf("%s\n", argv[pkmn]); //Afficher le nom du fichier
    }
    - L'utilisation de la valeur de retour 0 pour une fonction qui réussit un test n'est pas astucieuse. (0 correspond à false et 1 à true). Si on utilise 1 pour indiquer la réussite et 0 pour l'échec, on peut se permettre ce genre d'écriture très lisible :
    if(nameValid(...)) .....

    - Tu ne tiens pas compte des remarques qui te sont faites : pas de test de réussite des ouvertures de fichiers et des tentatives en cas d'échec inutiles et qui alourdissent le code. cf wbpOpen()

    - int * memoryCreate () //Allouer la memoire ne constitue PAS un prototype de fonction. Il faut écrire int * memoryCreate (void).
    Le retour de (int*)-1 est à exclure. Retourner NULL en cas d'échec

    - int findMP(char nom[])
    fgets ne retourne pas un int et il est anormal de devoir caster son retour en int. Lorsqu'on effectue un cast explicite, il faut avoir de très très bonnes raisons. Comme ce n'est le plus souvent pas le cas, ça relève de la bidouille.

    - Il est anormal de devoir faire une ouverture de fichier pour chercher MP, faire une sauvegarde de la position, fermer le fichier, rouvrir le fichier et faire un fseek() ...C'est une mauvaise utilisation du code des fonctions.

    - Attention, trop de commentaires inutiles tuent la lisibilité du code.

  16. #16
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par DrakaSAN Voir le message
    Bonjour tout le monde
    Salut, je viens d'arriver...

    Citation Envoyé par DrakaSAN Voir le message
    j ai été chargé de développer un petit programme, qui doit ouvrir un fichier (.wbp), récupérer certaines valeurs inscrites dedans, et les recopier a la suite dans un autre fichier (.keyframe).
    Le tout devant être le plus flexible possible.
    Pourquoi alors te fatiguer à toutes les mémoriser ? Pourquoi ne pas ouvrir les deux fichiers et dès que la valeur est trouvée dans le premier, la recopier dans le second ???

    Citation Envoyé par DrakaSAN Voir le message
    Et mes free me lancent des erreurs windows aléatoirement, et les messages d' "aide" sont parfaitement inutile ("windows cherche une solution a votre problème").
    Pouvait-il en être autrement ? Tu ne sais donc pas que la philosophie zindow c'est "puisqu'on ne sait pas le faire bien alors on le fait beau" ???

    Citation Envoyé par DrakaSAN Voir le message
    Le plus étrange, c'est que le programme peux marcher jusqu'au bout sans problème comme planter dès le premier free, quelque soit le nombre de fichier.
    Ca c'est la caractéristique d'un comportement indéterminé. Tu as fait quelque part un truc interdit et ton code, sans te dire où bien entendu, produit un comportement aléatoire, lequel comportement inclut donc une possible bonne exécution. Pour ton premier essai tu es entré direct dans la cour des grands. Félicitations...

    Citation Envoyé par DrakaSAN Voir le message
    Je suis a peu près sur que j'ai une erreur toute bête quelque part, mais je ne la vois pas, pourtant ça fait bien une dizaine de fois que je relis mon code ligne par ligne en suivant l'ordre d'execution et en notant toute les valeurs successives et que je ne trouve rien X(
    Bon, déjà une première analyse à froid (donc sans investigation poussée)

    Citation Envoyé par DrakaSAN Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int * memoryCreate ()       //Allouer la memoire
    //VARIABLES
         //I: /
         //O: tabPos (tableau dynamique)
    {
        int * tabPos = NULL;
        //Allouer tabPos (une case de memoire) avec calloc (pour la mettre a 0)
        printf("-Creation du tableau de memoire...");
        tabPos = calloc (sizeof(int),1);
    Regarde le schéma de calloc: le premier paramètre doit-être le nombre d'éléments et le second doit-être la taille d'un élément. Toi t'as fait l'inverse.
    Accessoirement es-tu certain d'avoir besoin d'initialiser à 0 une zone destinée à être remplie ???

    Citation Envoyé par DrakaSAN Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    if (tabPos==NULL)  //Si tabPos n'a toujours pas été alloué au bout de trois tentatives
            {
                printf("FAIL\nAllocation de mémoire impossible\nErreur %d\n__________\n", errno);
                return (int *) -1; //Indiquer l erreur et sortir du programme
            }
        printf("OK\n");
        return tabPos;
    }
    Ici c'est pas bon. Le standard d'une allocation ratée est de renvoyer NULL, pas -1. Surtout que -1 n'ayant aucun sens pour un pointeur, le nombre sera automatiquement converti en signé donc 0xFFFF FFFF ce qui peut très bien correspondre à une adresse réelle.

    Citation Envoyé par DrakaSAN Voir le message
    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
    int findMP(char nom[])      //Repere MP dans le .wbp et retourne sa position
    {
        char cache [strlen(MP)+2]={0};
        int pkmn=0;
        FILE * wbp=NULL;
        wbp=wbpOpen(nom);
     
        printf("-Recherche de %s...", MP);
        //Boucle
     
        do
        {
            //Lire le nombre de caractere neccessaire pour MP
            pkmn= (int) fgets ( cache, strlen(MP)+1, wbp );
            //Comparer cette chaine a MP et sortir de la boucle quand la comparaison est bonne
    /*
    Puisque fgets s arrete de lire lors d un '\n', on est assuré de
    passer tout le texte avant de tomber sur le premier MP
    */
     
            //Si la fin du fichier a été récupéré avant de trouver MP
            if (pkmn == (int) NULL)
    Là c'est à peu près pareil. pkmn est un int or fgets() renvoie une adresse. Donc cette adresse est convertie en int et cet entier est comparé avec NULL (qui est déjà 0 converti en adresse) reconverti en int. Théoriquement ça doit marcher quand-même mais moi j'aurais évité toutes ces conversions successives et travaillé avec pkmn en char*...

    Citation Envoyé par DrakaSAN Voir le message
    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
    void tri (int * tabPos, int nbrPos)
    //VARIABLES
         //I: tabPos, nbrPos
         //O: /
    {
        //VARIABLES
        //cache: Sert a deplacer les variables a trier
        int cache=0, bcl=0;
        //Trier tabPos
        printf("-Tri des valeurs...");
        printf("\n");
        do
        {
            if (tabPos[bcl] > tabPos[bcl+1])
            {
                cache = tabPos[bcl+1];
                tabPos[bcl+1] = tabPos[bcl];
                tabPos[bcl] = cache;
                bcl=bcl-2;
                if (bcl<0)
                {
                    bcl=0;
                }
            }
            bcl=bcl+1;
        }while (bcl < nbrPos);
        printf("OK\n");
    }
    Hum, tu as une fonction qsort() déjà toute faite pour trier des éléments divers. Elle demande un petit peu d'investissement pour apprendre à s'en servir mais une fois qu'on sait, on gagne un temps fou...

    Citation Envoyé par DrakaSAN Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    int main (int argc, char *argv[])
    {
        /*
        //Boucle principale
        printf("Debut de la boucle principale\n");
        do
        {
            if (nameValid(argv[pkmn])==0 && argc > 1)
    Pourquoi retester argc encore et encore à chaque fois ? Il me semble qu'il ne change jamais ?
    Citation Envoyé par DrakaSAN Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                printf("Recuperation du nom...");
                //Recuperation du nom du fichier .wbp
                strcpy(nom, argv[pkmn]);
    Mmmnoui. J'ai mes clefs de voiture dans la poche gauche mais je dois d'abord les passer dans la poche droite avant de m'en servir. Pourquoi ne pas travailler directement avec argv[pkmn]
    Bon, tous ces petits trucs en eux-mêmes ne sont probablement pas la cause de ton erreur, faut que je regarde mieux mais typiquement, peut-être que l'accumulation de ces bourdes qui sautent aux yeux plus d'autres peut-être moins visibles font que ...

    En tout cas chapeau. Tu mets des commentaires (peut-être pas tout à fait ceux qu'il faudrait comme le dit Diogène mais au-moins tu en mets), tu essayes de décomposer ton travail en fonctions dédiées, bref on sent que tu cherches à faire les choses bien. Tu verras, ne mettras pas longtemps à devenir très bon...

    [edit]
    Bon maintenant je commence l'investigation plus poussée. Déjà on va optimiser une première fonction
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void fileValid (char *argv[])     //Affiche tout les fichiers a traiter, pas d interet majeur dans l'algo
    //VARIABLES
         //In:
            //argv: Nom des fichier
    {
        char **pt_nom;
     
        printf("Fichiers a ouvrir:\n");
        for (pt_nom=argv; *pt_nom != NULL; pt_nom++)
            printf("%s\n", *pt_nom); //Afficher le nom du fichier
    }

    Donc au lieu de balayer sur l'indice je fais directement incrémenter un pointeur (car la liste argv se termine toujours par un NULL) ce qui permet d'éliminer un paramètre. De plus, je considère qu'elle reçoit déjà la bonne liste (donc sans argv[0] qui est le nom du programme) donc j'évite de me préoccuper de ce pb qui sera à charge de l'appelant qui devra appeler cette fonction de cette façon: fileValid(argv + 1) pour ne pas lui passer argv[0].

    Ensuite ben on va voir...

    [edit2]Je crois que j'ai trouvé
    1) tu fais une allocation de 1 int
    2) tu initialises nbrPos à 0
    3) dans ta boucle tu incrémentes nbrPos qui passe donc à 1 et tu fais un realloc de nbrPos (donc de 1) int
    Ben c'est là que ça pêche. Pour moi (et les pros de la norme confirmeront je pense) tu ne peux pas réallouer la même taille. realloc est fait pour agrandir une zone, pas pour la rétrécir (en général dans ce cas il ne fait rien) ni pour reallouer la même taille. Moi j'ai remplacé tabUpGS(&tabPos, nbrPos) par tabUpGs(&tabPos, nbrPos + 1) et là, plus de pb.

    Accessoirement, agrandir de un en un est une mauvaise stratégie car l'allocation consomme des ressources. Vaut mieux allouer de n en n. De plus, il est inutile de faire malloc + realloc car realloc sur un pointeur NULL le fait se comporter comme un malloc.
    Donc généralement je préconise la structure suivante
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    typedef struct {
    	<type*> zone;
    	<type*> copie;
    	size_t nb;
    	size_t size;
    } t_alloc;

    Puis le schéma de programmation suivant
    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    t_alloc mem;
    mem.zone=NULL;
    mem.nb=0;
    mem.size=0;
     
    for (... traitement quelconque ...)
    {
    	// Donc ici on doit stocker un élément, mais avant on va gérer la mémoire
    	// Si le nb d'éléments déjà stockés a atteint la taille allouée (ce qui arrive forcément à la première itération puisque le nb d'éléments et la taille allouée sont à 0)
    	if (mem.nb == mem.size)  
    	{
    		// On agrandit la zone
    		mem.size+=valeur; // (par exemple 100)
     
    		// On agrandit la zone de la taille demandée
    		mem.copie=realloc(mem.zone, mem.size * sizeof(type)); // Si mem.zone est à NULL alors realloc fait un simple malloc
     
    		// On teste l'allocation
    		if (mem.copie == NULL)
    		{
    			// On gère le pb (généralement on sort du traitement)
    			printf("pb,...\n");
    			break;
    		}
     
    		// L'allocation a réussi donc on la place dans la bonne zone
    		mem.zone=mem.copie;
    	}
     
    	/* Ici on est certain que
    		1) on a assez de place pour stocker un élément
    		2) nb est positionnée sur le premier emplacement de libre
    	Donc on peut sans souci écrire dans zone[nb]
    	*/
    	mem.zone[mem.nb]=ce que l on veut
     
    	// Il faut maintenant placer nb sur l'emplacement suivant
    	mem.nb+=1; // Et, avantage induit, nb contient alors le nombre réel d'éléments stockés
     
    	... suite du traitement ...
    }
    //... traitement de mem.zone... (on peut sans souci boucler de for (i=0; i < mem.nb; i++)...)
     
    // Libération mémoire
    free(mem.zone);
    Déroule cet algo à la main et tu verras que les éléments remplissent la zone sans jamais la dépasser car elle s'agrandit pile poil si elle est pleine et qu'il faut stocker un élément de plus...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  17. #17
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Citation Envoyé par diogene Voir le message
    Quelques généralités pour améliorer le code :

    - Il y a trop de code fonctionnant de façon marginale : il faut le sécuriser un peu. Par exemple fileValid() (et nameValid()) va planter si on ne met pas d'arguments dans la ligne de commande.
    Maintenant que tu met le doigt dessus, ca me montre un reflexe a prendre pour le debuguage.

    Citation Envoyé par diogene Voir le message
    - L'utilisation de la valeur de retour 0 pour une fonction qui réussit un test n'est pas astucieuse. (0 correspond à false et 1 à true). Si on utilise 1 pour indiquer la réussite et 0 pour l'échec, on peut se permettre ce genre d'écriture très lisible :
    if(nameValid(...)) .....
    Là ca entre en contradiction avec ce que mes profs de bts s'acharnent a me dire, pour eux, 0 est lors d'une exécution correcte afin de pouvoir utiliser les autres chiffres comme code d'erreur (cependant, c'est vrai que je n'utilise pas de code d'erreur)

    Citation Envoyé par diogene Voir le message

    - Tu ne tiens pas compte des remarques qui te sont faites : pas de test de réussite des ouvertures de fichiers et des tentatives en cas d'échec inutiles et qui alourdissent le code. cf wbpOpen()
    Je croyais l'avoir corrigé, je me suis apercu que non en reprenant tout a zero apres la remarque de Sve@r

    Citation Envoyé par diogene Voir le message
    - int * memoryCreate () //Allouer la memoire ne constitue PAS un prototype de fonction. Il faut écrire int * memoryCreate (void).
    Le retour de (int*)-1 est à exclure. Retourner NULL en cas d'échec
    Si je declare mes fonctions avant le main, je n'ai pas a utiliser de prototype nan?
    J'ai pris cette habitude après le (très mauvais) cours sur les prototypes, vu que c'a m'evitais d'avoir a les utiliser
    Je ne savais pas que ce n'est pas conventionnel
    (Bon bah je vais chercher des infos sur les prototypes)

    Citation Envoyé par diogene Voir le message

    - int findMP(char nom[])
    fgets ne retourne pas un int et il est anormal de devoir caster son retour en int. Lorsqu'on effectue un cast explicite, il faut avoir de très très bonnes raisons. Comme ce n'est le plus souvent pas le cas, ça relève de la bidouille.
    C'est effectivement de la bidouille, je le reconnais

    Citation Envoyé par diogene Voir le message

    - Il est anormal de devoir faire une ouverture de fichier pour chercher MP, faire une sauvegarde de la position, fermer le fichier, rouvrir le fichier et faire un fseek() ...C'est une mauvaise utilisation du code des fonctions.
    En fait je ne sais pas si lors de l'ouverture d'un fichier dans une fonction, le curseur reste toujours a la même place ou s'il est remis au debut lors du passage a une autre fonction, et je ne trouve nulle part d'info là dessus

    Citation Envoyé par diogene Voir le message

    - Attention, trop de commentaires inutiles tuent la lisibilité du code.
    Il n'y a pas si longtemps je me faisait taper sur les doigts pour ne pas assez commenter...

    Citation Envoyé par Sve@r Voir le message
    Salut, je viens d'arriver...
    Bah... Oui...

    Citation Envoyé par Sve@r Voir le message
    Pourquoi alors te fatiguer à toutes les mémoriser ? Pourquoi ne pas ouvrir les deux fichiers et dès que la valeur est trouvée dans le premier, la recopier dans le second ???
    Avec cette remarque, tu m'a fait comprendre trois choses:
    1.Je m'y suis très mal prit dès le départ
    2.Je suis un imbécile (mais je suppose que j aurai du le remarquer plus tôt )
    3.Je reccommence tout a zero

    Je viens de finir le nouveau code de cette manière, le seul problème est que je ne peux que pour l'instant je ne fais que vérifier si les valeurs sont triées ou non, mais je travaille dessus

    Citation Envoyé par Sve@r Voir le message

    Ca c'est la caractéristique d'un comportement indéterminé. Tu as fait quelque part un truc interdit et ton code, sans te dire où bien entendu, produit un comportement aléatoire, lequel comportement inclut donc une possible bonne exécution. Pour ton premier essai tu es entré direct dans la cour des grands. Félicitations...
    L'avantage c 'est que maintenant que je me suis pris ca en pleine figure, je saurais a quoi m'en tenir avec mes bidouille et mes utilisation de fonctions que je ne maitrise pas...

    Citation Envoyé par Sve@r Voir le message
    Regarde le schéma de calloc: le premier paramètre doit-être le nombre d'éléments et le second doit-être la taille d'un élément. Toi t'as fait l'inverse.
    Accessoirement es-tu certain d'avoir besoin d'initialiser à 0 une zone destinée à être remplie ???
    Décidément j'enchaine les gaffes, et les grosses >_>
    Pour l'initialisation a zero, c'est un des reflexes que j'ai pris lors de mes premiers programmes, je n'aime pas du tout ne pas savoir ce qu il y a dans mes variables (tu peux constater que j'initialise même mes chaines de caractères)

    Citation Envoyé par Sve@r Voir le message

    Ici c'est pas bon. Le standard d'une allocation ratée est de renvoyer NULL, pas -1. Surtout que -1 n'ayant aucun sens pour un pointeur, le nombre sera automatiquement converti en signé donc 0xFFFF FFFF ce qui peut très bien correspondre à une adresse réelle.

    Là c'est à peu près pareil. pkmn est un int or fgets() renvoie une adresse. Donc cette adresse est convertie en int et cet entier est comparé avec NULL (qui est déjà 0 converti en adresse) reconverti en int. Théoriquement ça doit marcher quand-même mais moi j'aurais évité toutes ces conversions successives et travaillé avec pkmn en char*...
    Problème resolu dans mon nouveau code, il fallait juste que je ne me mette pas a placer des returns sans l'avoir prevu dès le départ...

    Citation Envoyé par Sve@r Voir le message

    Hum, tu as une fonction qsort() déjà toute faite pour trier des éléments divers. Elle demande un petit peu d'investissement pour apprendre à s'en servir mais une fois qu'on sait, on gagne un temps fou...
    Je ne connaissait pas du tout, je suis en train de chercher la doc pour la nouvelle version en ce moment même

    Citation Envoyé par Sve@r Voir le message

    Pourquoi retester argc encore et encore à chaque fois ? Il me semble qu'il ne change jamais ?
    Vu que j'ai la mauvaise habitude de bidouiller et non tout reprendre : s

    Citation Envoyé par Sve@r Voir le message
    Mmmnoui. J'ai mes clefs de voiture dans la poche gauche mais je dois d'abord les passer dans la poche droite avant de m'en servir. Pourquoi ne pas travailler directement avec argv[pkmn]
    Par ce que je dois modifier le nom de fichier pendant le programme pour en changer l'extension, or argv est une constante

    Citation Envoyé par Sve@r Voir le message
    Bon, tous ces petits trucs en eux-mêmes ne sont probablement pas la cause de ton erreur, faut que je regarde mieux mais typiquement, peut-être que l'accumulation de ces bourdes qui sautent aux yeux plus d'autres peut-être moins visibles font que ...
    Bourdes que je ne devrais pas avoir faites quand même, et même si ce n'est pas le gros problème, ça doit en causer d'autre

    Citation Envoyé par Sve@r Voir le message
    En tout cas chapeau. Tu mets des commentaires (peut-être pas tout à fait ceux qu'il faudrait comme le dit Diogène mais au-moins tu en mets), tu essayes de décomposer ton travail en fonctions dédiées, bref on sent que tu cherches à faire les choses bien. Tu verras, ne mettras pas longtemps à devenir très bon...
    A la base, mon programme était quasi entièrement dans le main, c'est mon maitre de stage qui m'a fait reprendre mon travail.
    (a la base je n'avait que main, chainMPX, chainINT, isInt et tri)
    Pour les commentaires, j'ai commencé a en mettre depuis que je me suis retrouvé a refaire entièrement un de mes progs parce que je ne m'y retrouvait plus.
    De la même maniére que maintenant je vais vérifier complétement mes entrée et arrêter de bidouiller
    (C est qui qui a dit qu on ne peux apprendre que de ses erreurs?)

    (Je ne quote pas ton edit vu que je viens seulement de voir que tu l'a ajouté, je lis et j'edit après)

    Au passage, ma v0.3 fonctionne correctement, j'ai enlevé mes bidouillage, et il faut maintenant que je tri en cas de besoin, donc je regarde qsort().
    Un grand merci a vous pour votre patience, et pour vos encouragement

  18. #18
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 492
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 492
    Billets dans le blog
    1
    Par défaut
    Avec cette remarque, tu m'a fait comprendre trois choses:
    1.Je m'y suis très mal prit dès le départ
    2.Je suis un imbécile (mais je suppose que j aurai du le remarquer plus tôt )
    3.Je reccommence tout a zero
    C'est comme ça qu'on apprend


    arrêter de bidouiller
    Quand on bidouille, il y a plusieurs mauvaises causes possibles :
    • on ne maitrise pas le comportement du langage
    • on ne maitrise pas les fonctions qu'on utilise
    • notre algorithme est mauvais

    Il faut bien sûr trouver la ou lesquelles sont en cours d'utilisation et l'(es) éradiquer !


    Pour l'initialisation a zero, c'est un des reflexes que j'ai pris lors de mes premiers programmes, je n'aime pas du tout ne pas savoir ce qu il y a dans mes variables
    C'est un bon réflexe, mais ce n'est pas toujours utile. A doser.


    C'est comme les commentaires d'ailleurs. Il faut trouver la bonne dose et surtout le contenu judicieux :
    Il n'y a pas si longtemps je me faisait taper sur les doigts pour ne pas assez commenter...

    Là ca entre en contradiction avec ce que mes profs de bts s'acharnent a me dire, pour eux, 0 est lors d'une exécution correcte afin de pouvoir utiliser les autres chiffres comme code d'erreur (cependant, c'est vrai que je n'utilise pas de code d'erreur)
    Ce sont deux stratégies. Pour apporter de l'eau à ce moulin, je dirais que les commandes Unix renvoient 0 en cas de succès, pourquoi ne pas faire pareil avec nos fonctions ?


    Si je declare mes fonctions avant le main, je n'ai pas a utiliser de prototype nan?
    J'ai pris cette habitude après le (très mauvais) cours sur les prototypes, vu que c'a m'evitais d'avoir a les utiliser
    Je ne savais pas que ce n'est pas conventionnel
    Petit truc intéressant que me dit CodeBlocks :

    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
    void f(void); // declaration
     
    void f(void) // implementation
    {
        puts("f");
    }
     
    int main(int argc, char *argv[])
    {
        argv=NULL;
        argc=0;
     
        f();
     
        return 0;
    }
    En sélectionnant f et en cliquant droit dessus, CB propose d'aller à la déclaration ou à l'implémentation (j'indique en commentaire qui correspond à quoi). Visiblement, en C, déclaration et prototype reviennent aux mêmes, pour une fonction. L'implémentation (la définition de la fonction) donne bien sûr le prototype de la fonction, cad son type de retour et les types et nombres de ses paramètres.

    Pour ce qui est de l'histoire des fonctions avant le main, c'est peut-être parce que tu n'utilises pas dans tes fonctions d'autres fonctions. Essaye le code suivant :
    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
    void f(void)
    {
        g();
    }
     
    void g(void)
    {
        puts("g");
    }
     
    int main(int argc, char *argv[])
    {
        argv=NULL;
        argc=0;
     
        f();
     
        return 0;
    }
    et voit les warnings de ton compilateur :
    d:\...\main.c||In function 'f'
    d:\...\main.c|11|warning: implicit declaration of function 'g'|
    d:\...\main.c|14|warning: conflicting types for 'g'|
    d:\...\main.c|11|note: previous implicit declaration of 'g' was here|
    ||=== Build finished: 0 errors, 2 warnings (0 minutes, 0 seconds) ===|
    Il faut que quand tu utilises une fonction, le compilateur connaisse déjà son prototype, parce qu'il a rencontré plus tôt dans le fichier sa déclaration ou son implémentation qui donnent toutes les 2 le prototypes. Sinon, il considère avoir rencontré une déclaration implicite et lui donne un prototype par défaut que je ne connais pas (retour = int, mais paramètres = ??).

    Avec les 2 versions suivantes, plus de warning :
    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
    void g(void);
     
    void f(void)
    {
        g();
    }
     
    void g(void)
    {
        puts("g");
    }
     
    int main(int argc, char *argv[])
    {
        argv=NULL;
        argc=0;
     
        f();
     
        return 0;
    }
    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
     
    void g(void)
    {
        puts("g");
    }
     
     
    void f(void)
    {
        g();
    }
     
     
    int main(int argc, char *argv[])
    {
        argv=NULL;
        argc=0;
     
        f();
     
        return 0;
    }
    PS : si je n'ai pas été totalement précis sur les termes, corrigez-moi ^^

  19. #19
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 801
    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 801
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par DrakaSAN Voir le message
    Si je declare mes fonctions avant le main, je n'ai pas a utiliser de prototype nan?
    Exact. Si tu définis tes fonctions avant de les utiliser tu n'as alors pas besoin de les déclarer.
    La déclaration s'impose dans 2 cas
    1) quand tu ne peux pas définir une fonction avant de l'utiliser (style a qui appelle b et b qui appelle a)
    2) quand tu utilises une librairie publique => tu dois alors déclarer les fonctions de ladite librairie puisque tu n'as pas accès à leur code => mais en général chaque librairie possède ses headers contenant les déclarations appropriées

    Maintenant si tu prends la bonne habitude de toujours déclarer tes fonctions, tu n'auras plus de question existentielle style "est-ce que a sera appelé avant ou après b"...

    Citation Envoyé par DrakaSAN Voir le message
    En fait je ne sais pas si lors de l'ouverture d'un fichier dans une fonction, le curseur reste toujours a la même place ou s'il est remis au debut lors du passage a une autre fonction, et je ne trouve nulle part d'info là dessus
    Chaque fois que tu ouvres un fichier, cela génère une structure FILE contenant entre autres la position du fichier. Cette position est modifiée à chaque lecture/écriture et à chaque fseek mais elle est liée à la structure.
    Donc si tu ouvres ton fichier 2 fois en parallèle, tu pourras gérer 2 positions distinctes
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    FILE *f1;
    FILE *f2;
    f1=fopen("/etc/passwd", "r");
    f2=fopen("/etc/passwd", "r");
    fseek(f1, 10, SEEK_CUR);
    fgetc(f2);
    fgetc(f2);
    printf("position f1: %d\n", ftell(f1));   // => 10
    printf("position f2: %d\n", ftell(f2));   // => 2
    fclose(f1);
    fclose(f2);

    Maintenant il faut aussi toi-même que tu définisses ton propre besoin. Si par exemple tu veux créer une fonction totalement indépendante destinée à trouver la position d'une chaine quelconque dans un fichier quelconque, fonction pouvant ensuite être recopiée telle quelle dans un autre code, alors il faut que ta fonction fasse l'ouverture et la fermeture du fichier. Ce sera un peu plus lourd surtout si le fichier a déjà été ouvert en amont mais l'avantage est que tu auras un truc totalement déconnecté et donc réutilisable tel quel. Un légo quoi.
    Si au contraire tu n'as pas besoin qu'elle soit "extractible" et que tu préfères alors la rapidité, tu peux éviter l'ouverture/fermeture (en admettant alors que le fichier est obligatoirement ouvert en amont). Mais il faudra que ta fonction récupère la position courante avant de faire sa recherche puis qu'elle s'y replace en sortie.

    Citation Envoyé par DrakaSAN Voir le message
    Il n'y a pas si longtemps je me faisait taper sur les doigts pour ne pas assez commenter...
    Il faut savoir comprendre ce que Diogène a voulu dire. On ne met pas des commentaires pour le plaisir d'en avoir, on essaye de mettre des commentaires utiles à la bonne compréhension du code et de l'idée générale qui le sous-tend. Par exemple typiquement on s'en fiche un peu de savoir que argc sera le nombre d'arguments surtout qu'en général tout le monde le sait. Mais c'est à toi de sentir quand et comment en mettre et quand et comment ne pas en mettre.
    Tiens, regarde par exemple ces 2 versions de la fonction fileValid
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    printf("Fichiers a ouvrir:\n");
    do {
    	printf("%s\n", argv[pkmn]); //Afficher le nom du fichier
    	pkmn=pkmn+1;                //Passer au fichier suivant
    }while (pkmn<argc);             //Jusqu a avoir fait tout les fichiers

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    printf("Fichiers a ouvrir:\n");
     
    // Traitement et affichage de tous les fichiers dans une boucle allant jusqu'à argc
    do {
    	printf("%s\n", argv[pkmn]);
    	pkmn=pkmn+1;
    }while (pkmn<argc);

    Laquelle te semble la plus agréable à relire et/ou à modifier ? Surtout si la modif amène à cela
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    printf("Fichiers a ouvrir:\n");
     
    // Traitement et affichage de tous les fichiers dans une boucle allant jusqu'à argc
    for (pkmn=1; pkmn < argc; pkmn++)
    	printf("%s\n", argv[pkmn]);
    Le code change mais pas le commentaire. Bon bref il n'y a pas vraiment de règle mathématique du commentaire. La façon de commenter est à la fois la musique du code et la signature du codeur...

    Citation Envoyé par DrakaSAN Voir le message
    Avec cette remarque, tu m'a fait comprendre trois choses:
    1.Je m'y suis très mal prit dès le départ
    2.Je suis un imbécile (mais je suppose que j aurai du le remarquer plus tôt )
    3.Je reccommence tout a zero
    Mais non t'es pas idiot. Tu tâtonnes et c'est normal. Et en plus tu cherches donc c'est tout le contraire. Et tu verras que l'ignorance est de très courte durée et que la connaissance reste à vie...

    Citation Envoyé par DrakaSAN Voir le message
    Pour l'initialisation a zero, c'est un des reflexes que j'ai pris lors de mes premiers programmes, je n'aime pas du tout ne pas savoir ce qu il y a dans mes variables (tu peux constater que j'initialise même mes chaines de caractères)
    Héhé... mais tu le sais ce qu'il y a dans tes variables puisque c'est toi qui le mets...
    Effectivement comme le dit Bktero il y a 2 façons de penser
    1) tu mets tout à 0 et tu ne te poses pas de question
    2) tu n'initialises que ce qu'il faut (comme dans mon exemple de gestion mémoire où je n'initialise pas copie car il est rempli par le realloc) et quand tu arrives à un "if (toto == NULL)" tu prends 5 secondes pour te dire "est-ce que toto a bien été rempli avant d'être évalué". Personne ne te fera de reproche dans les deux cas... sauf dans le cas 2 si tu écris if (toto == ...) alors qu'il s'avère qu'il y a n'importe quoi dedans !

    Citation Envoyé par DrakaSAN Voir le message
    Je ne connaissait pas du tout, je suis en train de chercher la doc pour la nouvelle version en ce moment même
    Ok, reviens sur ce point si tu ne t'en sors pas...

    Citation Envoyé par DrakaSAN Voir le message
    A la base, mon programme était quasi entièrement dans le main, c'est mon maitre de stage qui m'a fait reprendre mon travail.
    Un bon maitre avoir est un trésor précieux posséder (disait Yoda)

    Citation Envoyé par DrakaSAN Voir le message
    (C est qui qui a dit qu on ne peux apprendre que de ses erreurs?)
    C'est totalement naturel. Et ça commence dès qu'on se met à marcher et qu'on se casse la f...

    Heureux de te voir si motivé
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  20. #20
    Membre averti
    Homme Profil pro
    Lycéen
    Inscrit en
    Juillet 2012
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2012
    Messages : 12
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Ce sont deux stratégies. Pour apporter de l'eau à ce moulin, je dirais que les commandes Unix renvoient 0 en cas de succès, pourquoi ne pas faire pareil avec nos fonctions ?
    Mes profs sont tous des defenseur de Unix/Linux, ca doit être ca.

    Citation Envoyé par Bktero Voir le message
    Pour ce qui est de l'histoire des fonctions avant le main, c'est peut-être parce que tu n'utilises pas dans tes fonctions d'autres fonctions. Essaye le code suivant :

    Il faut que quand tu utilises une fonction, le compilateur connaisse déjà son prototype, parce qu'il a rencontré plus tôt dans le fichier sa déclaration ou son implémentation qui donnent toutes les 2 le prototypes. Sinon, il considère avoir rencontré une déclaration implicite et lui donne un prototype par défaut que je ne connais pas (retour = int, mais paramètres = ??).
    J'utilise des fonctions dans des fonctions, regarde ChainMPX, MPXSuppr, MPXGetVal, il suffit de mettre les fonctions n'appellant pas d'autre fonctions au debut, puis celle en appellant une, puis deux...

    Citation Envoyé par Bktero Voir le message
    PS : si je n'ai pas été totalement précis sur les termes, corrigez-moi ^^
    Je pense pas avoir été beaucoup mieux x)

    Citation Envoyé par Sve@r Voir le message
    Exact. Si tu définis tes fonctions avant de les utiliser tu n'as alors pas besoin de les déclarer.
    Bon bah on utilisait pas les bon termes

    Citation Envoyé par Sve@r Voir le message
    La déclaration s'impose dans 2 cas
    1) quand tu ne peux pas définir une fonction avant de l'utiliser (style a qui appelle b et b qui appelle a)
    2) quand tu utilises une librairie publique => tu dois alors déclarer les fonctions de ladite librairie puisque tu n'as pas accès à leur code => mais en général chaque librairie possède ses headers contenant les déclarations appropriées
    1) Ca existe? Oo

    Citation Envoyé par Sve@r Voir le message
    Maintenant si tu prends la bonne habitude de toujours déclarer tes fonctions, tu n'auras plus de question existentielle style "est-ce que a sera appelé avant ou après b"...
    Si on s'y prend correctement ca pose pas trop problème... Du moins sur un nombre réduit de fonctions

    Citation Envoyé par Sve@r Voir le message

    Chaque fois que tu ouvres un fichier, cela génère une structure FILE contenant entre autres la position du fichier. Cette position est modifiée à chaque lecture/écriture et à chaque fseek mais elle est liée à la structure.
    Donc si tu ouvres ton fichier 2 fois en parallèle, tu pourras gérer 2 positions distinctes
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    FILE *f1;
    FILE *f2;
    f1=fopen("/etc/passwd", "r");
    f2=fopen("/etc/passwd", "r");
    fseek(f1, 10, SEEK_CUR);
    fgetc(f2);
    fgetc(f2);
    printf("position f1: %d\n", ftell(f1));   // => 10
    printf("position f2: %d\n", ftell(f2));   // => 2
    fclose(f1);
    fclose(f2);
    Donc vu que les FILE * sont des passages par adresses, le curseur reste a la même place, donc tu m'economise une dizaine de ligne sur ma v0.3

    Citation Envoyé par Sve@r Voir le message
    Maintenant il faut aussi toi-même que tu définisses ton propre besoin. Si par exemple tu veux créer une fonction totalement indépendante destinée à trouver la position d'une chaine quelconque dans un fichier quelconque, fonction pouvant ensuite être recopiée telle quelle dans un autre code, alors il faut que ta fonction fasse l'ouverture et la fermeture du fichier. Ce sera un peu plus lourd surtout si le fichier a déjà été ouvert en amont mais l'avantage est que tu auras un truc totalement déconnecté et donc réutilisable tel quel. Un légo quoi.
    Si au contraire tu n'as pas besoin qu'elle soit "extractible" et que tu préfères alors la rapidité, tu peux éviter l'ouverture/fermeture (en admettant alors que le fichier est obligatoirement ouvert en amont). Mais il faudra que ta fonction récupère la position courante avant de faire sa recherche puis qu'elle s'y replace en sortie.
    Ce programme n'est pas sensé sortir de l'entreprise ou je fais mon stage (bon, si je laisse une version bugué ici je pense pas qu'on m'en voudra ), donc je vais préférer la rapidité

    Citation Envoyé par Sve@r Voir le message

    Il faut savoir comprendre ce que Diogène a voulu dire. On ne met pas des commentaires pour le plaisir d'en avoir, on essaye de mettre des commentaires utiles à la bonne compréhension du code et de l'idée générale qui le sous-tend. Par exemple typiquement on s'en fiche un peu de savoir que argc sera le nombre d'arguments surtout qu'en général tout le monde le sait. Mais c'est à toi de sentir quand et comment en mettre et quand et comment ne pas en mettre.
    Tiens, regarde par exemple ces 2 versions de la fonction fileValid
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    printf("Fichiers a ouvrir:\n");
    do {
    	printf("%s\n", argv[pkmn]); //Afficher le nom du fichier
    	pkmn=pkmn+1;                //Passer au fichier suivant
    }while (pkmn<argc);             //Jusqu a avoir fait tout les fichiers

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    printf("Fichiers a ouvrir:\n");
     
    // Traitement et affichage de tous les fichiers dans une boucle allant jusqu'à argc
    do {
    	printf("%s\n", argv[pkmn]);
    	pkmn=pkmn+1;
    }while (pkmn<argc);

    Laquelle te semble la plus agréable à relire et/ou à modifier ? Surtout si la modif amène à cela
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    printf("Fichiers a ouvrir:\n");
     
    // Traitement et affichage de tous les fichiers dans une boucle allant jusqu'à argc
    for (pkmn=1; pkmn < argc; pkmn++)
    	printf("%s\n", argv[pkmn]);
    Le code change mais pas le commentaire.
    Effectivement ca change beaucoups de choses...
    Citation Envoyé par Sve@r Voir le message
    Bon bref il n'y a pas vraiment de règle mathématique du commentaire. La façon de commenter est à la fois la musique du code et la signature du codeur...
    ...donc vais me remettre a composer :p

    Citation Envoyé par Sve@r Voir le message

    Mais non t'es pas idiot. Tu tâtonnes et c'est normal. Et en plus tu cherches donc c'est tout le contraire. Et tu verras que l'ignorance est de très courte durée et que la connaissance reste à vie...
    Mais il me reste du chemin a faire ^^

    Citation Envoyé par Sve@r Voir le message

    Héhé... mais tu le sais ce qu'il y a dans tes variables puisque c'est toi qui le mets...
    Effectivement comme le dit Bktero il y a 2 façons de penser
    1) tu mets tout à 0 et tu ne te poses pas de question
    2) tu n'initialises que ce qu'il faut (comme dans mon exemple de gestion mémoire où je n'initialise pas copie car il est rempli par le realloc) et quand tu arrives à un "if (toto == NULL)" tu prends 5 secondes pour te dire "est-ce que toto a bien été rempli avant d'être évalué". Personne ne te fera de reproche dans les deux cas... sauf dans le cas 2 si tu écris if (toto == ...) alors qu'il s'avère qu'il y a n'importe quoi dedans !
    Justement, même si tu fais les variables, tu ne sais pas ce qui est dedans a la base, ca pourrait être un bon moyen pour faire de l’aléatoire (et plus simple que rand ^^') mais je ne supporte absolument pas dans un programme

    Citation Envoyé par Sve@r Voir le message

    Ok, reviens sur ce point si tu ne t'en sors pas...
    A l'heure u j'ecris ce message je n'ai pas eu le temps d'aller voir :s (je ne fais pas que du codage, et la je suis en pause)

    Citation Envoyé par Sve@r Voir le message

    Un bon maitre avoir est un trésor précieux posséder (disait Yoda)
    Euh... En fait c'est la seule fois ou il a regardé mon code, et il a pas vraiment regardé le contenu ^^'

    Citation Envoyé par Sve@r Voir le message
    C'est totalement naturel. Et ça commence dès qu'on se met à marcher et qu'on se casse la f...
    Ouaip, on se releve et on retombe jusqu a tenir a peu près debout

    Citation Envoyé par Sve@r Voir le message
    Heureux de te voir si motivé
    Le fait que je veuille finir dans les JVs y est pour quelque choses
    (Et oui je sais que les concepteurs apprécie d'un coup beaucoups moins les JVs, mais déjà que je n'aprécie les jeux plus qu'a leur scénario et originalité, ca me va... Bref)

    Bon, je vais voir si j'ai le temps d'avancer un peu en codage, j'ai presque fini ce que je dois faire a coter

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

Discussions similaires

  1. probleme avec realloc
    Par adrien1 dans le forum Débuter
    Réponses: 1
    Dernier message: 07/10/2009, 21h20
  2. Réponses: 5
    Dernier message: 05/12/2006, 14h04
  3. [Free Pascal] Problème avec 'str'
    Par TheBigMac dans le forum Free Pascal
    Réponses: 1
    Dernier message: 12/04/2006, 21h56
  4. [Free Pascal] Problème avec delay
    Par Cedrun dans le forum Free Pascal
    Réponses: 3
    Dernier message: 27/01/2006, 17h53
  5. [Debutant]Probleme avec un realloc
    Par Jabbal'H dans le forum C
    Réponses: 21
    Dernier message: 11/01/2006, 15h25

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