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 :

Problème compilation dû à une structure


Sujet :

C

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut Problème compilation dû à une structure
    Bonjour à toutes et à tous, et au passage joyeuses fêtes.

    Je vous remercie tout d'abord de votre attention et du temps pris pour me répondre.
    Je m'excuse d'avance auprès des modérateurs si jamais mon topic est mal placé.

    Je suis actuellement étudiant en informatique, débutant en c, et j'ai un projet consistant à réaliser une bibliothèque de fonctions permettant d'utiliser des BigInteger (de grands entiers quoi).

    Je m'en sors plutôt bien pour le moment sauf que j'ai un problème lors de la compilation de mon programme.

    En effet j'ai une fonction newBigInteger qui me permet de transformer une chaîne de caractère en une liste doublement chainée qui regroupe par 4 les caractères et les inverse (apparemment c'est mieux ainsi d'après mon professeur). J'ai donc une structure BigInteger qui à comme éléments le signe (un entier) et une liste doublement chainée (ma chaine de caractère transformée).

    je vous joins le code et vous explique mon problème.

    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
    typedef struct elem // Structure de la liste doublement chainée
    {
    	int valeur;
    	struct elem* precedent;
    	struct elem* suivant;
    
    } element;
    typedef element *DLlist;
    
    typedef struct // Structure BigInteger : un signe + une liste doublement chaînée
    {
        int sign;
        DLlist list;
    
    } dlstruct;
    
    typedef dlstruct *BigInteger;
    
    /* ***** FONCTIONS ***** */
    
    // newBigInteger
    
    BigInteger newBigInteger (char* chaine)
    {	
    	BigInteger b;
    	char* testchaine;
    
    	if (chaine==NULL)
    		exit(EXIT_FAILURE);
    	else
    	{
    		testchaine=strchr(chaine,'-');
    		if (testchaine==NULL)
    			b->sign=1;
    		else 
    		{		
    			b->sign=-1;
    			chaine++;
    		}
    		char *chaine2;
        		int longueur = strlen(chaine);  // Longueur est égale à la taille du nombre donné
        		DLlist l = creer(); // fonction qui permet de creer une liste vide
    		DLlist tmp;
    		int i = 4;
    		int a,b;
    
        		while(i<longueur)
    		{
            		chaine2= (&chaine[longueur-i]); 
    			a=atoi(chaine2);
    			ajouterq(l,a); /* fonction qui permet d'ajouter en queue de ma liste l'élément a */
    			chaine[longueur-i]='\0';
    			i=i+4;
    		}
    		b=atoi(chaine);
    		ajouterq(l,b);
    		tmp=supprimert(l); // fonction qui permet de supprimer la tête de ma liste
    		b->list=tmp; // ERROR : le problème est ici
    		
    	}
    	return b;
    }
    (ceci n'est qu'une partie de mon code car celui ci est très long....)

    Lorsque je compile mon programme, gcc me retourne:
    erreur: invalid type argument of ‘->’ (have ‘int’)
    b->list=tmp;
    ^

    J'ai eu beau chercher sur internet je n'arrive pas à trouver la solution... Puisque dans la suite, je réutilise "b->list" et il ne me considère plus celà comme une erreur...

    Je vous remercie encore du temps pris pour lire mon pavé juste immonde et pour le dérangement.
    Je m'excuse pour l'affichage désastreux de mon code.

    Merci.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Bonjour et bienvenue,

    Ton message est exactement à la bonne place (C→Débuter) et pour tout dire, cela fait plaisir de voir une demande rédigée comme la tienne, avec l'orthographe, les accents, la ponctuation, le code avec les bonnes balises et les formules de politesse ! Merci, donc, de nous aider à conserver un forum propre.

    Avant toute chose, sache que même si c'est une pratique très répandue dans les écoles, masquer un pointeur dans un typedef est une très mauvaise habitude, à ne jamais prendre en langage C.

    Ton problème vient du fait que tu as redéclaré « b ». Une fois en ligne 25 :
    … et une autre en ligne 45 :
    La variable la plus locale à un bloc masque les précédentes pendant la durée de son existence. J'ajoute également que le C original et C89 imposent que toutes les variables soient déclarées en début de bloc. C99 lève cette interdiction mais c'est toujours une bonne idée de conserver l'habitude de le faire quand même, car ces variables locales iront quand même dans la pile et, dans le cas contraire, quand un bloc commence à être long, il devient difficile de savoir si la variable référencée est celle locale au bloc ou la précédente ainsi que, le cas échéant, de retrouver la déclaration de la variable en question.

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Citation Envoyé par Obsidian Voir le message
    Ton problème vient du fait que tu as redéclaré « b ». Une fois en ligne 25 :
    … et une autre en ligne 45 :
    ...mais c'est toujours une bonne idée de conserver l'habitude de le faire quand même, car ces variables locales iront quand même dans la pile et, dans le cas contraire, quand un bloc commence à être long, il devient difficile de savoir si la variable référencée est celle locale au bloc ou la précédente ainsi que, le cas échéant, de retrouver la déclaration de la variable en question.
    Bonjour
    Moi je rajouterais que si tu prends l'habitude de mettre des noms plus explicites que "a", "b" ou "c" tu risques moins de faire ce genre d'erreur...

    Citation Envoyé par Zthoustra 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
    int a,b;
     
    while(i<longueur)
    {
    	chaine2= (&chaine[longueur-i]); 
    	a=atoi(chaine2);
    	ajouterq(l,a); /* fonction qui permet d'ajouter en queue de ma liste l'élément a */
    	chaine[longueur-i]='\0';
    	i=i+4;
    }
    b=atoi(chaine);
    ajouterq(l,b);
    ...surtout que ici, la variable "b" est totalement inutile. Déjà tu peux réutiliser "a" qui ne sert plus après le while mais surtout tu peux utiliser directement atoi() => ajouterq(l, atoi(chaine)); (et pareil avec "a" qui n'est pas plus utile non plus)...

    PS: et peut-être aussi remplacer ce "4" par sizeof(int) pour être plus portable...
    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]

  4. #4
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    Tout d'abord merci pour vos réponses claires précises. Effectivement, mon erreur était stupide et je m'excuse de vous avoir dérangé pour si peu...


    J'ai en revanche une nouvelle question. Maintenant je n'ai plus de problèmes au niveau de la compilation. Par contre, lorsque je lance mon programme il me dit qu'il y a une erreur de segmentation (core dumped)...Savez vous pourquoi? Sinon je peux rajouter la suite de mon code pour comprendre....

    Merci encore.

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    J'ai en revanche une nouvelle question. Maintenant je n'ai plus de problèmes au niveau de la compilation. Par contre, lorsque je lance mon programme il me dit qu'il y a une erreur de segmentation (core dumped)...Savez vous pourquoi? Sinon je peux rajouter la suite de mon code pour comprendre....
    Une erreur de segmentation est une « segfault ». Ça veut dire que ton processus a tenté de lire ou d'écrire en mémoire mais en dehors du segment qui lui était alloué (et donc d'écraser ses petits copains voire même le système d'exploitation lui-même).

    C'est une erreur très fréquente en C et cela signifie que tu as soit un pointeur invalide quelque part (à 90 %), soit que tu dépasses la limite d'un tableau (si tu essais d'écrire dans le 11ème élément d'un tableau qui n'en compte que 10, le C ne t'empêchera pas de le faire), soit que tu fais un débordement de pile quelque part (spécialement vrai avec les fonctions récursives), soit que tu essaies d'accéder à de la mémoire que tu as déjà libéré au préalable, ou encore que tu essaies de la libérer une seconde fois.

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Sinon je peux rajouter la suite de mon code pour comprendre....
    Je pense que là ce sera indispensable...
    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]

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    Ok merci pour vos réponses toujours aussi rapides !

    Tout est lié à ma chaine de caractère du moins je le pense. Car j'ai fais différents test...

    Je vous explique ce que je pense être le problème. L'utilisateur du programme doit rentrer une chaine de caractère quelconque qui peut contenir 10000 caractères...Je pense donc que c'est possible mais c'est surement pour celà que mon programme plante (je dois faire péter la pile)...

    Le problème est qu'on ne peut pas prévoir la taille de cette chaine...

    Du coup je vous met la suite du code (mon main) pour plus de compréhension (car je n'ai pas l'impression d'être très clair)...

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "biginteger.h"
    #include "liste_doublmt_chainee.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** Fonction principale ***** */
     
    int main()
    {
        int choixMenu=0;
    	char *chaine;
     
        printf("\n~~~~ Menu ~~~~\n\n");
        printf("1:  newBigInteger\n");
        printf("2:  printBigInteger\n");
        printf("3:  isNull\n");
        printf("4:  signBigInt\n");
        printf("5:  equalsBigInt\n");
        printf("6:  compareBigInt\n");
        printf("7:  sumBigInt\n");
        printf("8:  diffBigInt\n");
        printf("9:  mulBigInt\n");
        printf("11: quotientBigInt\n");
        printf("12: restBigInt\n");
        printf("13: gcdBigInt\n");
        printf("14: lcmBigInt\n");
        printf("15: factorial\n");
        printf("16: cnp\n");
        printf("\n\nVeuillez choisir la fonction à utiliser en entrant le nombre correspondant :");
        scanf("%d", &choixMenu);
     
        switch (choixMenu)
        {
        case 1:
            printf("\n\nTapez le nombre :"); // il m'affiche bien ceci
            scanf(" %s", chaine);
    	printf("\n%s\n", chaine); // et également celà
            newBigInteger(chaine); .
            break;
    }

    Encore merci pour votre attention et votre temps pris pour répondre.

  8. #8
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 480
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 480
    Par défaut
    Re-bonsoir,

    La fonction main() que tu nous présentes ici est incomplète. Cela dit, le problème vient de là :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	char *chaine;
     
            scanf(" %s", chaine);
    	printf("\n%s\n", chaine); // et également celà
    Dans tous les cas, tu dois passer en argument un pointeur vers un endroit suffisamment grand et adapté pour recevoir la donnée qu'il va lire. Quand il s'agit d'un entier, ça ne pose pas de problème : tu passes directement l'adresse d'une variable de même type puisque la taille est fixe.

    Dans le cas d'une chaîne de caractères, en revanche, il faut que tu lui indiques un buffer, que tu auras donc dû allouer au préalable. Quand tu écris « char * chaine », tu déclares un pointeur sur un caractère et, par extension, sur ceux qui suivent, donc sur le début d'une chaîne. Mais ce pointeur ne pointe sur rien du tout a priori.

    Soit tu fais un malloc dont tu récupères le résultat dans ton pointeur « chaine » (sans oublier de le libérer en fin de programme), soit tu déclares directement un tableau à la place :
    Le fait d'invoquer le nom du tableau tout seul renvoie son adresse en mémoire, donc un pointeur de type char, et le reste de ton code demeure compatible.

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Citation Envoyé par Obsidian Voir le message
    Re-bonsoir,

    La fonction main() que tu nous présentes ici est incomplète. Cela dit, le problème vient de là :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	char *chaine;
     
            scanf(" %s", chaine);
    	printf("\n%s\n", chaine); // et également celà
    Dans tous les cas, tu dois passer en argument un pointeur vers un endroit suffisamment grand et adapté pour recevoir la donnée qu'il va lire. Quand il s'agit d'un entier, ça ne pose pas de problème : tu passes directement l'adresse d'une variable de même type puisque la taille est fixe.

    Dans le cas d'une chaîne de caractères, en revanche, il faut que tu lui indiques un buffer, que tu auras donc dû allouer au préalable. Quand tu écris « char * chaine », tu déclares un pointeur sur un caractère et, par extension, sur ceux qui suivent, donc sur le début d'une chaîne. Mais ce pointeur ne pointe sur rien du tout a priori.

    Soit tu fais un malloc dont tu récupères le résultat dans ton pointeur « chaine » (sans oublier de le libérer en fin de programme), soit tu déclares directement un tableau à la place :
    Le fait d'invoquer le nom du tableau tout seul renvoie son adresse en mémoire, donc un pointeur de type char, et le reste de ton code demeure compatible.
    Salut

    Pour compléter, il y a une règle simple à observer avec les pointeurs: quand tu déclares un pointeur style <type>* toto;, tu ne dois jamais taper dans "*toto" si tu ne t'es pas assuré au préalable que toto contienne une adresse valide.
    Ca peut se présenter de plusieurs façons
    • l'adresse est recopiée depuis celle d'une variable préexistante
      Code c : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      int variable;
      int *toto;   // Ici j'ai un pointeur indéterminé
      toto=&variable;   // Ici mon pointeur devient valide
      *toto=123;       // Donc ici je peux le remplir
      printf("La zone pointée contient %d\n", *toto);
    • l'adresse est passée en paramètre d'une fonction. Dans ce cas seulement tu n'as pas à te préoccuper de sa validité car c'est à la charge de l'appelant de la fonction de lui passer un paramètre correct
      Code c : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      void remplir(int *toto /* Je considère que toto est valide */)
      {
          *toto=123;      // Donc ici je peux le remplir
      }
       
      int main()
      {
          int variable;
          remplir(&variable);
          printf("La variable contient %d\n", variable);
      }
    • l'adresse est récupérée depuis une demande d'allocation mémoire (malloc/calloc/realloc). Dans ce cas il est primordial de ne jamais perdre cette adresse car tu dois impérativement la libérer quand tu n'en as plus besoin.
      Code c : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      int *toto;
      toto=malloc(sizeof(int)); // Ici mon pointeur devient valide
      *toto=123;       // Donc ici je peux le remplir
      printf("La zone pointée contient %d\n", *toto);
      free(toto);
      Cette libération est vraiment impérative sinon tu perds la mémoire jusqu'au (sur certains OS) reboot de ton système


    Pour en revenir à ton cas c'est plus subtil car tu fais un scanf("%s", chaine) donc l'accès à la zone est masqué dans la fonction. Mais si tu réfléchis, tu comprends alors que scanf() va remplir la zone donc, à un moment ou à un autre, ira taper dans "*chaine". Donc tu dois d'abord écrire quelque part chaine=<adresse valide> (tu te trouves en fait dans le second exemple où tu dois passer à scanf() une adresse valide).
    Ou alors, plus simplement comme le dit Obsidian, remplacer ton pointeur par une zone mémoire automatiquement allouée dans la pile comme l'est un tableau. Pour ton souci de 10000 caractères tu n'as pas à t'en faire, ta pile est largement capable d'assumer cette demande (9,8ko) et bien d'autres encore...
    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]

  10. #10
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    Bonsoir/Bonjour.

    Merci encore pour vos explications qui m'ont éclairé sur plusieurs points. Le problème c'est que j'ai du mal à faire l'analogie avec une chaine de caractère...En effet j'ai tenté de remplacé "char *chaine" par "char chaine[10000]" mais cela ne résoud pas mon problème....

    Je ne suis donc pas sur de bien comprendre le principe...(il a un peu du mal le garçon hein) pourtant lors du cour sur les pointeurs il me semblait avoir compris.

    Du coup je ne vois pas comment changer mon programme...Faudrait-il du coup que je crée une fonction qui permet de "remplir" une chaine de caractère comme me l'a suggéré Sve@r?
    Ou bien que je modifie mon code de tel sorte à allouer et à libérer immédiatement la place occupé par ma chaine de caractère?

    Désolé encore pour mon incompréhension, je n'ai aucuns problèmes avec l'algorithmique mais dès qu'il s'agit de traduire celà en code je me sens un peu perdu (tout nouveau dans le domaine).

    Merci encore pour votre patience et votre rapidité.

    Je vous joins la fin de mon code car comme l'a très judiscieusement remarqué Obsidian je n'avais mis que la partie "intéressante" selon moi.

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "biginteger.h"
    #include "liste_doublmt_chainee.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** Fonction principale ***** */
     
    int main()
    {
        int choixMenu=0;
    	char chaine [10000];
     
        printf("\n~~~~ Menu ~~~~\n\n");
        printf("1:  newBigInteger\n");
        printf("2:  printBigInteger\n");
        printf("3:  isNull\n");
        printf("4:  signBigInt\n");
        printf("5:  equalsBigInt\n");
        printf("6:  compareBigInt\n");
        printf("7:  sumBigInt\n");
        printf("8:  diffBigInt\n");
        printf("9:  mulBigInt\n");
        printf("11: quotientBigInt\n");
        printf("12: restBigInt\n");
        printf("13: gcdBigInt\n");
        printf("14: lcmBigInt\n");
        printf("15: factorial\n");
        printf("16: cnp\n");
        printf("\n\nVeuillez choisir la fonction à utiliser en entrant le nombre correspondant :");
        scanf("%d", &choixMenu);
     
        switch (choixMenu)
        {
        case 1:
            printf("\n\nTapez le nombre :");
            scanf(" %s", chaine);
    	printf("\n%s\n", chaine);
            newBigInteger(chaine);
            break;
        case 2:
            printf("\n\nTapez le nombre :");
            scanf(" %s", chaine);
            BigInteger b=newBigInteger(chaine);
            printBigInteger(b);
            break;
        case 3:
            printf("\n\nTapez le nombre :");
            scanf(" %s", chaine);
            BigInteger c=newBigInteger(chaine);
            isNull(c);
            break;
        case 4:
     
            break;
        case 5:
     
            break;
        case 6:
     
            break;
        case 7:
     
            break;
        case 8:
     
            break;
        case 9:
     
            break;
        case 10:
     
            break;
        case 11:
     
            break;
        case 12:
     
            break;
        case 13:
     
            break;
        case 14:
     
            break;
        case 15:
     
            break;
        case 16:
     
            break;
        default:
            printf("Veuillez entrez un nombre compris entre 1 et 16.");
            break;
        }
     
    	return 0;
     
    }
    EDIT: J'avais une question d'ordre pratique... Comment faut-il dans le programme rentrer la chaine de caractère? de cette manière : 123456789 ou de cette manière : "123456789" (avec ou sans les guillemets?). Merci.

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        case 1:
            printf("\n\nTapez le nombre :");
            scanf(" %s", chaine);
    En effet j'ai tenté de remplacé "char *chaine" par "char chaine[10000]" mais cela ne résoud pas mon problème....
    Pourtant ça le devrait. Toutefois il y a dans ton scanf() un espace entre les guillemets et le "%s". Je ne sais pas si c'est une erreur ou si c'est volontaire mais je ne connait pas le comportement de scanf() dans ce cas.

    On va d'ailleurs parler maintenant de scanf(). C'est une grande habitude des professeurs de C de la présenter assez vite aux élèves car elle permet ensuite d'embrayer sur les TP débutants avec les premières saisies et les petits jeux "plus petit/plus grand".
    Cependant c'est une fonction super difficile car elle attend une saisie "formatée" (scanF). Et ce que tape un humain est tout sauf formaté. Même d'ailleurs avec la meilleure volonté du monde, rien que taper <return> ça fout la zone
    Exemple
    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
    #include <stdio.h>
    int main()
    {
        char nom[100];
        int age;
     
        printf("Quel est votre age ?\n");
        scanf("%d", &age);
     
        printf("Quel est votre nom ?\n");
        scanf("%s", nom);
     
        printf("Vous vous appelez [%s] et vous avez [%d] ans\n", nom, age);
    }

    Tu peux prendre ce code, saisir les infos avec la meilleure volonté du monde, tu ne pourras jamais saisir ton nom. Parce que quand tu tapes ton âge, tu le valides par <return>. Et ce return il a un code ascii qui entre dans le tampon clavier (il s'agit d'ailleurs du '\n' bien connu dans les printf). Et quand le scanf() extrait le nombre du clavier, il y laisse tout ce qui n'est pas numérique et donc y laisse ce '\n'. Et au scanf suivant (une chaine), ben le tampon n'étant pas vide le '\n' est alors récupéré immédiatement sans que le programme t'ait laissé la possibilité de saisir quelque chose.

    Donc une fois qu'on commence à être à l'aise avec le C, une étape importante est d'apprendre à se passer de scanf(). Ce qui n'est pas difficile. Puisque scanf() bloque au '\n' alors suffit de passer par une fonction qui ne bloque pas. Et la meilleure pour ça est fgets(). Ensuite, suffit de passer par sscanf (petit "s" en plus) permettant d'extraire les infos non pas du clavier mais d'une zone texte...
    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
    #include <stdio.h>
    int main()
    {
        char nom[100];
        char saisie[100];
        int age;
     
        printf("Quel est votre age ?\n");
        fgets(saisie, 100, stdin);
        sscanf(saisie, "%d", &age);
     
        printf("Quel est votre nom ?\n");
        fgets(saisie, 100, stdin);
        sscanf(saisie, "%s", nom);
     
        printf("Vous vous appelez [%s] et vous avez [%d] ans\n", nom, age);
    }
    La différence c'est qu'on passe par un tampon intermédiaire (saisie) et une fonction (fgets) qui libère stdin (le clavier) de toute caractère quel qu'il soit. Ainsi le clavier est toujours propre pour une nouvelle saisie. Et en plus tu peux même regarder le retour de sscanf() pour vérifier ta saisie car il t'indique le nb d'éléments correctement récupérés
    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
    #include <stdio.h>
    int main()
    {
        char saisie[100];
        char nom[100];
        int age;
     
        while (1)
        {
            printf("Quel est votre age ?\n");
            fgets(saisie, 100, stdin);
            if (sscanf(saisie, "%d", &age) == 1) break;
            printf("Saisie incorrecte - Recommencez !!!\n");
        }
     
        printf("Quel est votre nom ?\n");
        fgets(saisie, 100, stdin);
        sscanf(saisie, "%s", nom);
     
        printf("Vous vous appelez [%s] et vous avez [%d] ans\n", nom, age);
    }

    Essaye de t'en inspirer pour ton code car en l'état, il semble correct.

    Mais il est à mon avis perfectible. Et si tu t'y prends maintenant tu auras alors moins de mal que si tu t'y prends plus tard.
    Tout d'abord normalise tes noms de structure de cette façon struct s_xxx {...} et tes noms de type typedef .... t_xxx;. Tu pourras alors nommer tes variables "elem" ou "element" sans avoir de souci.
    Ensuite ne masque pas les étoiles derrière un type typedef element *DLlist;. C'est la grande habitude en ce moment (on le voit partout, peut-être avec le développement de langages comme C# ou Java qui masquent les pointeurs) mais c'est super dangereux en C. Parce qu'en C, c'est toi qui doit tout gérer. Tu n'as pas un gentil garbage collector qui va gentiment regarder tout ce que t'as oublié de libérer. Donc tu dois constamment garder à l'esprit les pointeurs que tu manipules. Et donc vaut mieux manipuler un "element *toto" qu'un "DLlist toto". Je suis d'ailleurs très inquiet quand je vois DLlist l = creer(); parce que là, je m'imagine un bon gros malloc() peut-être un peu ensuite oublié.

    Enfin quand on manipule une liste chainée, il y a un grand truc à faire dès le départ: créer un type pour la liste elle-même.
    Exemple
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Le type pour l'élément
    typedef struct s_elem {
        char nom[100];
        struct s_elem *next;
    } t_elem;
     
    // Le type pour la liste
    typedef struct {
        t_elem *first;
    } t_liste;

    Ca peut paraitre con de créer un type pour un simple élément mais ça a 3 avantages
    1) si tu dois modifier le first (ce qui arrive assez souvent avec des listes chainées), te suffit de passer simplement l'adresse de la liste à ta fonction. Tu n'as pas à gérer des double étoiles
    Exemple avec un code n'ayant que défini le type pour l'élément
    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
    // Le type pour l'élément
    typedef struct s_elem {
        char nom[100];
        struct s_elem *next;
    } t_elem;
     
    int main()
    {
        t_elem *first;
        init_liste(&first);
    }
     
    void init_liste(t_elem **e /* Allez les double pointeurs */)
    {
        (*e)=NULL;  // Et allez que je vais me coltiner de l'étoile de partout !!!
    }

    Exemple avec mon type liste
    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
    // Le type pour l'élément
    typedef struct s_elem {
        char nom[100];
        struct s_elem *next;
    } t_elem;
     
    // Le type pour la liste
    typedef struct {
        t_elem *first;
    } t_liste;
     
    int main()
    {
        t_liste liste;
        init_liste(&liste);
    }
     
    void init_liste(t_liste *l)
    {
        l->first=NULL;  // Ecriture élégante et simple...
    }

    2) si tu dois faire évoluer ton code (rajouter par exemple un compteur d'éléments), la modification est immédiate. Tu le rajoutes dans le type et toutes les fonctions y ont immédiatement accès. Tu n'as pas à le rajouter ensuite comme paramètre aux fonctions qui en ont besoin
    Exemple avec un code n'ayant que défini le type pour l'élément
    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
    // Le type pour l'élément
    typedef struct s_elem {
        char nom[100];
        struct s_elem *next;
    } t_elem;
     
    int main()
    {
        t_elem *first;
        int nb_elem;     // Variable en plus
        init_liste(&first, &nb_elem /* Paramètre en plus */);
        compteur_liste(first, nb_elem /* Paramètre en plus */);
    }
     
    void init_liste(t_elem **e,  int *nb_elem /* Paramètre en plus, avec son étoile à la con et merci le jour où son type change !!! */)
    {
        (*e)=NULL;
        (*nb_elem)=0;
    }
     
    void compteur_liste(t_elem *e,  int nb_elem /* Paramètre en plus (merci le jour où son type change !!!) */)
    {
        printf("Ma liste contient %d éléments\n", nb_elem);
    }

    Exemple avec mon type liste
    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
    // Le type pour l'élément
    typedef struct s_elem {
        char nom[100];
        struct s_elem *next;
    } t_elem;
     
    // Le type pour la liste
    typedef struct {
        t_elem *first;
        int nb_elem;
    } t_liste;
     
    int main()
    {
        t_liste liste;
        init_liste(&liste);
        compteur_liste(&liste);
    }
     
    void init_liste(t_liste *l)
    {
        l->first=NULL;
        l->nb_elem=0;    // Hop, modif immédiate
    }
     
    void compteur_liste(t_liste *l)
    {
        printf("Ma liste contient %d éléments\n", l->nb_elem /* Hop, accès immédiat */);
    }

    3) la modif (en cas de changement) est immédiate
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // Le type pour la liste
    typedef struct {
        t_elem *first;
        unsigned long nb_elem;    // Ben oui, c'est évident qu'un nb d'éléments est toujours positif !!!
    } t_liste;
     
    // Modification des fonctions... ah ben non pas besoin !!!

    En fait j'aime bien faire une analogie avec des chemises. Les chemises on peut les tenir par le col mais c'est mieux si on les met sur un cintre. Donc comme je le dis, je crains que ton code soit un peu sale au niveau de ta gestion mémoire (surtout si t'as du mal avec les pointeurs ce qui est normal au début). Et donc si tu le reprends maintenant proprement ce sera fastidieux mais moins que si tu rajoutes ce qu'on nomme "des verrues" à la va vite qui risquent de faire plus de mal que de bien.

    Ici un petit exemple simple de liste chainée basé sur ce principe.

    Citation Envoyé par Zthoustra Voir le message
    Je vous joins la fin de mon code car comme l'a très judiscieusement remarqué Obsidian je n'avais mis que la partie "intéressante" selon moi.
    Il parlait surtout des autres fonctions (comme creer()) putôt que d'un main rempli de case non implémentés...

    Citation Envoyé par Zthoustra Voir le message
    EDIT: J'avais une question d'ordre pratique... Comment faut-il dans le programme rentrer la chaine de caractère? de cette manière : 123456789 ou de cette manière : "123456789" (avec ou sans les guillemets?). Merci.
    Sans les guillemets. Si tu en mets, scanf() ne saura pas les gérer sauf si tu lui indiques. Certains, comme Diogène, sont très fort la dedans mais ça moi j'aime pas. Chacun son truc...
    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]

  12. #12
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    Bonjour.

    Tout d'abord merci pour ce petit cour sur le scanf et les structures que j'ai dû relire 3 ou 4 fois et je ne suis pas encore bien sûr de comprendre toutes les subtilités.

    Pourtant ça le devrait. Toutefois il y a dans ton scanf() un espace entre les guillemets et le "%s". Je ne sais pas si c'est une erreur ou si c'est volontaire mais je ne connait pas le comportement de scanf() dans ce cas.
    J'ai essayé d'enlever l'espace dans le scanf() mais aucunes différences...

    J'ai également tenté avec le "fgets" et le "sscanf" mais là j'ai l'impression que cest encore pire, le programme ne me laisse même pas le temps de taper ma chaine de caractère pour me dire "erreur de segmentation (core dumped)".

    Je pense que du coup le problème vient de là :

    Je suis d'ailleurs très inquiet quand je vois DLlist l = creer(); parce que là, je m'imagine un bon gros malloc() peut-être un peu ensuite oublié.
    J'ai pourtant pris celle que l'on avait faite en cour mais j'ai des doutes...

    Je vous met donc (encore) du code (au final vous allez avoir mon code en entier en continuant ainsi...)

    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
    #ifndef LISTE_DOUBLMT_CHAINEE_H_INCLUDED
    #define LISTE_DOUBLMT_CHAINEE_H_INCLUDED
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "biginteger.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** TYPES ***** */
     
    typedef struct elem
    {
    	int valeur;
    	struct elem* precedent;
    	struct elem* suivant;
     
    } element;
    typedef element *DLlist;
     
    /* ***** FONCTIONS ***** */
     
    // Créer une liste doublement chaînée
     
    DLlist creer()
    {
    	DLlist nouvel=(element*)malloc(sizeof(element));
    	nouvel->valeur=0;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	return nouvel;
    }
     
    // Ajouter un élément en fin de liste
     
    DLlist ajouterq(DLlist l, int v)
    {
    	DLlist nouvel=(element*)malloc(sizeof(element));
    	DLlist p;
    	nouvel->valeur=v;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	if(l==NULL)
    	{
    		l=nouvel;
    	}
    	else
    	{
    		p=l;
    		while (p->suivant !=NULL)
    		{
    			p=p->suivant;
    		}
    		p->suivant=nouvel;
    		nouvel->precedent=p;
    	}
    	return l;
    }
     
    // Afficher une liste
     
    void afficherListe(DLlist l)
    {
    	printf("\n\n");
        	if (l == NULL)
        	{
            	 exit(EXIT_FAILURE);
        	}
    	else
    	{
    		while (l->suivant!=NULL)
    		{
    			printf(" %d <=>", l->valeur);
    			l=l->suivant;
    		}
    		printf(" %d\n\n", l->valeur);
    	}
    }
     
    // Supprimer un élément en tête de liste
     
    DLlist supprimert(DLlist l)
    {
    	DLlist tmp;
    	if (l == NULL)
    		tmp=NULL;
    	else
    	{
    		tmp=l->suivant;
    		if (tmp !=NULL)
    			tmp->precedent=NULL;
    		free(l);
    	}
    	return tmp;
    }
    Bon là je vous ai presque tout mis....C'est un peu indigeste (et j'en suis navré) mais là je craque, je passe mes fêtes à chercher une solution au problème et je ne trouve vraiment pas la solution (malgré votre aide précieuse).

    Je vais tenter de changer ce que vous m'avez dit pour une présentation plus claire avec les typedef etc...

    Encore merci, pour votre aide et votre patience.
    Et je vous souhaite une bonne année 2014.

  13. #13
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Bonjour.
    Euh oui sympa mais un bonjour unique dans le topic suffit

    Citation Envoyé par Zthoustra Voir le message
    J'ai également tenté avec le "fgets" et le "sscanf" mais là j'ai l'impression que cest encore pire, le programme ne me laisse même pas le temps de taper ma chaine de caractère pour me dire "erreur de segmentation (core dumped)".

    Je pense que du coup le problème vient de là :
    Il vient pas de là mais d'un truc plus profond qui ressort ensuite à ce niveau. C'est le plus grand danger du C: faire un truc interdit qui amène à un comportement indéterminé. Parce qu'un comportement "indéterminé" c'est exactement ce que ça veut dire: un comportement qu'on ne peut pas prédire. Ca peut produire un code qui fonctionne, qui plante et s'il plante il peut planter n'importe où même à un endroit correct...

    Citation Envoyé par Zthoustra Voir le message
    Je vous met donc (encore) du code (au final vous allez avoir mon code en entier en continuant ainsi...)
    En fait ce serait un plus. Mais bon, on peut y arriver...

    Citation Envoyé par Zthoustra Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    typedef int boolean;
    Je sens que ton prof est un habitué du C++ et qu'il cherche à répercuter en C certaines habitudes du C++. Fonctionne mais c'est pas utile.

    Citation Envoyé par Zthoustra 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
    /* ***** TYPES ***** */
    
    typedef struct elem
    {
    	int valeur;
    	struct elem* precedent;
    	struct elem* suivant;
    
    } element;
    typedef element *DLlist;
    
    /* ***** FONCTIONS ***** */
    
    // Créer une liste doublement chaînée
    DLlist creer()
    {
    	DLlist nouvel=(element*)malloc(sizeof(element));
    	nouvel->valeur=0;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	return nouvel;
    }
    Donc là incohérence dans la lecture. Parle-t-on d'un "element*" ou d'un DLlist ? Ah oui c'est vrai que c'est la même chose. Mais ça choque alors qu'il en faut pas beaucoup pour faire un truc un petit peu mieux...

    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
    /* ***** TYPES ***** */
     
    typedef struct s_elem
    {
    	int valeur;
    	struct s_elem* precedent;
    	struct s_elem* suivant;
    } t_elem;
     
    // Créer une élément d'une liste doublement chaînée avec sa valeur
    t_elem *creer(int valeur)
    {
    	t_elem *nouvel=(t_elem*)malloc(sizeof(t_elem));
    	nouvel->valeur=valeur;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	return nouvel;
    }

    Citation Envoyé par Zthoustra 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
    // Ajouter un élément en fin de liste
    DLlist ajouterq(DLlist l, int v)
    {
    	DLlist nouvel=(element*)malloc(sizeof(element));
    	DLlist p;
    	nouvel->valeur=v;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	if(l==NULL)
    	{
    		l=nouvel;
    	}
    	else
    	{
    		p=l;
    		while (p->suivant !=NULL)
    		{
    			p=p->suivant;
    		}
    		p->suivant=nouvel;
    		nouvel->precedent=p;
    	}
    	return l;
    }
    Donc c'est clair que ça ne va pas. La fonction reçoit un paramètre "l" qu'elle va modifier (rappel: on ne peut pas modifier un paramètre d'une fonction car le paramètre est perdu en fin de fonction). Toutefois tu le renvoies avant de le perdre. Ca peut fonctionner mais uniquement si tu gères bien le truc. Mais c'est assez hasardeux. A mon avis, c'est ici que ça plante...

    De plus, la fonction refait toute l'allocation qui était déjà faite dans "creer". Pourquoi ne pas la réutiliser ici ? Surtout que la mienne plus généraliste affecte directement une valeur plutôt que de mettre tout à 0 donc est utilisable dans toutes les configurations...

    Je comptais la rectifier en l'adaptant à ta façon de faire mais il me manque trop d'infos. Surtout la façon dont tu t'en sers (probablement dans la fonction newBigInteger qu'on n'a pas encore vu). A ce propos je suis inquiet quand je vois ça
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        case 1:
            printf("\n\nTapez le nombre :");
            scanf(" %s", chaine);
    	printf("\n%s\n", chaine);
            newBigInteger(chaine);
            break;
        case 2:
            printf("\n\nTapez le nombre :");
            scanf(" %s", chaine);
            BigInteger b=newBigInteger(chaine);
            printBigInteger(b);
            break;
    Dans un cas tu récupères ce que renvoie la fonction et pas dans l'autre. Mais si elle renvoie une zone allouée (ce qui est très probable en listes chainées) alors la zone est perdue...

    Bon donc trop de manques. Je préfère te taper un exemple minimaliste fonctionnel de liste doublement chainée...

    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
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
     
    typedef struct s_elem {
    	int valeur;
    	struct s_elem *next;
    	struct s_elem *prev;
    } t_elem;
     
    typedef struct {
    	t_elem *first;
    	t_elem *last;
    } t_liste;
     
    // Initialisation de la liste
    void init_liste(t_liste *l)
    {
    	l->first=NULL;
    	l->last=NULL;
    }
     
    // Création d'un élément
    t_elem *creer_elem(int valeur)
    {
    	t_elem *elem;
    	if ((elem=malloc(sizeof(t_elem))) == NULL) return NULL;
    	elem->next=NULL;
    	elem->prev=NULL;
    	elem->valeur=valeur;
    	return elem;
    }
     
    // Ajout d'un élément en fin de liste
    t_elem *append(t_liste *l, int valeur)
    {
    	t_elem *elem;
     
    	if ((elem=creer_elem(valeur)) == NULL)
    		return NULL;
     
    	// Si la liste n'est pas vide
    	if (l->first != NULL)
    	{
    		// Le pointeur précédent de l'élément créé est mis à jour
    		elem->prev=l->last;
     
    		// Le pointeur de l'ex dernier est mis à jour
    		l->last->next=elem;
    	}
    	else
    	{
    		// La liste n'est désormais plus vide
    		l->first=elem;
    	}
     
    	// Dans les deux cas, l'élément a été ajouté en fin de liste
    	l->last=elem;
     
    	// Faut toujours renvoyer qqchose (pour pouvoir faire la différence avec NULL)
    	return elem;
    }
     
    // En inversant les first et last, et next et prev on peut très facilement rajouter une autre fonction qui insère un élément en début de liste...
     
    // Nettoyage de la liste
    void libere_liste (t_liste *l)
    {
    	t_elem *current;
    	t_elem *previous;
     
    	// S'il n'y a pas d'élément
    	if (l->first == NULL)
    		return;
     
    	// Traitement de tous les élément
    	current=l->first;
    	do {
    		previous=current;
    		current=current->next;
    		free(previous);
    	} while (current != NULL);
     
    	// La liste a été vidée - On la réinitialise
    	init_liste(l);
    }
     
    // Affichage de la liste
    void affich_liste(t_liste *l, char sens)
    {
    	t_elem *current;
     
    	if (l->first == NULL)
    	{
    		printf("Liste vide\n");
    		return;
    	}
     
    	// Evaluation du sens
    	switch (sens)
    	{
    		case '<': // Sens croissant
    			for (current=l->first; current != NULL; current=current->next)
    				printf("%d, ", current->valeur);
    			printf("\n");
    			break;
    		case '>': // Sens croissant
    			for (current=l->last; current != NULL; current=current->prev)
    				printf("%d, ", current->valeur);
    			printf("\n");
    			break;
    	}
    }
     
    int main()
    {
    	t_liste liste;
    	init_liste(&liste);
     
    	append(&liste, 1);
    	append(&liste, 2);
    	append(&liste, 3);
     
    	affich_liste(&liste, '<');
    	affich_liste(&liste, '>');
    	libere_liste(&liste);
    }

    Essaye de t'en inspirer parce que je suis sûr que tu peux ensuite l'adapter à ton problème...

    Citation Envoyé par Zthoustra Voir le message
    Bon là je vous ai presque tout mis....C'est un peu indigeste (et j'en suis navré)
    C'est bien plus agréable que grand nombre de codes que j'ai déjà vu ici !!!

    Citation Envoyé par Zthoustra Voir le message
    mais là je craque, je passe mes fêtes à chercher une solution au problème et je ne trouve vraiment pas la solution (malgré votre aide précieuse).
    T'inquiète pas, on va y arriver. Surtout que ton code est quand-même bien conçu malgré ses maladresses. On sent que tu as compris la grande majorité sur les pointeurs. Ne manque que l'habitude...
    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]

  14. #14
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    Bonne année 2014 à vous !

    Sur ce, j'ai quelques questions quant à votre dernier poste.

    Donc c'est clair que ça ne va pas. La fonction reçoit un paramètre "l" qu'elle va modifier (rappel: on ne peut pas modifier un paramètre d'une fonction car le paramètre est perdu en fin de fonction). Toutefois tu le renvoies avant de le perdre. Ca peut fonctionner mais uniquement si tu gères bien le truc. Mais c'est assez hasardeux. A mon avis, c'est ici que ça plante...

    De plus, la fonction refait toute l'allocation qui était déjà faite dans "creer". Pourquoi ne pas la réutiliser ici ? Surtout que la mienne plus généraliste affecte directement une valeur plutôt que de mettre tout à 0 donc est utilisable dans toutes les configurations...
    Je ne comprend pas trop du coup ce qui ne va pas car en plus dans l'exemple type que vous me mettez, votre fonction pour ajouter en queue de la liste renvoie un élément et pas une liste si j'ai bien compris. Or j'aimerai que ma fonction me renvoie une liste..
    Du coup j'ai (un peu) modifié mon code cela ne va t-il toujours pas?

    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
    DLlist ajouterq(DLlist l, int v)
    {
    	DLlist nouvel=creer();
    	DLlist p;
    	nouvel->valeur=v;
    	if(l==NULL)
    	{
    		p=nouvel;
    	}
    	else
    	{
    		p=l;
    		while (p->suivant !=NULL)
    		{
    			p=p->suivant;
    		}
    		p->suivant=nouvel;
    		nouvel->precedent=p;
    	}
    	return p;
    }
    Dans un cas tu récupères ce que renvoie la fonction et pas dans l'autre. Mais si elle renvoie une zone allouée (ce qui est très probable en listes chainées) alors la zone est perdue...
    Je ne comprend pas le problème ici. Je vous joins newBiginteger (que j'ai déja mis en tout début de topic m'enfin je le remet ).

    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
    /* ***** FONCTIONS ***** */
     
    // newBigInteger
     
    BigInteger newBigInteger (char* chaine)
    {	
    	BigInteger b;
    	char* testchaine;
     
    	if (chaine==NULL)
    		exit(EXIT_FAILURE);
    	else
    	{
    		testchaine=strchr(chaine,'-');
    		if (testchaine==NULL)
    			b->sign=1;
    		else 
    		{		
    			b->sign=-1;
    			chaine++;
    		}
    		char *chaine2;
        		int longueur = strlen(chaine);  // Longueur est égale à la taille du nombre donné
        		DLlist l = creer();
    		DLlist tmp;
    		int i = 4;
    		int a,d;
     
        		while(i<longueur)
    		{
            		chaine2= (&chaine[longueur-i]); 
    			a=atoi(chaine2);
    			ajouterq(l,a);
    			chaine[longueur-i]='\0';
    			i=i+4;
    		}
    		d=atoi(chaine);
    		ajouterq(l,d);
    		tmp=supprimert(l);
    		b->list=tmp;
     
    	}
    	return b;
    }
    PS: Cela fait deux jours que je regarde votre message pour comprendre certaines choses, et vous avez modifiés plusieurs fois votre message le peaufinant de plus en plus (du coup ça a répondu à plusieurs réponses que j'avais ^^).

  15. #15
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Je ne comprend pas trop du coup ce qui ne va pas car en plus dans l'exemple type que vous me mettez, votre fonction pour ajouter en queue de la liste renvoie un élément et pas une liste si j'ai bien compris.
    J'ai mis en commentaire qu'il fallait que la fonction renvoie quelque chose (différent de NULL) juste pour que l'appelant puisse savoir s'il y a eu un pb ou pas. J'ai choisi de renvoyer l'élément créé mais j'aurais pu aussi bien renvoyer "1" ou même ne rien renvoyer du tout puisque la fonction s'occupe de tout (créer l'élément et le placer à la bonne place dans la liste). Donc moi ce qui est renvoyé (un élément ou une liste) je m'en fous (tant que c'est pas NULL)...

    Citation Envoyé par Zthoustra Voir le message
    Or j'aimerai que ma fonction me renvoie une liste..
    C'est une autre façon de faire, comme je l'ai dit. Mais c'est plus dur à gérer car c'est alors à l'appelant de prendre en compte la liste renvoyée et bien s'en servir. D'ailleurs tu dis "liste" mais en réalité tu ne renvoies qu'un élément (parce que pour toi la "liste" c'est juste son premier élément à la différence de ma façon de voir où pour moi la "liste" c'est une structure contenant, entre autres, le premier élément)...

    Citation Envoyé par Zthoustra Voir le message
    Du coup j'ai (un peu) modifié mon code cela ne va t-il toujours pas?
    A ce niveau là, je pense que tu devrais nous le mettre d'un coup qu'on puisse le prendre en bloc et le compiler chez-nous...

    Citation Envoyé par Zthoustra 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
    DLlist ajouterq(DLlist l, int v)
    {
    	DLlist nouvel=creer();
    	DLlist p;
    	nouvel->valeur=v;
    	if(l==NULL)
    	{
    		p=nouvel;
    	}
    	else
    	{
    		p=l;
    		while (p->suivant !=NULL)
    		{
    			p=p->suivant;
    		}
    		p->suivant=nouvel;
    		nouvel->precedent=p;
    	}
    	return p;
    }
    A première vue ici ça va. Tu peux toutefois modifier "crer()" pour qu'elle mette elle-même la valeur (passée en paramètre) dans l'élément créé (parce qu'elle y met 0 donc c'est pas grand chose de lui faire mettre autre chose...)

    Citation Envoyé par Zthoustra 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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    
    BigInteger newBigInteger (char* chaine)
    {	
    	BigInteger b;
    	char* testchaine;
    
    	if (chaine==NULL)
    		exit(EXIT_FAILURE);
    	else
    	{
    		testchaine=strchr(chaine,'-');
    		if (testchaine==NULL)
    			b->sign=1;
    		else 
    		{		
    			b->sign=-1;
    			chaine++;
    		}
    		char *chaine2;
        		int longueur = strlen(chaine);  // Longueur est égale à la taille du nombre donné
        		DLlist l = creer();
    		DLlist tmp;
    		int i = 4;
    		int a,d;
    
        		while(i<longueur)
    		{
            		chaine2= (&chaine[longueur-i]); 
    			a=atoi(chaine2);
    			ajouterq(l,a);
    			chaine[longueur-i]='\0';
    			i=i+4;
    		}
    		d=atoi(chaine);
    		ajouterq(l,d);
    		tmp=supprimert(l);
    		b->list=tmp;
    		
    	}
    	return b;
    }
    J'ai mis en rouge ce qui me choque. Ta fonction "ajouter" renvoie des choses (la liste modifiée il me semble) mais ce qui a été renvoyé tu ne le récupères pas. Et ensuite, une fois que tout est ajouté tu supprimes tout ???

    Fais gaffe aussi à strchr() car cette fonction cherche le caractère dans toute la chaine. Donc si ta chaine contient "123-456" il le trouve donc ça passe dans le "else" et là tu fais "chaine++" donc ta chaine vaut ensuite "23-456" ce qui n'est pas vraiment ce que je m'imagine que tu veux faire...

    Si tu veux savoir si ta chaine commence par '-' tu peux regarder if (chaine[0] == '-'). T'as pas le droit de comparer une chaine avec une valeur mais t'as tout à fait le droit de comparer l'un ou l'autre de ses éléments...
    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]

  16. #16
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    J'ai mis en commentaire qu'il fallait que la fonction renvoie quelque chose (différent de NULL) juste pour que l'appelant puisse savoir s'il y a eu un pb ou pas. J'ai choisi de renvoyer l'élément créé mais j'aurais pu aussi bien renvoyer "1" ou même ne rien renvoyer du tout puisque la fonction s'occupe de tout (créer l'élément et le placer à la bonne place dans la liste). Donc moi ce qui est renvoyé (un élément ou une liste) je m'en fous (tant que c'est pas NULL)...
    J'avais bien compris, le problème ici c'est que je veux récupérer une liste modifié...

    A première vue ici ça va. Tu peux toutefois modifier "crer()" pour qu'elle mette elle-même la valeur (passée en paramètre) dans l'élément créé (parce qu'elle y met 0 donc c'est pas grand chose de lui faire mettre autre chose...)
    Oui j'ai bien compris =) je vais le changer !

    Ta fonction "ajouter" renvoie des choses (la liste modifiée il me semble) mais ce qui a été renvoyé tu ne le récupères pas. Et ensuite, une fois que tout est ajouté tu supprimes tout ???
    En fait ma fonction "ajouterq" prend en paramètre une liste et un entier. Elle permet de renvoyer la liste en paramètre AVEC en fin de liste l'entier en question.
    De plus, ma fonction "supprimert" supprime le premier élément de ma liste qui est par défault 0 (lorsque je crée ma liste avec "creer()") donc non je ne supprime pas tout.

    Fais gaffe aussi à strchr() car cette fonction cherche le caractère dans toute la chaine. Donc si ta chaine contient "123-456" il le trouve donc ça passe dans le "else" et là tu fais "chaine++" donc ta chaine vaut ensuite "23-456" ce qui n'est pas vraiment ce que je m'imagine que tu veux faire...

    Si tu veux savoir si ta chaine commence par '-' tu peux regarder if (chaine[0] == '-'). T'as pas le droit de comparer une chaine avec une valeur mais t'as tout à fait le droit de comparer l'un ou l'autre de ses éléments...
    Merci pour le tuyau j'ai modifié !

    A ce niveau là, je pense que tu devrais nous le mettre d'un coup qu'on puisse le prendre en bloc et le compiler chez-nous...
    Et c'est ce que je vais faire ! Good luck pour la lecture

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "liste_doublmt_chainee.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** TYPES ***** */
     
    typedef struct // Structure BigInteger : un signe + une liste doublement chaînée
    {
        int sign;
        DLlist list;
     
    } dlstruct;
     
    typedef dlstruct *BigInteger;
     
     
    /* ***** PROTOTYPES ***** */
     
    BigInteger newBigInteger (char* chaine);
    void printBigInteger (BigInteger a);
     
    /* ***** FONCTIONS ***** */
     
    // newBigInteger
     
    BigInteger newBigInteger (char* chaine)
    {	
    	BigInteger b;
     
    	if (chaine==NULL)
    		exit(EXIT_FAILURE);
    	else
    	{
     
    		if (chaine[0]=='-')
    			b->sign=1;
    		else 
    		{		
    			b->sign=-1;
    			chaine++;
    		}
    		char *chaine2;
        		int longueur = strlen(chaine);  // Longueur est égale à la taille du nombre donné
        		DLlist l = creer();
    		DLlist tmp;
    		int i = 4;
    		int a,d;
     
        		while(i<longueur)
    		{
            		chaine2= (&chaine[longueur-i]); 
    			a=atoi(chaine2);
    			ajouterq(l,a);
    			chaine[longueur-i]='\0';
    			i=i+4;
    		}
    		d=atoi(chaine);
    		ajouterq(l,d);
    		tmp=supprimert(l);
    		b->list=tmp;
     
    	}
    	return b;
    }
     
    // printBigInteger
     
    void printBigInteger (BigInteger b)
    {
    	printf("Voici notre BigInteger sous forme de liste");
    	afficherListe(b->list);
     
    }
    Ca c'est mon fichier "BigInteger.h"

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "biginteger.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** TYPES ***** */
     
    typedef struct elem
    {
    	int valeur;
    	struct elem *precedent;
    	struct elem *suivant;
     
    } element;
    typedef element *DLlist;
     
    /* ***** PROTOTYPES ***** */
     
    void afficherListe(DLlist l);
    DLlist ajouterq(DLlist l, int v);
    DLlist ajoutert(DLlist l, int v);
    DLlist creer();
    DLlist supprimert(DLlist l);
     
    /* ***** FONCTIONS ***** */
     
    // Créer une liste doublement chaînée
     
    DLlist creer()
    {
    	DLlist nouvel=(element*)malloc(sizeof(element));
    	nouvel->valeur=0;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	return nouvel;
    }
     
    // Ajouter un élément en tête de liste
     
    DLlist ajoutert(DLlist l, int v)
    {
    	DLlist nouvel;
    	nouvel=(element*)malloc(sizeof(element));
    	nouvel->valeur=v;
    	nouvel->suivant=l;
    	nouvel->precedent=NULL;
    	if (l!=NULL)
    	{
    		l->precedent=nouvel;
    	}
    	return nouvel;
    }
     
    // Ajouter un élément en fin de liste
     
    DLlist ajouterq(DLlist l, int v)
    {
    	DLlist nouvel=creer();
    	DLlist p;
    	nouvel->valeur=v;
    	if(l==NULL)
    	{
    		p=nouvel;
    	}
    	else
    	{
    		p=l;
    		while (p->suivant !=NULL)
    		{
    			p=p->suivant;
    		}
    		p->suivant=nouvel;
    		nouvel->precedent=p;
    	}
    	return p;
    }
     
    // Afficher une liste
     
    void afficherListe(DLlist l)
    {
    	printf("\n\n");
        	if (l == NULL)
        	{
            	 exit(EXIT_FAILURE);
        	}
    	else
    	{
    		while (l->suivant!=NULL)
    		{
    			printf(" %d <=>", l->valeur);
    			l=l->suivant;
    		}
    		printf(" %d\n\n", l->valeur);
    	}
    }
     
    // Supprimer un élément en tête de liste
     
    DLlist supprimert(DLlist l)
    {
    	DLlist tmp;
    	if (l == NULL)
    		tmp=NULL;
    	else
    	{
    		tmp=l->suivant;
    		if (tmp !=NULL)
    			tmp->precedent=NULL;
    		free(l);
    	}
    	return tmp;
    }
     
    // Vérifier si deux listes sont identiques
     
    boolean equalsDLlist(DLlist l, DLlist m)
    {
        if (l == NULL || m == NULL)
             exit(EXIT_FAILURE);
        else
        {
            DLlist p = l;
            DLlist n = m;
     
            if (p->valeur == n->valeur)
            {
                while (p->valeur == n->valeur && p->suivant!=NULL && n->suivant!=NULL)
                {
                    p = p->suivant;
                    n = n->suivant;
                }
                if (p->suivant == NULL && n->suivant == NULL && p->valeur== n->valeur)
                    return TRUE;
                else
                    return FALSE;
            }
            else
                return FALSE;
        }
    }
    Mon fichier "liste_doublmt_chainee.h"

    Et enfin mon fichier 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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "biginteger.h"
    #include "liste_doublmt_chainee.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** Fonction principale ***** */
     
    int main()
    {
        int choixMenu=0;
    	char chaine [10000];
    	char saisie [10000];
        printf("\n~~~~ Menu ~~~~\n\n");
        printf("1:  newBigInteger\n");
        printf("2:  printBigInteger\n");
        printf("3:  isNull\n");
        printf("4:  signBigInt\n");
        printf("5:  equalsBigInt\n");
        printf("6:  compareBigInt\n");
        printf("7:  sumBigInt\n");
        printf("8:  diffBigInt\n");
        printf("9:  mulBigInt\n");
        printf("11: quotientBigInt\n");
        printf("12: restBigInt\n");
        printf("13: gcdBigInt\n");
        printf("14: lcmBigInt\n");
        printf("15: factorial\n");
        printf("16: cnp\n");
        printf("\n\nVeuillez choisir la fonction à utiliser en entrant le nombre correspondant :");
        scanf("%d", &choixMenu);
     
        switch (choixMenu)
        {
        case 1:
            printf("\n\nTapez le nombre :");
            fgets(saisie, 10000, stdin);
        	sscanf(saisie, "%s", chaine);
    	printf("\n%s\n", chaine);
            newBigInteger(chaine);
            break;
        case 2:
            printf("\n\nTapez le nombre :");
            scanf("%s", chaine);
            BigInteger b=newBigInteger(chaine);
            printBigInteger(b);
            break;
        case 3:
     
            break;
        case 4:
     
            break;
        case 5:
     
            break;
        case 6:
     
            break;
        case 7:
     
            break;
        case 8:
     
            break;
        case 9:
     
            break;
        case 10:
     
            break;
        case 11:
     
            break;
        case 12:
     
            break;
        case 13:
     
            break;
        case 14:
     
            break;
        case 15:
     
            break;
        case 16:
     
            break;
        default:
            printf("Veuillez entrez un nombre compris entre 1 et 16.");
            break;
        }
     
    	return 0;
     
    }
    Voilà la totale ! Merci encore.

  17. #17
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Bon ben beaucoup d'incompréhension dans ta façon de concevoir un programme. Déjà je ne comprends même pas que ça compile chez-toi vu que ton main inclus "biginteger.h" et ton "liste_doublement_chainee.h" et que chaque ".h" s'inclue l'un/l'autre sans que tu les aies protégés contre un effet de ce type. Juste là le compilo explose.

    Donc pour prévenir un ".h" contre une inclusion multiple, il faut lui définir une compilation conditionnellle liée à une macro à son nom.
    Typiquement, pour "biginteger.h", cela se présentera ainsi
    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
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "liste_doublmt_chainee.h"
    
    #ifndef _BIGINTER_H_
    #define _BIG_INTEGER_H_
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
    typedef int boolean;
     
    /* ***** TYPES ***** */
     
    typedef struct // Structure BigInteger : un signe + une liste doublement chaînée
    {
        int sign;
        DLlist list;
     
    } dlstruct;
     
    typedef dlstruct *BigInteger;
     
     
    /* ***** PROTOTYPES ***** */
     
    BigInteger newBigInteger (char* chaine);
    void printBigInteger (BigInteger a);
     
    /* ***** FONCTIONS ***** */
     
    // newBigInteger
     
    BigInteger newBigInteger (char* chaine)
    {	
    	BigInteger b;
     
    	if (chaine==NULL)
    		exit(EXIT_FAILURE);
    	else
    	{
     
    		if (chaine[0]=='-')
    			b->sign=1;
    		else 
    		{		
    			b->sign=-1;
    			chaine++;
    		}
    		char *chaine2;
        		int longueur = strlen(chaine);  // Longueur est égale à la taille du nombre donné
        		DLlist l = creer();
    		DLlist tmp;
    		int i = 4;
    		int a,d;
     
        		while(i<longueur)
    		{
            		chaine2= (&chaine[longueur-i]); 
    			a=atoi(chaine2);
    			ajouterq(l,a);
    			chaine[longueur-i]='\0';
    			i=i+4;
    		}
    		d=atoi(chaine);
    		ajouterq(l,d);
    		tmp=supprimert(l);
    		b->list=tmp;
     
    	}
    	return b;
    }
     
    // printBigInteger
     
    void printBigInteger (BigInteger b)
    {
    	printf("Voici notre BigInteger sous forme de liste");
    	afficherListe(b->list);
     
    }
    
    #endif // _BIG_INTEGER_H_

    Et pareil pour l'autre. Ainsi quand liste.h inclueras biginteger.h, la macro "_BIG_INTEGER_H" étant indéfinie il passera dans le if et il la définira. Puis quand ton main reinclueras "biginteger.h", la macro étant déjà définie, il évitera de réinclure le code.

    On en vient au code justement. Ben on ne met jamais de code dans un ".h". Parce qu'un ".h" est ce qui est visible (il est distribué au public) alors que le code, lui, reste invisible. Ca permet ainsi de le protéger. Et si tu réfléchis, tu verras que ça fonctionne tout pareil si tu mets ton code proprement dit avec ton main.
    Ici un petit tuto sur le pourquoi et la façon de découper un programme en ".h" et ".c".

    Donc en l'état, après avoir rajouté mes "#ifndef" ça compile (hormis ce typedef int boolean" qui était redéfini plusieurs fois et qui n'est utilisé qu'une fois donc que j'ai viré).

    Maintenant que ça compile, réponse à tes deux questions

    Pourquoi tu peux pas saisir de nombre ? Parce que t'as adapté mon exemple de saisie avec fgets()+sscanf() mais tu l'as pas adapté au choix du menu où tu y as laissé un scanf(). Donc au scanf() tu tapes "1<entree>" et le "<entree>" reste dans stdin. Au fgets() suivant, il récupère le "<entree>" sans te laisser la possibilité de saisir quoi que ce soit...
    Donc soit tu remplaces là-aussi le scanf() par fgets()+sscanf(), soit tu rajoutes un fgetc(stdin) sous le scanf(). J'ai pris cette seconde solution.

    Pourquoi ça plante ? Parce qu'au choix 1 tu appelles la fonction newBigInteger(), parce que cette fonction défini un "bigInteger b" et que tu vas remplir directement b->sign comme si b était un type concret. Or ce n'est pas un type mais un pointeur (masqué) et qui bien évidemment n'a pas été alloué !!! Comme quoi, quand on dit que ce n'est pas une bonne idée de masquer les pointeurs...

    Dernier détail: si tu quittes une fonction en exit() ou en return sur un cas particulier, le else en dessous est inutile. Ca te fait gagner un bloc "else" et son décalage à droite.

    Ci-joint le code réécrit selon les principes exposés dans ce post. Il ne fonctionne pas plus (vu que b reste un pointeur) mais lui au-moins il compile...

    Fichier "biginteger.h"
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
     
    #ifndef _BIGINTEGER_H_
    #define _BIGINTEGER_H_
     
    #define TRUE 1
    #define FALSE 0
     
    /* ***** TYPES ***** */
     
    typedef struct // Structure BigInteger : un signe + une liste doublement chaînée
    {
        int sign;
        DLlist list;
     
    } *BigInteger;
     
    /* ***** PROTOTYPES ***** */
     
    BigInteger newBigInteger (char*);
    void printBigInteger (BigInteger);
     
    #endif // _BIGINTEGER_H_

    Fichier "liste.h" (je l'ai renommé car ce nom long me gonflait)
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
     
    #ifndef _LISTE_H_
    #define _LISTE_H_
     
    #define TRUE 1
    #define FALSE 0
     
    /* ***** TYPES ***** */
     
    typedef struct elem
    {
    	int valeur;
    	struct elem *precedent;
    	struct elem *suivant;
     
    } element;
    typedef element *DLlist;
     
    /* ***** PROTOTYPES ***** */
     
    void afficherListe(DLlist);
    DLlist ajouterq(DLlist, int);
    DLlist ajoutert(DLlist, int);
    DLlist creer(int);
    DLlist supprimert(DLlist);
     
    #endif // _LISTE_H_

    Et le main
    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
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "liste.h"
    #include "biginteger.h"
     
    // Nécessaire pour le type boolean :
     
    #define TRUE 1
    #define FALSE 0
     
    /* ***** Fonction principale ***** */
     
    int main()
    {
    	int choixMenu=0;
    	char chaine [10000];
    	char saisie [10000];
    	printf("\n~~~~ Menu ~~~~\n\n");
    	printf("1:  newBigInteger\n");
    	printf("2:  printBigInteger\n");
    	printf("3:  isNull\n");
    	printf("4:  signBigInt\n");
    	printf("5:  equalsBigInt\n");
    	printf("6:  compareBigInt\n");
    	printf("7:  sumBigInt\n");
    	printf("8:  diffBigInt\n");
    	printf("9:  mulBigInt\n");
    	printf("11: quotientBigInt\n");
    	printf("12: restBigInt\n");
    	printf("13: gcdBigInt\n");
    	printf("14: lcmBigInt\n");
    	printf("15: factorial\n");
    	printf("16: cnp\n");
    	printf("\n\nVeuillez choisir la fonction à utiliser en entrant le nombre correspondant :");
    	scanf("%d", &choixMenu);
    	fgetc(stdin);    // Suppression du <return>
     
    	switch (choixMenu)
    	{
    	case 1:
    		printf("\n\nTapez le nombre :");
    		fgets(saisie, 10000, stdin);
    		sscanf(saisie, "%s", chaine);
    		printf("\n%s\n", chaine);
    		newBigInteger(chaine);
    		break;
    	case 2:
    		printf("\n\nTapez le nombre :");
    		scanf("%s", chaine);
    		BigInteger b=newBigInteger(chaine);
    		printBigInteger(b);
    		break;
    	case 3:
    		break;
    	case 4:
    		break;
    	case 5:
    		break;
    	case 6:
    		break;
    	case 7:
    		break;
    	case 8:
    		break;
    	case 9:
    		break;
    	case 10:
    		break;
    	case 11:
    		break;
    	case 12:
    		break;
    	case 13:
    		break;
    	case 14:
    		break;
    	case 15:
    		break;
    	case 16:
    		break;
    	default:
    		printf("Veuillez entrez un nombre compris entre 1 et 16.");
    		break;
    	}
    	return 0;
    }
    
    /* ***** FONCTIONS ***** */
    // newBigInteger
    BigInteger newBigInteger (char* chaine)
    {	
    	BigInteger b;
     
    	if (chaine==NULL)
    		exit(EXIT_FAILURE);
    
    	if (chaine[0]=='-')
    		b->sign=1;    // Et b il est alloué quand ???
    	else 
    	{		
    		b->sign=-1;
    		chaine++;
    	}
    	char *chaine2;
    	int longueur = strlen(chaine);  // Longueur est égale à la taille du nombre donné
    	DLlist l = creer(0);
    	DLlist tmp;
    	int i = 4;
    	int a,d;
    
    	while(i<longueur)
    	{
    		chaine2= (&chaine[longueur-i]); 
    		a=atoi(chaine2);
    		ajouterq(l,a);
    		chaine[longueur-i]='\0';
    		i=i+4;
    	}
    	d=atoi(chaine);
    	ajouterq(l,d);
    	tmp=supprimert(l);
    	b->list=tmp;
    	return b;
    }
     
    // printBigInteger
    void printBigInteger (BigInteger b)
    {
    	printf("Voici notre BigInteger sous forme de liste");
    	afficherListe(b->list);
    }
    
    // Créer une liste doublement chaînée
    DLlist creer(int v)
    {
    	DLlist nouvel=(element*)malloc(sizeof(element));
    	nouvel->valeur=v;
    	nouvel->suivant=NULL;
    	nouvel->precedent=NULL;
    	return nouvel;
    }
     
    // Ajouter un élément en tête de liste
    DLlist ajoutert(DLlist l, int v)
    {
    	DLlist nouvel;
    	nouvel=(element*)malloc(sizeof(element));
    	nouvel->valeur=v;
    	nouvel->suivant=l;
    	nouvel->precedent=NULL;
    	if (l!=NULL)
    	{
    		l->precedent=nouvel;
    	}
    	return nouvel;
    }
     
    // Ajouter un élément en fin de liste
    DLlist ajouterq(DLlist l, int v)
    {
    	DLlist nouvel=creer(v);
    	DLlist p;
    	if(l==NULL)
    	{
    		p=nouvel;
    	}
    	else
    	{
    		p=l;
    		while (p->suivant !=NULL)
    		{
    			p=p->suivant;
    		}
    		p->suivant=nouvel;
    		nouvel->precedent=p;
    	}
    	return p;
    }
     
    // Afficher une liste
    void afficherListe(DLlist l)
    {
    	printf("\n\n");
    	if (l == NULL)
    			 exit(EXIT_FAILURE);
    	while (l->suivant!=NULL)
    	{
    		printf(" %d <=>", l->valeur);
    		l=l->suivant;
    	}
    	printf(" %d\n\n", l->valeur);
    }
     
    // Supprimer un élément en tête de liste
    DLlist supprimert(DLlist l)
    {
    	DLlist tmp;
    	if (l == NULL)
    		tmp=NULL;
    	else
    	{
    		tmp=l->suivant;
    		if (tmp !=NULL)
    			tmp->precedent=NULL;
    		free(l);
    	}
    	return tmp;
    }
     
    // Vérifier si deux listes sont identiques
    int equalsDLlist(DLlist l, DLlist m)
    {
    	if (l == NULL || m == NULL)
    		 exit(EXIT_FAILURE);
    
    	DLlist p = l;
    	DLlist n = m;
    
    	if (p->valeur == n->valeur)
    	{
    		while (p->valeur == n->valeur && p->suivant!=NULL && n->suivant!=NULL)
    		{
    			p = p->suivant;
    			n = n->suivant;
    		}
    		if (p->suivant == NULL && n->suivant == NULL && p->valeur== n->valeur)
    			return TRUE;
    		else
    			return FALSE;
    	}
    	else
    		return FALSE;
    }

    Pour le reste ben c'est quand-même grandement à revoir. Déjà au choix 1 tu appelles newBigInteger() sans récupérer ce qu'il renvoie...
    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]

  18. #18
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2013
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Décembre 2013
    Messages : 8
    Par défaut
    Ca y est, ça marche. Il me reste deux ou trois points à revoir comme vous dîtes mais la fonction marche.
    Je vous en suis tellement reconnaissant merci mille fois. Grâce à vous, je vais ENFIN pouvoir avancer correctement dans mon projet. Désolé encore pour mes questions stupides mes grosses âneries.... En tout cas merci beaucoup d'avoir pris le temps de m'aider ça m'a fait énormément progresser merci !
    En fait, le gros soucis comme vous l'avez judicieusement remarqué était que je n'avais pas alloué mon BigInteger. Et je n'avais vraiment pas compris ce qu'été un header.

    Merci encore.

  19. #19
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 833
    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 833
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Zthoustra Voir le message
    Grâce à vous, je vais ENFIN pouvoir avancer correctement dans mon projet.
    Amène le quand il sera fini. On pourra le corriger...
    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]

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

Discussions similaires

  1. Erreur de compilation avec une structure
    Par existenz3 dans le forum Débuter
    Réponses: 3
    Dernier message: 10/12/2010, 09h07
  2. Problème d'accès à une structure.
    Par a_ferre dans le forum Débuter
    Réponses: 12
    Dernier message: 08/05/2008, 13h25
  3. Gtk: problème pour passer une structure en paramètres
    Par C_Chaou dans le forum GTK+ avec C & C++
    Réponses: 3
    Dernier message: 19/04/2007, 19h29
  4. Réponses: 6
    Dernier message: 14/02/2006, 11h29
  5. Réponses: 7
    Dernier message: 21/12/2005, 16h44

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