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

  1. #1
    Invité
    Invité(e)
    Non Execution de la boucle For lors de son utilisation dans une fonction (Fusion de deux tableaux)
    Bonjour tout le monde,

    J'aimerai avoir votre aide sur un problème qui me tourmente depuis quelque jours avec une boucle (FOR).

    Je vous explique premièrement qu'est ce que j'essaie de faire, dans mon code C, j'essaye de fusionner deux tableaux, A, et B dans un troisième intitulé Tableau_C.

    La première fonction que j'avais fait, permet de définir la taille ainsi que la saisi des tableaux A et B.

    La deuxième fonction qui s'intitule Fusion de deux Tableaux, permet de faire appel à la fonction précédente (Saisi), afin qu'elle puisse concaténer les deux tableaux (A et B), à mon point de vue, elle le fait, mais il ne m'affiche pas le dernier résultat qui est l'Affichage du tableaux C.

    Après plusieurs tentatives, j'ai remarqué que le programme n'exécute pas ma dernière boucle For dans la fonction Fusion des Deux Tableaux.


    Si vous pouvez m'aider, je vous en serais très reconnaissant, vos remarques et critiques seront d'une grande importance durant mon parcours d'apprentissage du langage C.

    Je vous joint une copie de mon code.

    Merci beaucoup à vous tous, et au plaisir de lire vos commentaires.

  2. #2
    Membre averti
    Tu pourrais déjà commencer par poster ton code sur le forum avec les balises de code (clique sur l'icône # et copie-colle ton code entre les balises - prévisualise ton message pour vérifier que le code s'affiche correctement), afin qu'il soit visible et que l'on sache de quoi on parle sur ce topic. Ensuite, on pourra discuter plus précisément de ton code, qui pose de nombreux problèmes.

    De façon très globale, l'un des principaux problèmes dans ton code est que tu sembles ignorer le scope des variables que tu déclares. Ainsi : si tu modifies un tableau qui est local à une fonction, cette modification ne sera pas visible dans la fonction appelante sous prétexte que tu y as déclaré un tableau portant le même nom. Il s'agit de tableaux différents, qui ont chacun leur scope.

    Pour qu'une fonction puisse modifier le contenu d'une variable déclarée dans la fonction appelante, il faut lui passer le pointeur vers cette variable. Pour un tableau, mettre en paramètre le nom du tableau équivaut en C à passer un pointeur vers son premier élément. Pour des variables autres que des tableaux, et qui ne seraient pas déjà des pointeurs, tu devra utiliser l'opérateur & pour signifier que tu veux passer l'adresse de la variable. C'est du C de base, révise ces bases.

    Avant de poster ton code entre balises, éventuellement modifié, tu pourrais te pencher sur la multitude d'avertissements qu'il renvoie lors d'une tentative de compilation, essayer de traiter chacun de ces avertissements et comprendre pourquoi ils se manifestent et nous soumettre un code plus propre.

  3. #3
    Invité
    Invité(e)
    Voici mon code sans erreur, et sans warning
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
     
     
    int Fusion_Deux_Tableaux(int Tableau_1[], int Tableau_2[], int Taille);
    int SaisiDuTableau(int Tableau[]);
     
     
     
    //***************************************************************************************************//
    //                                       FONCTION MAIN                                               //
    //***************************************************************************************************//
    int main(int argc, char *argv[])
    {
        printf("Hello Hamza, Lets get Fun Again!\n\n");
     
    int Taille=0;
    int Tableau_A[Taille];
    int Tableau_B[Taille];
    int Tableau_C[Taille+Taille];
     
        *Tableau_C=Fusion_Deux_Tableaux(Tableau_A, Tableau_B, Taille);
     
    }
     
    //***************************************************************************************************//
    //                                       FONCTION DE FUSION                                          //
    //***************************************************************************************************//
    int Fusion_Deux_Tableaux(int Tableau_1[], int Tableau_2[], int Taille)
    {
    int j = 1;
    int i = 0;
    int k = 0;
    //Taille = 0;
     
    int TableauFusion[Taille+Taille];
     
    SaisiDuTableau(Tableau_1);
        for(i=0 ; i<Taille ; i++)
            {
                TableauFusion[i]=Tableau_1[i];
            }
     
     
    SaisiDuTableau(Tableau_2);
        i=0;
        for(k=Taille ; k<(Taille+Taille) ; k++)
            {
                TableauFusion[k]=Tableau_2[i];
                i++;
            }
     
    for(i=0 ; (i<(Taille+Taille)) ;i++ )
       {
        printf("La valeur du %i element du Tableau est maintenant : %d\n\n", j, *(TableauFusion+i));
        j++;
     
       }
     
       return *TableauFusion;
     
    }
     
    //***************************************************************************************************//
    //                                       SAISI FONCTION                                              //
    //***************************************************************************************************//
     
    int SaisiDuTableau(int Tableau[])
    {
    int j = 1;
    int i = 0;
    int Taille=0;
     
    printf("Donner la taille du Tableau SVP!!\n\n");
    scanf("%i", &Taille);
     
        for(i=0 ; i<Taille ; i++)
        {
            printf("donner le %d Element du tableau \n\n", j);
            scanf("%d", &Tableau[i]);
            j++;
        }
     
    int ValTemporary1, ValTemporary2;
     
        for(i=0 ; (i<Taille) ;i++ )
            {
                for(j=i;j<(Taille);j++)
                {
                    if((Tableau[i]>Tableau[j]))
                        {
                        ValTemporary1=Tableau[i];
                        Tableau[i]=0;
                        ValTemporary2=Tableau[j];
                        Tableau[j]=0;
                        Tableau[i]=ValTemporary2;
                        Tableau[j]=ValTemporary1;
                                    ValTemporary1 = 0;
                                    ValTemporary2 = 0;
                        }
                }
            }
    j=1;
       for(i=0 ; (i<Taille) ;i++ )
       {
          printf("La valeur du %i element du Tableau est : %d\n\n", j, *(Tableau+i));
          j++;
       }
     
     
     
       return *Tableau;
    }
     
     
    //**********************************************************************************************************************//

  4. #4
    Expert éminent sénior
    Bonjour

    J'ai pas lu ton code en détail car je me suis arrêté à ceci: *Tableau_C=Fusion_Deux_Tableaux(Tableau_A, Tableau_B, Taille), avec la fonction "Fusion_Deux_Tableaux()" qui renvoie un simple entier. Et là ça ne peut pas marcher.

    Ce qu'il faut savoir sur les pointeurs et les tableaux, c'est que le nom d'un tableau correspond à l'adresse de son premier élément => tab <=> &tab[0]. Donc le pointé *tab corrrespond à son premier élément tab[0].
    Ainsi, si j'écris int tab[10] puis tab[0]=123 ou *tab=123 les deux instructions sont strictement équivalentes. Et en allant plus loin, le tableau incrémenté de "n" fait pointer directement sue la case "n" => *(tab+n) <=> tab[n]. C'est de cette façon qu'on peut utiliser des pointeurs de balayage de tableaux qui peuvent traiter tout un tableau.

    Donc en écrivant *Tableau_C=truc, tu stockes le résultat de "truc" (ici un int) dans la première case du tableau. Déjà le reste du tableau n'est pas rempli, et d'autre part, un simple int ne peut absolument pas correspondre à la fusion de deux tableaux d'int (ou alors l'int est super grand et contient tous les tableaux concaténés).

    Pour fusionner deux tableaux dans un 3°, ta fonction doit recevoir les 3 tableaux en paramètre => void Fusion_Deux_Tableaux(int tabA[], int tabB[], int tabC[], int taille) (pas besoin de mettre de valeur dans les crochets pour les tableaux 1D). De là, la fonction ayant en main les 3 tableaux, pourra lire le premier, lire le second et remplir le 3°. Et je l'ai mis "void" car je ne vois pas ce qu'elle pourrait renvoyer.

    Une autre solution existe aussi où la fonction de fusion alloue elle-même le tableau contenant le résultat de la fusion puis renvoie le pointeur de l'allocation mais c'est plus compliqué pour un débutant.

    Accessoirement ce n'est pas très sain de mélanger "saisie" et "travail". Une fonction de fusion ne doit s'occuper que de la fusion et pas de la saisie qui se fait ailleurs (par exemple dans le main). Cela la rend plus universelle (demain le tableau pourrait venir d'un fichier et non plus du clavier, la fonction doit pouvoir le traiter pareillement).


    Ah, une dernière chose, quand tu écris int taille=0; int Tableau_A[Taille] il n'y a rien qui te choque ??? Ce n'est pas parce que tu débutes que ça doit t'empêcher de réfléchir...
    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

  5. #5
    Expert éminent
    Citation Envoyé par Sve@r Voir le message
    int taille=0; int Tableau_A[Taille] il n'y a rien qui te choque ???
    utiliser 1 variable au lieu d'1 constante pour déclarer la taille d'1 tableau

  6. #6
    Expert éminent sénior
    Citation Envoyé par foetus Voir le message
    utiliser 1 variable au lieu d'1 constante pour déclarer la taille d'1 tableau
    Oui il y a déjà ça (encore qu'avec les VLA ça le fait) mais c'est surtout la taille à 0 qui m'a fait tiquer !!!

    Et puis toi t'étais pas dans le jeu. Tu as largement prouvé ton niveau en C pour que t'aies pas besoin de donner la réponse. C'était pour le PO
    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

  7. #7
    Invité
    Invité(e)
    Je vous remercier tous pour votre temps et vos réponses, j'apprécié vraiment. Mais mon problème n'est pas encore résolu après vos recommandations/corrections, je n'arrive pas encore à afficher la fusion des deux tableaux, je n'arrive pas à exécuter la dernière printf qui est située dans la dernière boucle FOR de la fonction Fusion !!

  8. #8
    Expert éminent sénior
    Citation Envoyé par hamzafokraoui Voir le message
    je n'arrive pas encore à afficher la fusion des deux tableaux, je n'arrive pas à exécuter la dernière printf qui est située dans la dernière boucle FOR de la fonction Fusion !!
    Et tu penses qu'on va deviner ton nouveau code ???

    Citation Envoyé par hamzafokraoui Voir le message
    je n'arrive pas à exécuter la dernière printf qui est située dans la dernière boucle FOR de la fonction Fusion !!
    Donc c'est que la dernière boucie for() ne s'exécute pas. Donc que la condition de boucle (celle située au milieu) est fausse dès le départ.
    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

  9. #9
    Expert éminent
    dans tes boucles pour, tu peux utiliser l'opérateur virgule pour chaîner les opérations dans les initialisations et les incrémentations
    Ensuite, c'est 1 + compliqué dans les initialisations lorsque tu définies 1 variable

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        i=0;
        for(k=Taille, i=0 ; k<(Taille+Taille) ; k++, i++)
            {
                TableauFusion[k]=Tableau_2[i];
                i++;
            }



    Citation Envoyé par Sve@r Voir le message
    Et puis toi t'étais pas dans le jeu. Tu as largement prouvé ton niveau en C pour que t'aies pas besoin de donner la réponse. C'était pour le PO
    Moi je n'ai pas répondu et lorsque j'ai répondu, au vu du magnifique code "harcodé" de partout, je vois bien que @hamzafokraoui ne pouvait sortir cette réponse (c'était de l'humour - décalage, humour, drôle) parce qu'il vient de commencer le chapitre "Chapitre 3 les pointeurs késako"

  10. #10
    Invité
    Invité(e)
    Problème Résolu
    Citation Envoyé par foetus Voir le message
    dans tes boucles pour, tu peux utiliser l'opérateur virgule pour chaîner les opérations dans les initialisations et les incrémentations
    Ensuite, c'est 1 + compliqué dans les initialisations lorsque tu définies 1 variable
    Merci beaucoup pour ton aide, je viens de résoudre le problème,

    je vais vous faire part de ma solution.

    il s'agit de la variable Taille que j'utilise dans la fonction Fusion, elle est déclarée mais il n'a aucune valeur!!!. elle est définit juste dans la fonction SaisiTableau.
    J'ai déduit donc qu'il faut que je fait un return Taille de la fonction SaisiTableau, que j'utiliserai par la suite dans Fusion. C'est pour cela qu'aucune boucle (FOR) ne s’exécute dans la fonction Fusion, il sait pas c'est quoi la valeur de Taille.

    Merci à vous tous, et bonne journée.

  11. #11
    Membre averti
    Salut hamzafokraoui,

    Bravo !

    Ta variable Taille avait une valeur, celle que tu as passée en paramètre de la fonction. Cependant, vu que tu passes dans les différentes fonctions la variable Taille et non pas un pointeur vers la variable Taille, la fonction appelée travaille sur une copie locale de cette variable, et les modifications faites à cette copie ne seront pas accessibles à la fonction appelante.

    Voilà un code simple pour illustrer cela.

    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
    #include <stdio.h>
     
    void traitement(int n);
     
    int main(void) {
        /* Taille est déclarée dans main et initialisée à 0 */
        int Taille=0;
     
        traitement(Taille);
        printf("Après exécution Taille = %d\n", Taille);
    }
     
    /* la fonction a un prototype qui prend un entier et non un pointeur 
     * le paramètre est alors copié et la fonction travaille sur une
     * copie */
    void traitement(int n) {
        n = 1;
    }


    Affiche : Après exécution Taille = 0

    Une fonction avec un prototype comprenant un pointeur sur int pourra par contre modifier la valeur de la variable passée en paramètre, en accédant indirectement à celle-ci via son adresse.

    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
    #include <stdio.h>
     
    void traitement(int * n);
     
    int main(void) {
        /* Taille est déclarée dans main et initialisée à 0 */
        int Taille=0;
     
        traitement(&Taille);
        printf("Après exécution Taille = %d\n", Taille);
    }
     
    /* la fonction a un prototype qui prend un pointeur sur un entier
     * la fonction dispose désormais d'un moyen indirect d'accéder à la
     * valeur de la variable passée en paramètre et peut la modifier */
    void traitement(int * n) {
        *n = 1;
    }


    Affiche : Après exécution Taille = 1

    Note que j'ai fait exprès dans cet exemple d'utiliser des noms de paramètres qui ne sont pas identiques à la variable passée Taille (on aurait pu), pour illustrer que, dans les deux cas, la fonction travaille avec une nouvelle variable : dans le premier cas avec un int n contenant une copie de la valeur de la variable passée, dans le second cas un int * n qui est une variable pointeur. Le scope de ces variables (leur portée) est limité à la fonction, mais dans le second cas, l'indirection permet d'accéder indirectement au contenu de la variable déclarée dans main via son adresse mémoire.

    Pour le passage de tableaux en paramètres, tu n'as pas à utiliser l'opérateur & pour passer un pointeur, car les concepteurs du C ont décidé que les tableaux ne sont pas copiés et que leur passage en paramètre signifie que l'on passe un pointeur vers le premier élément.

    Pour te convaincre de cela, tu peux remplacer tes int Tableau_1[] par int * Tableau_1 dans ton prototype de Fusion, et elle devrait fonctionner de la même manière.

  12. #12
    Expert éminent
    Citation Envoyé par -Eks- Voir le message
    Cependant, vu que tu passes dans les différentes fonctions la variable Taille et non pas un pointeur vers la variable Taille
    Le problème est + profond c'est 1 problème de conception.
    Il faut faire la fameuse et classique structure/ "objet" Array - Vector avec 1 pointeur et les 2 tailles (taille allouée et nombre d'éléments)

    Parce que tu n'as pas remarqué que @hamzafokraoui est perdu : il parle de retourner la taille "J'ai déduit donc qu'il faut que je fait un return Taille de la fonction SaisiTableau, que j'utiliserai par la suite dans Fusion"
    Mais il ne peut pas retourner 2 trucs : la taille et le tableau.
    Et ta solution de mettre seulement la taille en paramètre sortie (passage par adresse) c'est 1 peu le chantier aussi ... et peut éventuellement exploser le nombre de paramètres (pour chaque tableau tu as le 1 pointeur et la taille à renseigner)

    Mais lorsque tu vois que @hamzafokraoui n'utilise pas l'allocation dynamique (malloc - free), comme je le disais il est au tout début du début de son apprentissage C.
    Donc de là, lui parler de structure, constructeur/ destructeur, ...

  13. #13
    Membre averti
    Bonjour foetus,

    J'ai essayé de lui donner une explication plus détaillée que mon explication d'origine, tout en restant simple, sur le scope des variables et le passage de paramètres, pour que ces notions soient claires pour lui.

    Je le félicitais parce qu'il avait trouvé par lui même la raison pour laquelle sa boucle ne s'exécutait pas, pas parce que je pense que tous ses problèmes sont résolus. Sve@r lui avait en fait donné cette raison de façon elliptique en écrivant que sa "condition de boucle (celle située au milieu) est fausse dès le départ". Il a pu résoudre ce problème en le contournant.

    Je ne sais pas s'il a résolu ou même perçu tous les autres problèmes que posait son code. On ne peut que supposer ce qu'il contient, car il ne poste pas son code modifié (qu'il affirme prendre en compte les remarques des uns et des autres).

    Outre les problèmes que tu signales, il faudrait, à peu près dans cet ordre :
    • demander d'abord le nombre d'éléments dans t1
    • déclarer et dimensionner t1
    • demander le nombre d'éléments dans t2
    • déclarer et dimensionner t2
    • en déduire la dimension de t3, tableau de destination
    • déclarer et dimensionner t3
    • obtenir les données pour t1 et t2 et les fusionner dans t3
    • libérer la mémoire sur t1, t2 et t3 si on a besoin de le faire


    Le choix de passer par une variable tableau dimensionné à l'exécution (variable-length array - VLA), plutôt que par une allocation dynamique (malloc / free), est une solution de facilité dans son cas. Elle peut se justifier : s'il n'a pas à libérer cette mémoire en cours d'exécution ou à en modifier la taille, et s'il lui est autorisé et possible d'utiliser cette possibilité du C disponible depuis l'évolution du standard C99.

    Le choix de passer 2, 4 ou 6 paramètres à ses fonctions est certainement moins élégant que de passer des struct ou des pointeurs sur struct, mais c'est je pense un luxe qu'il pourra se permettre lorsqu'il aura déjà maîtrisé les bases :-)

    Sur la forme, je ne parlerais pas à un débutant en C d'objets, de constructeur / destructeur comme tu le fais, pour ne pas créer de confusion dans son esprit avec le C++.

    Sur le fond, j'aurais, moi aussi, écrit ce programme de façon totalement différente du PO, et sans doutes de la tienne.

  14. #14
    Expert éminent sénior
    Citation Envoyé par -Eks- Voir le message
    Je ne sais pas s'il a résolu ou même perçu tous les autres problèmes que posait son code. On ne peut que supposer ce qu'il contient, car il ne poste pas son code modifié (qu'il affirme prendre en compte les remarques des uns et des autres).
    Ouais. Et quand je lui en ai fait la remarque il est parti en vrille en me disant que son code il l'avait posté et ce gros tartufe a rajouté que si je voulais pas l'aider je n'avais qu'à partir (sans déconner, quand on voit tout ce que je lui ai écrit comme explications !!!). Ensuite j'ai répondu et bon le truc est parti en sucette à tel point que les modos ont dû supprimer toute la suite. T'as remarqué qu'il a mis -1 à tous les posts y compris le tien ?
    Alors maintenant je le laisse se démerder. Il croit qu'il suffit de retourner la taille pour que ça fonctionne il va vite déchanter. Certes, la boucle s'exécutera mais bon, il n'y a pas que ça qui est foiré dans son code.
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site

  15. #15
    Invité
    Invité(e)
    Citation Envoyé par -Eks- Voir le message

    Un énorme Merci à tes remarques et à tes corrections, je prendrai sans aucun doute en note ce que tu viens de mentionner.

    Citation Envoyé par foetus Voir le message

    Merci beaucoup à toi, Tu as raison, je sais que je suis perdu la majorité du temps , saches très bien que j'apprécié tes remarques aussi, et je vais prendre en considération tout ce que tu viens de mentionner.

###raw>template_hook.ano_emploi###