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 :

Programme compile sur tout système mais instable uniquement sur Debian


Sujet :

C

  1. #1
    Invité
    Invité(e)
    Par défaut Programme compile sur tout système mais instable uniquement sur Debian
    Bonsoir à vous,

    Depuis hier soir je rencontre pour la première fois une colle que je n'arrive pas à résoudre et ça me pousse donc à poster mon premier message sur ce forum.

    Pour faire simple et court, j'ai un programme en C (projet de fin d'année) qui à été développé sur la distribution Antergos , le programme compile(GCC) et fonctionne très bien sur cette distribution , également le prog est compatible pour Windows 7, compile(Min-gw) et fonctionne très bien. Seulement sur ma distribution actuelle Debian 8 le programme compile sans problème, s'exécute mais il a un comportement instable en particulier avec l'acces aux données aussi bien static que dynamique.

    Le problème doit surement venir de la compilation seulement aucun indice , aucun message , le programme n'utilise que des lib natif (stdio,stdlib et string), j'ai essayé plusieurs versions de GCC en machine virtuel debian , sur mon debian je suis sur gcc 6 et j'ai testé 7 et 8 aucun résultat.
    Il existe 2 versions de l'application une totalement static et une autre dynamique avec des des liste doublements chainé et l'erreur est exactement la même.
    l'application fait quelques miliers de lignes et quelques fichiers je ne peux donc pas vous les montré mais voila ce qui se passe :
    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
     
    Pseudo Code Approximatif:
    Main()
    {
           Structure_chainé *clients=new_Structure_chainé();
           load_data(clients,fichier.txt); //pas de soucis les données sont load sont ok
           clients->head->name="John doe"  //Pas de soucis
           printf("%d",clients->head->age) // Pas de soucis
           Une_fonction(clients);
     }
     
    Une_fonction(Structure_chainé *clients)
    {
           if(clients!=NULL) // plante immediatement alors que sur antergos et windows 7 ça marche impec 
     }
    Donc voilà si par hasard quelqu'un aurait une idée je suis preneur.
    Merci d'avance et bonne soirée !

    ps: je sais qu'à première vue on pourrais croire que c'est un problème avec le code style fuite de mémoire ou autre mais je peux assuré à 100% que le code n'a aucune erreur.
    Dernière modification par Invité ; 28/08/2018 à 00h31.

  2. #2
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : mai 2010
    Messages : 2 529
    Points : 4 607
    Points
    4 607
    Par défaut
    ça ressemble à une erreur de typage...
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  3. #3
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 630
    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 : 9 630
    Points : 26 305
    Points
    26 305
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par mochiwa Voir le message
    l'application fait quelques miliers de lignes et quelques fichiers je ne peux donc pas vous les montré
    Pseudo Code Approximatif:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Main()
    {
           Structure_chainé *clients=new_Structure_chainé();
           load_data(clients,fichier.txt); //pas de soucis les données sont load sont ok
           clients->head->name="John doe"  //Pas de soucis
           printf("%d",clients->head->age) // Pas de soucis
           Une_fonction(clients);
     }
     
    Une_fonction(Structure_chainé *clients)
    {
           if(clients!=NULL) // plante immediatement alors que sur antergos et windows 7 ça marche impec 
     }
    Il serait utile tout de même d'avoir le code source de la fonction "new_Structure_chainé()".
    De plus, tu pourrais aussi créer un second programme ne contenant que la fonction "main()", "new_Structure_chainé()" et "Une_fonction()" et voir si l'erreur se reproduit. Honnêtement un bug de Debian's gcc est toujours possible bien entendu mais les probabilités sont quand-même plus contre toi que contre gcc (surtout que les sources de gcc sont les mêmes partout quoi)...

    Citation Envoyé par mochiwa Voir le message
    ps: je sais qu'à première vue on pourrais croire que c'est un problème avec le code style fuite de mémoire ou autre mais je peux assuré à 100% que le code n'a aucune erreur.
    Sur quelques milliers de lignes tu peux vraiment garantir qu'il n'y en a pas une qui génère un comportement indéterminé ? Surtout avec ta structure à 2 niveaux (clients->head->name) ?? T'as bien correctement alloué "client" et "client->head" ???
    Parce qu'un comportement indéterminé c'est réellement ce que ça veut dire => le comportement est alors imprévisible. Le programme peut planter comme ne pas planter, planter là où il y a la ligne ou bien planter plus loin. Il peut fonctionner les jours pairs mais planter les jours impairs. Ou bien (comme c'est le cas ici) fonctionner avec Min-gw mais planter sous Debian...
    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

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    6 819
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 6 819
    Points : 31 245
    Points
    31 245
    Billets dans le blog
    4
    Par défaut
    Les accents devraient être proscrits dans du code.
    Un truc comme clients->head->name="John doe" est hautement suspect. Confusion dynamique et non dynamique aisée quand on débute.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Hello merci d'intervenir , alors j'ai uploadé mon projet sur GITHUB voila le lien: https://github.com/mochiwa/Pap_projet

    Citation Envoyé par Bousk Voir le message
    Les accents devraient être proscrits dans du code.
    Un truc comme clients->head->name="John doe" est hautement suspect. Confusion dynamique et non dynamique aisée quand on débute.
    Alors bien sûr dans le code que j'ai mis dans mon message initial ce n'était qu'un pseudo-code assez(très) maladroit qui n'a rien à voir avec le code comme vous pourrez le constater, l'objectif était de montrer que le programme plante au passage d'une fonction.

    Citation Envoyé par Sve@r Voir le message
    Sur quelques milliers de lignes tu peux vraiment garantir qu'il n'y en a pas une qui génère un comportement indéterminé ? Surtout avec ta structure à 2 niveaux (clients->head->name) ?? T'as bien correctement alloué "client" et "client->head" ???
    Parce qu'un comportement indéterminé c'est réellement ce que ça veut dire => le comportement est alors imprévisible. Le programme peut planter comme ne pas planter, planter là où il y a la ligne ou bien planter plus loin. Il peut fonctionner les jours pairs mais planter les jours impairs. Ou bien (comme c'est le cas ici) fonctionner avec Min-gw mais planter sous Debian...
    Une erreur de code me paraît assez difficile à croire du moins pour quelque chose de "simple" comme une allocation ou autres , et pour cause le projet de fin d'année a été rendu en juin et était pleinement fonctionnel sur Antergos,Arch,Kubuntu,windows7,10 de plus le programme fonctionne toujours à merveille sur Antergos et Windows sans aucune erreur ou autre problème d'allocation (Valgrind).

    Petite info si vous souhaitez teser le programme et que vous compilez sur Windows, il faut commenter la ligne #define LINUX 1 dans le fichier Header/own.h


    EDIT:

    Citation Envoyé par Sve@r Voir le message
    De plus, tu pourrais aussi créer un second programme ne contenant que la fonction "main()", "new_Structure_chainé()" et "Une_fonction()" et voir si l'erreur se reproduit.
    Je viens de testé et voilà ce qu'il se passe:
    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
     
    void makeEntity(Entity *entity)
    {
    	do{
    		setStringParam(entity->name,"Nom",BUFFER_SIZE,3);
    	}while(!isAlphaRegex(entity->name,BUFFER_SIZE));
     
    	do{
     		setStringParam(entity->forename,"Prenom",BUFFER_SIZE,3);
     	}while(!isAlphaRegex(entity->forename,BUFFER_SIZE));
     
     	entity->sexe=!isValid("* Etes-vous un Homme ?");
     	printf("* --Date de naissance--\n");
     	makeDateTime(&entity->birthday);
    }
    void printEntity(const Entity *entity)
    {
     	printf("* -Nom : %s\n",entity->name );
     	printf("* -Prenom : %s\n",entity->forename );
     	printf("* -Sexe : ");
     	if(entity->sexe)
     		printf("femme\n");
     	else
     		printf("homme\n");
     	printf("* -Naissance: ");
     	printDateTimeToString(&entity->birthday);
     	printf("\n");
    }
    Customer *new_customer(const int id)
    {
    	Customer *customer=(Customer *)alloc(sizeof(Customer));
    	initCustomer(customer);
    	customer->id=id;
    	do
    	{
    		printCustomerTitle();
    		makeEntity(&customer->entity);
    		printCustomerTitle();
    		printEntity(&customer->entity);
    	}while(!isValid("Valider l'identite ?"));
     
    	do
    	{
    		printCustomerTitle();
    		makeAddress(&customer->address);
    		printCustomerTitle();
    		printAddress(&customer->address);
    	}while(!isValid("Valider l'adresse ?"));
    	return customer;
    }
     
    int main(int argc, char const *argv[])
    {
        Customer *custo=new_customer(1);
    }
    Ce code à très bien fonctionné du début à la fin !

    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
     
    void makeEntity(Entity *entity)
    {
    	do{
    		setStringParam(entity->name,"Nom",BUFFER_SIZE,3);
    	}while(!isAlphaRegex(entity->name,BUFFER_SIZE));
     
    	do{
     		setStringParam(entity->forename,"Prenom",BUFFER_SIZE,3);
     	}while(!isAlphaRegex(entity->forename,BUFFER_SIZE));
     
     	entity->sexe=!isValid("* Etes-vous un Homme ?");
     	printf("* --Date de naissance--\n");
     	makeDateTime(&entity->birthday);
    }
    void printEntity(const Entity *entity)
    {
     	printf("* -Nom : %s\n",entity->name );
     	printf("* -Prenom : %s\n",entity->forename );
     	printf("* -Sexe : ");
     	if(entity->sexe)
     		printf("femme\n");
     	else
     		printf("homme\n");
     	printf("* -Naissance: ");
     	printDateTimeToString(&entity->birthday);
     	printf("\n");
    }
    Customer *new_customer(const int id)
    {
    	Customer *customer=(Customer *)alloc(sizeof(Customer));
    	initCustomer(customer);
    	customer->id=id;
    	do
    	{
    		printCustomerTitle();
    		makeEntity(&customer->entity);
    		printCustomerTitle();
    		printEntity(&customer->entity);
    	}while(!isValid("Valider l'identite ?"));
     
    	do
    	{
    		printCustomerTitle();
    		makeAddress(&customer->address);
    		printCustomerTitle();
    		printAddress(&customer->address);
    	}while(!isValid("Valider l'adresse ?"));
    	return customer;
    }
     
    ArrayCustomer *new_array_customer()
    {
    	ArrayCustomer *array=(ArrayCustomer *)alloc(sizeof(ArrayCustomer));
    	array->size=0;
    	array->head=NULL;
    	array->tail=NULL;
    	array->middle=NULL;
    	return array;
    }
     
     
     
    int main(int argc, char const *argv[])
    {
        ArrayCustomer *array=new_array_customer();
        Customer *custo=new_customer(1);
    }
    Ce code me donne une Segmentation fault au niveau de la création du Customer à la ligne entity->sexe=!isValid("* Etes-vous un Homme ?"); de la fonction makeEntity().
    Remarquéez qu'il n'y a, au niveau du Customer, aucune différence avec le code précédent la seul différence dans ce code est que je crée avant ou après une autre entité ArrayCustomer.

    Et c'est maintenant que ça devient marrant !
    Si je reexecute le premier code qui fonctionnait bien , je me retrouve denouveau avec une segmentation fault au même endroit .
    Dernière modification par Invité ; 28/08/2018 à 08h40.

  6. #6
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : juin 2002
    Messages : 2 165
    Points : 4 605
    Points
    4 605
    Par défaut
    Alors très rapidement, j'ai recompilé le programme sous Windows avec GCC 8.1.0 et CLang 6.0.1, dans les deux cas j'ai des crash (pour commencer si je sors sans rien faire).

    Je n'ai pas regarder en détail et je ne sais pas exactement où est le problème mais plusieurs points gênants dans le code :
    * Utilisation d'identification réservé (sauf erreur de ma part "__ + majuscule" est réservé)
    * La dernière ligne de certains fichiers n'est pas complète
    * Des case sans break qui font tomber dans le cas suivant (c'est peut être voulu, mais ça reste maladroit)
    * Des comparaisons de float avec ==
    * L'utilisation de char pour stocker le retour de fgetc qui est un int et que tu compares ensuite avec EOF
    * Des =NULL sur un paramètre de fonction qui est au mieux inutile, au pire faux si tu penses que cela va modifier la valeur pour l'appelant

    La plupart de ces erreurs sont relevés par un compilateur ou un linter (qui signale aussi l'absence d'accolades sur le corps des if, ce qui n'est pas forcément faux mais peu conseillé car source d'erreur).

    Sinon, j'ai de gros doutes sur les allocations / libérations. Au passage, pourquoi n'as tu fait pas un structure de liste distincte des nœuds et distincte de des données plutôt que de mélanger les trois (d'autant que tu as plusieurs liste dans ton code) ?

  7. #7
    Expert éminent
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    mai 2010
    Messages
    3 088
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : mai 2010
    Messages : 3 088
    Points : 9 682
    Points
    9 682
    Par défaut
    Citation Envoyé par mochiwa Voir le message
    Le problème doit surement venir de la compilation seulement aucun indice , aucun message , le programme n'utilise que des lib natif (stdio,stdlib et string), j'ai essayé plusieurs versions de GCC en machine virtuel debian , sur mon debian je suis sur gcc 6 et j'ai testé 7 et 8 aucun résultat.
    C'est une grave erreur de jugement que tu as faite , dire que le compilo bug signifierai que tu as une confiance aveugle sur ton niveau en C !

    Quand on remarque que le truc ne bug pas dans une machine X et bug dans la machine Y = souci avec les pointeurs , y'a un débordement/segfault quelque part
    Vu ton code , tu as des pointeurs partout donc une grosse source de bug en perspective , surtout si on débute !

  8. #8
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    4 384
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : juin 2009
    Messages : 4 384
    Points : 13 214
    Points
    13 214
    Billets dans le blog
    1
    Par défaut
    Puisque tu es sous Debian, je vais être fou et dire :
    valgrind ./ton_programme.out


    Je vais aussi demander que tu nous montres ta ligne de compilation (notamment les options pour activer les warnings de GCC).

  9. #9
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Kannagi Voir le message
    C'est une grave erreur de jugement que tu as faite , dire que le compilo bug signifierai que tu as une confiance aveugle sur ton niveau en C !
    Quand on remarque que le truc ne bug pas dans une machine X et bug dans la machine Y = souci avec les pointeurs , y'a un débordement/segfault quelque part
    Vu ton code , tu as des pointeurs partout donc une grosse source de bug en perspective , surtout si on débute !
    En réalité je ne pensais pas que le compilateur buggait(suis encore qu'un jeune étudiant quand j'aurais 20 ans de métier je pourrais peut être accusé le compilateur :p) mais plutôt la compilation, j'imaginais une version différente d'une lib ou autre. Sans avoir une confiance aveugle en mon niveau en C, j'ai(avais) assez confiance au fonctionnement du programme car il n'a pas tourné que sur mon pc mais sur une dizaine d'ordi différents , Os différents et je n'avais pas de soucis, donc pour moi une erreur de code était à exclure .



    Citation Envoyé par Bktero Voir le message
    Puisque tu es sous Debian, je vais être fou et dire :
    valgrind ./ton_programme.out


    Je vais aussi demander que tu nous montres ta ligne de compilation (notamment les options pour activer les warnings de GCC).

    Que ce soit pour Debian ou arch j'utilise ce Makefile:
    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
     
    CC=gcc -W
    HEADER=-I Header
    VALGRIND=valgrind --leak-check=yes ./main
    EXE=main
    FILE=$*.c
     
    all: main clean
     
    memory-leak: main
    	$(VALGRIND)
     
    main: main.o
    	$(CC) $(HEADER) -o $(EXE) *.o
    main.o: main.c own.o menu.o
    	$(CC) -o $@ -c $(FILE)
    own.o : own.c
    	$(CC) -o $@ -c $(FILE)
    menu.o: menu.c  customer.o order.o
    	$(CC) -o $@ -c $(FILE)
    customer.o: customer.c address.o date.o entity.o 
    	$(CC) -o $@ -c $(FILE)
    address.o: address.c
    	$(CC) -o $@ -c $(FILE)
    date.o: date.c
    	$(CC) -o $@ -c $(FILE)
    entity.o: entity.c
    	$(CC) -o $@ -c $(FILE)
    order.o: order.c line.o product.o 
    	$(CC) -o $@ -c $(FILE)
    line.o: line.c 
    	$(CC) -o $@ -c $(FILE)
    product.o: product.c
    	$(CC) -o $@ -c $(FILE)
     
     
    clean:
    	rm -f *.o
    Ce qui donne quelque chose comme gcc -w -o main *.c
    Comme vous pouvez le voir, j'utilisais déjà valgrind pour tester si mes algorithms généraient des fuites de mémoire ce qui donnais : valgrind --leak-check=yes ./main

    Je viens de l'executé (Honte à moi de ne pas l'avoir fait avant !) et voilà ce qu'il me sort:
    ce qu'il se passe lorse que je lance mon prog et que je me rends dans le menu 2 et qu'il s'ensuit une segmentation fault.
    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
     
    ###############################################################
    #   _____      _     _            _____          _            #
    #  / ____|    (_)   (_)          |  __ \        | |           #
    # | |    _   _ _ ___ _ _ __   ___| |__) |_ _ ___| |     __ _  #
    # | |   | | | | / __| | '_ \ / _ \  ___/ _` / __| |    / _` | #
    # | |___| |_| | \__ \ | | | |  __/ |  | (_| \__ \ |___| (_| | #
    #  \_____\__,_|_|___/_|_| |_|\___|_|   \__,_|___/______\__,_| #
    #                                                             #
    ###############################################################
    		1) Creer une commande
    		2) Afficher l'historique des commandes
    		3) Menu produits
    		4) Menu clients
    		9) Quitter
    > 2
    ==3698== Invalid read of size 8
    ==3698==    at 0x10C70A: mainMenu (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698==  Address 0xffefffec8 is on thread 1's stack
    ==3698==  136 bytes below stack pointer
    ==3698== 
    ==3698== Use of uninitialised value of size 8
    ==3698==    at 0x10CE2C: printAllOrder (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698==    by 0x10C719: mainMenu (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698== 
    ==3698== Invalid read of size 8
    ==3698==    at 0x10CE2C: printAllOrder (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698==    by 0x10C719: mainMenu (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
    ==3698== 
    ==3698== 
    ==3698== Process terminating with default action of signal 11 (SIGSEGV)
    ==3698==  Access not within mapped region at address 0x8
    ==3698==    at 0x10CE2C: printAllOrder (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698==    by 0x10C719: mainMenu (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3698==  If you believe this happened as a result of a stack
    ==3698==  overflow in your program's main thread (unlikely but
    ==3698==  possible), you can try to increase the size of the
    ==3698==  main thread stack using the --main-stacksize= flag.
    ==3698==  The main thread stack size used in this run was 8388608.
    ==3698== 
    ==3698== HEAP SUMMARY:
    ==3698==     in use at exit: 2,536 bytes in 34 blocks
    ==3698==   total heap usage: 92 allocs, 58 frees, 118,220 bytes allocated
    ==3698== 
    ==3698== LEAK SUMMARY:
    ==3698==    definitely lost: 0 bytes in 0 blocks
    ==3698==    indirectly lost: 0 bytes in 0 blocks
    ==3698==      possibly lost: 0 bytes in 0 blocks
    ==3698==    still reachable: 2,536 bytes in 34 blocks
    ==3698==         suppressed: 0 bytes in 0 blocks
    ==3698== Reachable blocks (those to which a pointer was found) are not shown.
    ==3698== To see them, rerun with: --leak-check=full --show-leak-kinds=all
    ==3698== 
    ==3698== For counts of detected and suppressed errors, rerun with: -v
    ==3698== Use --track-origins=yes to see where uninitialised values come from
    ==3698== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
    Makefile:10: recipe for target 'memory-leak' failed
    make: *** [memory-leak] Segmentation fault

    Et si je ne fait que l'allocation d'un Customer voilà ce que me donne Valgrind:
    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
     
    #########################################################
    #  __  __                     _____ _ _            _    #
    # |  \/  |                   / ____| (_)          | |   #
    # | \  / | ___ _ __  _   _  | |    | |_  ___ _ __ | |_  #
    # | |\/| |/ _ \ '_ \| | | | | |    | | |/ _ \ '_ \| __| #
    # | |  | |  __/ | | | |_| | | |____| | |  __/ | | | |_  #
    # |_|  |_|\___|_| |_|\__,_|  \_____|_|_|\___|_| |_|\__| #
    #                                                       #
    #########################################################
    * Nom : teste
    * Prenom : test
    * Etes-vous un Homme ? (y|n)
    > y
    ==3901== Use of uninitialised value of size 8
    ==3901==    at 0x10B8A1: makeEntity (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3901== 
    ==3901== Invalid write of size 1
    ==3901==    at 0x10B8A1: makeEntity (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3901==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==3901== 
    ==3901== 
    ==3901== Process terminating with default action of signal 11 (SIGSEGV)
    ==3901==  Access not within mapped region at address 0x0
    ==3901==    at 0x10B8A1: makeEntity (in /home/mochiwa/Downloads/PAP_PORJECT(1)/PAP_PORJECT/main)
    ==3901==  If you believe this happened as a result of a stack
    ==3901==  overflow in your program's main thread (unlikely but
    ==3901==  possible), you can try to increase the size of the
    ==3901==  main thread stack using the --main-stacksize= flag.
    ==3901==  The main thread stack size used in this run was 8388608.
    ==3901== 
    ==3901== HEAP SUMMARY:
    ==3901==     in use at exit: 320 bytes in 1 blocks
    ==3901==   total heap usage: 3 allocs, 2 frees, 2,368 bytes allocated
    ==3901== 
    ==3901== LEAK SUMMARY:
    ==3901==    definitely lost: 0 bytes in 0 blocks
    ==3901==    indirectly lost: 0 bytes in 0 blocks
    ==3901==      possibly lost: 0 bytes in 0 blocks
    ==3901==    still reachable: 320 bytes in 1 blocks
    ==3901==         suppressed: 0 bytes in 0 blocks
    ==3901== Reachable blocks (those to which a pointer was found) are not shown.
    ==3901== To see them, rerun with: --leak-check=full --show-leak-kinds=all
    ==3901== 
    ==3901== For counts of detected and suppressed errors, rerun with: -v
    ==3901== Use --track-origins=yes to see where uninitialised values come from
    ==3901== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
    Makefile:10: recipe for target 'memory-leak' failed
    make: *** [memory-leak] Segmentation fault
    Du coup je crois que j'ai cerné l'erreur....
    ma fonction d'allocation est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void *alloc(const size_t size)
    {
    	void *ptr=NULL;
    	if((ptr=malloc(size))==NULL)
    		exitFail("ALLOCATION DYNAMIQUE IMPOSSIBLE");
    	return ptr;
    }
    qui renvoit donc un void qu'il faut casté , le problème ne serais pas dù à une taille incorrecte ?

  10. #10
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : juin 2002
    Messages : 2 165
    Points : 4 605
    Points
    4 605
    Par défaut
    Citation Envoyé par mochiwa Voir le message
    Du coup je crois que j'ai cerné l'erreur....
    ma fonction d'allocation est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void *alloc(const size_t size)
    {
    	void *ptr=NULL;
    	if((ptr=malloc(size))==NULL)
    		exitFail("ALLOCATION DYNAMIQUE IMPOSSIBLE");
    	return ptr;
    }
    qui renvoit donc un void qu'il faut casté , le problème ne serais pas dù à une taille incorrecte ?
    Vu les adresses que donne valgrind, je pense plutôt qu'à un moment tu manipules un pointeur nul.

    Au passage, vu les tests rapides que j'ai fait ce matin, tu as un souci juste en choisissant 9 dans le menu principal sans rien faire d'autre.

  11. #11
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 630
    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 : 9 630
    Points : 26 305
    Points
    26 305
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Bktero Voir le message
    Puisque tu es sous Debian, je vais être fou et dire :
    valgrind ./ton_programme.out
    Whaou, quelle audacieuse témérité tu nous fais là

    Citation Envoyé par mochiwa Voir le message
    Du coup je crois que j'ai cerné l'erreur....
    ma fonction d'allocation est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void *alloc(const size_t size)
    {
    	void *ptr=NULL;
    	if((ptr=malloc(size))==NULL)
    		exitFail("ALLOCATION DYNAMIQUE IMPOSSIBLE");
    	return ptr;
    }
    qui renvoit donc un void qu'il faut casté
    Non. Un pointeur "void*" est un pointeur universel qu'on peut donc récupérer dans n'importe quel pointeur sans besoin de le caster. Il y a même eu sur ce forum il y a quelque temps un grand débat sur la nécessité ou pas de caster malloc() avec de très bons arguments dans les deux cas (et perso je préfère ne pas caster). Donc l'erreur ne vient pas de là. Tout ce qu'on peut te reprocher c'est de sortir du programme en cas d'échec ce qui ne doit jamais se faire (si une sous-fonction rencontre un souci elle doit le renvoyer à son appelant qui gère alors le cas et qui peut alors soit assumer soit remonte le souci à son propre appelant et etc jusqu'au main). Mais ce n'est pas la cause principale. Et tu peux le vérifier en remplaçant tes appels à ta fonctiion alloc() par des appels à la fonction d'origine malloc() qui n'est pas bien différente. Si l'erreur se reproduit c'est que ça ne vient pas de là.

    Citation Envoyé par mochiwa Voir le message
    Remarquéez qu'il n'y a, au niveau du Customer, aucune différence avec le code précédent la seul différence dans ce code est que je crée avant ou après une autre entité ArrayCustomer.

    Et c'est maintenant que ça devient marrant !
    Si je reexecute le premier code qui fonctionnait bien , je me retrouve denouveau avec une segmentation fault au même endroit .
    C'est typique du comportement indéterminé. Ca fonctionne puis on rajoute un truc con style printf("Hello") et ça ne fonctionne plus.
    Le souci de ton test est qu'il n'est pas reproductible ici (il fait appel à plein de sous-fonctions qu'il faudrait soit récupérer soit shunter). Donc il faut récupérer tout le source du projet. Or j'ai pas le temps maintenant mais je le prendrai plus tard pour récupérer ton source et le regarder tranquilement.

    Citation Envoyé par mochiwa Voir le message
    le problème ne serais pas dù à une taille incorrecte ?
    Tu peux contrôler ça via un assert (size > 0) en début de fonction...
    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

  12. #12
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    4 384
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : juin 2009
    Messages : 4 384
    Points : 13 214
    Points
    13 214
    Billets dans le blog
    1
    Par défaut
    CC=gcc -W

    Ce qui donne quelque chose comme gcc -w -o main *.c
    Woh woh ! -w en minuscule, ça inhibe tous les warnings, il ne faut jamais utiliser cette option. Bon, ton makefile semble avoir -W en majuscule, qui est alias deprecated de -Wextra :
    Citation Envoyé par https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
    This enables some extra warning flags that are not enabled by -Wall. (This option used to be called -W. The older name is still supported, but the newer name is more descriptive.)
    Il faut vraiment que tu rajoutes -Wall pour avoir le minimum vital à savoir -Wall -Wextra. On en a discuté récemment sur le forum C++ (mais ça s'applique parfaitement au C) : https://www.developpez.net/forums/d1.../#post10414059

  13. #13
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par gl Voir le message
    Vu les adresses que donne valgrind, je pense plutôt qu'à un moment tu manipules un pointeur nul.

    Au passage, vu les tests rapides que j'ai fait ce matin, tu as un souci juste en choisissant 9 dans le menu principal sans rien faire d'autre.
    Bonjour gl, j'ai bien lus votre message ce matin , et j'étais justement occupé de testé où se perdent mes pointers. j'ai également essayé ce matin la compilation sur windows avec gcc 5 (fournis avec code block) et gcc 8 le programme fonctionnais sans erreur lors de la sortie en utilisant l'option 9 . Toutefois l'erreur que vous me signalé je l'ai également mais sur debian, j'ai donc creusé un peux et les fonctions d'allocation et de libération de mémoire sont hors cause ! (bonne nouvelle pour moi ça :p)

    La fonction fautive je crois l'avoir trouvé et elle est fourbe et incompréensible pour moi du moins pour le moment.Dans l'intégralité de mon code j'utile des fonctions sécurisées pour obtenir des informations tapées
    Les voici :
    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
     
    int readInt()
    {
    	char tab[10];
    	initString(tab,10);
    	read(tab,10);
    	return strtol(tab,NULL,10);
    }
     
    float readFloat()
    {
    	char tab[30];
    	initString(tab,30);
    	read(tab,30);
    	return strtof(tab,NULL);
    }
     
    int isValid(const char *string)
    {
    	char *c=malloc(sizeof(char)*2);
    	do{
    		printf("%s (y|n)\n> ",string );
    		read(c,2);
    	}while(c[0]!='y' && c[0]!='n');
     
    	if(c[0]=='y')
    	{
    		free(c);
    		return 1;
     
    	}
    	return 0;
    }
    Elles ont toute en commun :
    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
     
    int read(char *string,const size_t lenght)
    {
    	char *ptr=NULL;
    	if(lenght<1)
    		return 1;
    	if(fgets(string,lenght,stdin))
    	{
    		ptr=strchr(string,'\n');
    		if(ptr!=NULL)
    			*ptr='\0';
    		else
    			clearBuffer();
    		return 0;
    	}
    	clearBuffer();
    	return 1;
    }
    Fonction qui ajoute un \0 à la fin d'un tableau de char cela pour évité les Buffer overflow.
    Je vais procédé à quelques testes et je reviens vers vous.

    Citation Envoyé par Bktero Voir le message
    Woh woh ! -w en minuscule, ça inhibe tous les warnings, il ne faut jamais utiliser cette option. Bon, ton makefile semble avoir -W en majuscule, qui est alias deprecated de -Wextra :


    Il faut vraiment que tu rajoutes -Wextra pour avoir le minimum vital à savoir -Wall -Wextra. On en a discuté récemment sur le forum C++ (mais ça s'applique parfaitement au C) : https://www.developpez.net/forums/d1.../#post10414059
    -Oui désolé j'utilise bien -W et non -w sorry faute de frappe.
    -Merci pour l'info sur le -W deprecated !
    Citation Envoyé par Sve@r Voir le message
    Tout ce qu'on peut te reprocher c'est de sortir du programme en cas d'échec ce qui ne doit jamais se faire (si une sous-fonction rencontre un souci elle doit le renvoyer à son appelant qui gère alors le cas et qui peut alors soit assumer soit remonte le souci à son propre appelant et etc jusqu'au main)
    -J'ai toujours cru que face à une erreur d'allocation il fallait mieux quitter le programme, je retiens !
    Dernière modification par Invité ; 28/08/2018 à 13h21.

  14. #14
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 630
    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 : 9 630
    Points : 26 305
    Points
    26 305
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mochiwa Voir le message
    La fonction fautive je crois l'avoir trouvé et elle est fourbe et incompréensible pour moi du moins pour le moment.Dans l'intégralité de mon code j'utile des fonctions sécurisées pour obtenir des informations tapées
    Les voici :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int readInt()
    {
    	char tab[10];
    	initString(tab,10);
    	read(tab,10);
    	return strtol(tab,NULL,10);
    }
    Petit souci ici: tu initialises un tableau de 10 char en le transformant en chaine (donc je présume que initString() placera au-moins un '\0' dans ce tableau) mais ensuite tu demandes à read() de remplir 10 charactères => tu peux donc écraser le '\0' précédemment positionné ce qui fait que ta chaine n'en est plus une => interdit alors d'utiliser ensuitestrtoXXX()...

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int readInt()
    {
    	char tab[10 + 1];
    	initString(tab,10 + 1);
    	read(tab,10);
    	return strtol(tab,NULL,10);
    }
    Et pareil pour la saisie en float

    Citation Envoyé par mochiwa 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
    int isValid(const char *string)
    {
    	char *c=malloc(sizeof(char)*2);
    	do{
    		printf("%s (y|n)\n> ",string );
    		read(c,2);
    	}while(c[0]!='y' && c[0]!='n');
     
    	if(c[0]=='y')
    	{
    		free(c);
    		return 1;
     
    	}
    	return 0;
    }
    Celle là risque d'être mémorable dans les pires choses qu'il m'ait été donné de voir
    1) tu alloues 2 caractères alors que tu pourrais utiliser directement un char c[2];
    2) tu n'utilises que le premier caractère sur les deux alloués (enfin je pense que le second contient un '\n'),
    3) tu ne libères la zone allouée que si on répond "y". C'est vrai que quand on répond "n", c'est qu'on ne veut pas donc on ne libère pas => logique !!!

    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
    int isValid(const char *string) {
    	typedef struct {
    		char *mot;
    		unsigned short val;
    	} t_rep;
    	t_rep rep[]={
    		{"oui", 1},
    		{"yes", 1},
    		{"y", 1},
    		{"non", 0},
    		{"no", 0},
    		{"n", 0},
    		{NULL, 0},
    	};
    	t_rep *pt
    	char saisie[100];
    	char *c;
    	while (1) {
    		printf("%s (y|n)\n> ", string);
    		fgets(saisie, 100, stdin);
     
    		// Suppression du '\n'
    		if ((c=strchr(saisie, '\n')) != NULL) *c='\0';
     
    		// Examen de la réponse et renvoi valeur correspondante
    		for (pt=rep; pt->mot != NULL; pt++) {
    			if (strcmp(pt->mot, saisie) == 0) return pt->val;
    		}
    	}
    }
    C'est pas un peu plus classe ???

    Citation Envoyé par mochiwa Voir le message
    Elles ont toute en commun :
    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
    int read(char *string,const size_t lenght)
    {
    	char *ptr=NULL;
    	if(lenght<1)
    		return 1;
    	if(fgets(string,lenght,stdin))
    	{
    		ptr=strchr(string,'\n');
    		if(ptr!=NULL)
    			*ptr='\0';
    		else
    			clearBuffer();
    		return 0;
    	}
    	clearBuffer();
    	return 1;
    }
    Ok, je vois à peu près ce que tu fais. Tu fais une saisie dans laquelle tu shunte le '\n'. Ok ça élimine ma première remarque sur le '\0' potentiellement écrasé (mais mon code correctif avec "10 + 1" peut rester tout de même car ça rend les deux fonctions indépendantes l'une de l'autre ce qui est toujours une bonne chose car ça permet ensuite de changer de fonction de lecture sans s'inquiéter de l'écrasement potentiel du '\0'). Toutefois perso j'aurais pas appelé la zone réceptrice "string" car généralement j'associe plutôt ça à un truc à afficher qu'à faire saisir => goûts et couleurs...
    On pourrait avoir le code de clearBuffer() ? Pour moi il devrait ressembler à ça
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void clearBuffer() {
    	while (fgetc(stdin) != EOF);
    }
    En tout cas j'emets tout de même de plus en plus de réserves sur ton code de quelques milliers de lignes "garanti sans erreurs"...
    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

  15. #15
    Invité
    Invité(e)
    Par défaut
    [QUOTE=Bktero;10439075]

    Citation Envoyé par Sve@r Voir le message
    Petit souci ici: tu initialises un tableau de 10 char en le transformant en chaine (donc je présume que initString() placera au-moins un '\0' dans ce tableau) mais ensuite tu demandes à read() de remplir 10 charactères => tu peux donc écraser le '\0' précédemment positionné ce qui fait que ta chaine n'en est plus une => interdit alors d'utiliser ensuitestrtoXXX()...

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int readInt()
    {
    	char tab[10 + 1];
    	initString(tab,10 + 1);
    	read(tab,10);
    	return strtol(tab,NULL,10);
    }
    Et pareil pour la saisie en float


    Celle là risque d'être mémorable dans les pires choses qu'il m'ait été donné de voir
    1) tu alloues 2 caractères alors que tu pourrais utiliser directement un char c[2];
    2) tu n'utilises que le premier caractère sur les deux alloués (enfin je pense que le second contient un '\n'),
    3) tu ne libères la zone allouée que si on répond "y". C'est vrai que quand on répond "n", c'est qu'on ne veut pas donc on ne libère pas => logique !!!
    Aie m'a faut cela ne correspond pas au code ... c'est un test que je viens de faire et je l'ai maladroitement copié ...
    Voici le vrai isValid()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int isValid(const char *string)
    {
    	char c[1];
    	do{
    		printf("%s (y|n)\n> ",string );
    		read(c,2);
    	}while(c[0]!='y' && c[0]!='n');
     
    	if(c[0]=='y')
    		return 1;
    	return 0;
    }
    Quant à la fonction read sont seul but est de sécurisé le scanf et elle me semble correcte car quoi qu'il arrive le dernier element du tableau sera \0

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    void clearBuffer()
    {
    	char c=0;
    	while(c!='\n' && c!=EOF)
    		c=getchar();
    }
    Dernière modification par Invité ; 28/08/2018 à 14h19.

  16. #16
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 630
    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 : 9 630
    Points : 26 305
    Points
    26 305
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mochiwa Voir le message
    Voici le vrai isValid()
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int isValid(const char *string)
    {
    	char c[1];
    	do{
    		printf("%s (y|n)\n> ",string );
    		read(c,2);
    	}while(c[0]!='y' && c[0]!='n');
     
    	if(c[0]=='y')
    		return 1;
    	return 0;
    }
    Classe !!! Tu définis un tableau de "1 caractère" (dans ce cas, autant écrire directement char c; !!!) et tu demandes à read() d'y mettre 2 caractères. Tu sens où je veux en venir ou bien ça reste encore un peu flou ???

    Citation Envoyé par mochiwa Voir le message
    mais je peux assuré à 100% que le code n'a aucune erreur.


    Citation Envoyé par mochiwa Voir le message
    Quant à la fonction read sont seul but est de sécurisé le scanf et elle me semble correcte car quoi qu'il arrive le dernier element du tableau sera \0
    Oui, j'ai pas dit qu'elle était incorrecte (toutefois avec scanf() tu as aussi un '\0'). Mais bon, on peut l'écrire plus simplement (Simple is better than complex).
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int read(char *saisie, const size_t lenght) {
    	char *c;
    	if (lenght < 1) return 1;
    	c=fgets(saisie, lenght, stdin);
    	clearBuffer();		// Je l'ai mis ici car ça correspond à ce que tu avais écrit mais je pense que c'est inutile vu que si fgets() renvoie NULL c'est que stdin est déjà vide
    	if (c == NULL) return 1;
    	if ((c=strchr(saisie, '\n')) != NULL) *c='\0';
    	return 0;
    }

    Citation Envoyé par mochiwa Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void clearBuffer()
    {
    	char c=0;
    	while(c!='\n' && c!=EOF)
    		c=getchar();
    }
    Ouais, je me doutais que ce serait cette fonction (qu'on trouve aussi dans la faq de ce forum).
    Bon déjà getchar() ne renvoie pas un char mais un int (déjà dit par Bousk). Ca a son importance parce que comparer un char valant 0xff (dernier des caractères ascii) avec EOF (soit -1 soit aussi 0xff quand on le tronque sur un char) sera vraie ; tandis que comparer un int contenant le dernier des ascii (donc dans ce cas 0x00ff) avec EOF (qui, là, en int, vaut 0xffff) sera faux. Ainsi si "stdin" contient à un moment donné le dernier ascii de la table ta fonction s'arrête alors qu'elle ne devrait pas.
    De plus, cette fonction ne vide "stdin" que jusqu'à son premier "\n". Or une fonction dénommée "clearBuffer()" est supposée (d'après son nom) vider tout le buffer. Celui qui tape 15 fois sur "return" ne verra son buffer vidé que du premier et gardera les 14 dans sa tronche.
    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

  17. #17
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    4 384
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : juin 2009
    Messages : 4 384
    Points : 13 214
    Points
    13 214
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mochiwa Voir le message
    -Oui désolé j'utilise bien -W et non -w sorry faute de frappe.
    -Merci pour l'info sur le -W deprecated !
    Oui mais encore As-tu tenté de compiler ton programme avec des options un peu plus agressives ?

    Moi je viens d'essayer en modifiant la première ligne de ton Makefile pour avoir ça :
    CC=gcc -Wall -Wextra -pedantic -Wwrite-strings
    J'obtiens ceci :
    λ mingw32-make.exe
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o own.o -c own.c
    own.c: In function 'openFile':
    own.c:106:13: warning: passing argument 1 of 'exitFail' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    exitFail("Impossible d'ouvrir le fichier!");
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    In file included from own.c:1:0:
    Header/own.h:420:6: note: expected 'char *' but argument is of type 'const char *'
    void exitFail(char *str);
    ^~~~~~~~
    own.c: In function 'alloc':
    own.c:202:12: warning: passing argument 1 of 'exitFail' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    exitFail("ALLOCATION DYNAMIQUE IMPOSSIBLE");
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    In file included from own.c:1:0:
    Header/own.h:420:6: note: expected 'char *' but argument is of type 'const char *'
    void exitFail(char *str);
    ^~~~~~~~
    own.c: In function 'writeCpy':
    own.c:382:12: warning: passing argument 1 of 'exitFail' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    exitFail("CAN'T OPEN(write) FILE ");
    ^~~~~~~~~~~~~~~~~~~~~~~~~
    own.c:311:6: note: expected 'char *' but argument is of type 'const char *'
    void exitFail(char *str)
    ^~~~~~~~
    own.c: In function 'loadCpy':
    own.c:394:12: warning: passing argument 1 of 'exitFail' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    exitFail("CAN'T OPEN(read) FILE");
    ^~~~~~~~~~~~~~~~~~~~~~~
    own.c:311:6: note: expected 'char *' but argument is of type 'const char *'
    void exitFail(char *str)
    ^~~~~~~~
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o address.o -c address.c
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o date.o -c date.c
    date.c: In function 'getMonthToString':
    date.c:10:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Janvier";
    ^~~~~~~~~
    date.c:12:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Fevrier";
    ^~~~~~~~~
    date.c:14:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Mars";
    ^~~~~~
    date.c:16:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Avril";
    ^~~~~~~
    date.c:18:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Mais";
    ^~~~~~
    date.c:20:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Juin";
    ^~~~~~
    date.c:22:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Juillet";
    ^~~~~~~~~
    date.c:24:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Aout";
    ^~~~~~
    date.c:26:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Septembre";
    ^~~~~~~~~~~
    date.c:28:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Octobre";
    ^~~~~~~~~
    date.c:30:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Novembre";
    ^~~~~~~~~~
    date.c:32:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "Decembre";
    ^~~~~~~~~~
    date.c:34:11: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
    return "NULL";
    ^~~~~~
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o entity.o -c entity.c
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o customer.o -c customer.c
    customer.c: In function 'getNextCustomer':
    customer.c:100:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(customer->next==NULL)
    ^
    customer.c: In function 'getPreviousCustomer':
    customer.c:114:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(customer->previous==NULL)
    ^
    customer.c: In function 'getFirstCustomer':
    customer.c:127:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(head!=NULL)
    ^
    customer.c: In function 'getLastCustomer':
    customer.c:137:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(tail!=NULL)
    ^
    customer.c: In function 'editCustomer':
    customer.c:399:23: warning: this statement may fall through [-Wimplicit-fallthrough=]
    customer->isDelete=1;
    ~~~~~~~~~~~~~~~~~~^~
    customer.c:400:4: note: here
    case 9:
    ^~~~
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o line.o -c line.c
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o product.o -c product.c
    product.c: In function 'getNextProduct':
    product.c:106:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(product->next==NULL)
    ^
    product.c: In function 'getPreviousProduct':
    product.c:119:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(product->previous==NULL)
    ^
    product.c: In function 'getFirstProduct':
    product.c:132:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(array->head!=NULL)
    ^
    product.c: In function 'getLastProduct':
    product.c:142:4: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
    if(array->tail!=NULL)
    ^
    product.c: In function 'editProduct':
    product.c:262:22: warning: this statement may fall through [-Wimplicit-fallthrough=]
    product->isDelete=1;
    ~~~~~~~~~~~~~~~~~^~
    product.c:263:4: note: here
    case 9:
    ^~~~
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o order.o -c order.c
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o menu.o -c menu.c
    gcc -Wall -Wextra -pedantic -Wwrite-strings -o main.o -c main.c
    main.c: In function 'main':
    main.c:5:14: warning: unused parameter 'argc' [-Wunused-parameter]
    int main(int argc, char const *argv[])
    ^~~~
    main.c:5:32: warning: unused parameter 'argv' [-Wunused-parameter]
    int main(int argc, char const *argv[])
    ^~~~
    gcc -Wall -Wextra -pedantic -Wwrite-strings -I Header -o main *.o
    rm -f *.o
    1. Les [-Wdiscarded-qualifiers] viennent de -Wwrite-strings. Peut-être rien de grave ici mais il y a des risques d'erreurs de segmentation.
    2. Les [-Wdangling-else] viennent de -Wall. Peut-être rien de grave ici mais cela peut être signe d'erreur de logiques.
    3. Les [-Wimplicit-fallthrough=] viennent de -Wextra. Ils étaient normalement déjà là quand tu compilais. Même chose que pour le point précédent.


    Ce n'est peut-être rien, mais beaucoup de ces warnings méritent d'être corrigés. Ça lèvera des doutes pour la suite du projet.

  18. #18
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Classe !!! Tu définis un tableau de "1 caractère" (dans ce cas, autant écrire directement char c; !!!) et tu demandes à read() d'y mettre 2 caractères. Tu sens où je veux en venir ou bien ça reste encore un peu flou ???





    Oui, j'ai pas dit qu'elle était incorrecte (toutefois avec scanf() tu as aussi un '\0'). Mais bon, on peut l'écrire plus simplement (Simple is better than complex).
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int read(char *saisie, const size_t lenght) {
    	char *c;
    	if (lenght < 1) return 1;
    	c=fgets(saisie, lenght, stdin);
    	clearBuffer();		// Je l'ai mis ici car ça correspond à ce que tu avais écrit mais je pense que c'est inutile vu que si fgets() renvoie NULL c'est que stdin est déjà vide
    	if (c == NULL) return 1;
    	if ((c=strchr(saisie, '\n')) != NULL) *c='\0';
    	return 0;
    }


    Ouais, je me doutais que ce serait cette fonction (qu'on trouve aussi dans la faq de ce forum).
    Bon déjà getchar() ne renvoie pas un char mais un int (déjà dit par Bousk). Ca a son importance parce que comparer un char valant 0xff (dernier des caractères ascii) avec EOF (soit -1 soit aussi 0xff quand on le tronque sur un char) sera vraie ; tandis que comparer un int contenant le dernier des ascii (donc dans ce cas 0x00ff) avec EOF (qui, là, en int, vaut 0xffff) sera faux. Ainsi si "stdin" contient à un moment donné le dernier ascii de la table ta fonction s'arrête alors qu'elle ne devrait pas.
    De plus, cette fonction ne vide "stdin" que jusqu'à son premier "\n". Or une fonction dénommée "clearBuffer()" est supposée (d'après son nom) vider tout le buffer. Celui qui tape 15 fois sur "return" ne verra son buffer vidé que du premier et gardera les 14 dans sa tronche.

    GG vous avez résolu le problème, cela venais d'une mauvaise comprehension de la fonction fgets ... en effet dans la description de la fonction on n'a:
    char * fgets ( char * str, int num, FILE * stream );
    str
    Pointer to an array of chars where the string read is copied.
    num
    Maximum number of characters to be copied into str (including the terminating null-character).
    stream
    Pointer to a FILE object that identifies an input stream.
    stdin can be used as argument to read from the standard input.
    Pour moi le " (including the terminating null-character) " signifiait qu'il falait le compter en plus
    ex: un tab de 1 = 2 case mémoire donc num=2 ...

    Par contre une question reste en suspend .. Pourquoi cela fonctionnais et fonctionne toujours très bien sur Antergos et Windows7 ?

    Merci beaucoup pour le temps passé dessu c'est super sympa !

  19. #19
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    février 2006
    Messages
    9 630
    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 : 9 630
    Points : 26 305
    Points
    26 305
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par mochiwa Voir le message
    Pour moi le " (including the terminating null-character) " signifiait qu'il falait le compter en plus
    ex: un tab de 1 = 2 case mémoire donc num=2 ...
    Tu as raisonné à l'envers. Si une fonction t'indique qu'elle rajoute le null-character alors toi tu dois prendre en compte ce rajout et donc prévoir de ton côté l'espace pour le stocker. Parce que la fonction ne peut pas réserver l'espace à ta place !!!
    C'est pour ça que pour mes strings de X j'écris toujours char string[X + 1] => pour que le lecteur futur sache que j'ai pensé au '\0'.
    Une toute petite exception avec fgets() car cette fonction enlève "1" à la taille demandée (si tu demandes fgets(zone, 50, stdin) la fonction ne récupèrera alors que 49 caractères) pour pouvoir y stocker le '\0'.
    Et donc dans ce cas, si je veux saisir "string" j'écris alors fgets(string, X+1, stdin) là encore pour que le lecteur futur sache que je sais que fgets() enlève "1".

    Citation Envoyé par mochiwa Voir le message
    Par contre une question reste en suspend .. Pourquoi cela fonctionnais et fonctionne toujours très bien sur Antergos et Windows7 ?
    Comportement indéterminé. C'est la pire des situations qui peut se produire en C => le code est incorrect mais fonctionne "par chance". Sauf que la chance ça dure pas. Et puis si W7 était une référence en terme de programmation (ou même en terme de quoi que ce soit) ça se saurait...
    Par ailleurs tu as beaucoup de warnings. Suis les conseils de Bktero. Un warning c'est un message du compilateur qui dit "je ne suis pas certain d'avoir bien compris ce que vous voulez faire alors je vais tenter un truc mais si ça marche pas c'est pas ma faute" => c'est pas super rassurant quoi !!!
    Un code vraiment correct ne doit produire aucun warning.

    Citation Envoyé par mochiwa Voir le message
    Merci beaucoup pour le temps passé dessu c'est super sympa !
    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

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 07/11/2009, 14h02
  2. Réponses: 7
    Dernier message: 20/07/2009, 20h43
  3. execution sur l'emulateur mais non pas sur le Pocket PC
    Par inter_amine dans le forum Windows Mobile
    Réponses: 2
    Dernier message: 08/06/2007, 10h35
  4. Réponses: 1
    Dernier message: 17/10/2005, 23h47
  5. Réponses: 2
    Dernier message: 07/07/2005, 09h31

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