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 tableau 3d et pointeurs


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre prolifique
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    10 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 10 245
    Par défaut Problème tableau 3d et pointeurs
    Bonjour,
    J'ai fais une recherche et je n'ai pas trouvé de solution, en choisissant les résultats que de la partie C et C++, il y a énormément de topics et les noms ne sont pas toujours explicite.
    J'espère ne pas créer un topic, alors qu'il y en existe déjà un.

    Je voudrais faire une espèce d'agenda, avec un tableau à 3 dimensions.
    Je voudrais par exemple que les caractères du nom du premier enregistré soit en [0][0][i].
    [0][1][i] pour l'adresse e-mail (par exemple)
    [0][2][i] pour l'adresse (par exemple)
    [1][0][i] Nom de l'utilisateur du 2ième enregistré.
    etc...

    Je déjà fait ça avec un tableau 2d ont ne peut qu'ajouter les noms de contacts :

    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
    #include <iostream>
    using namespace std;
    #include <string.h>
     
    void AjouterContact(char Tab[][20], int* NbContacts);
    void AfficherContact(char Tab[][20], int NbContacts);
    void SupprimerContact(int* NbContacts);
     
    int main()
    {
    char Tab[10][20];
    int NbContacts=0;
    int Choix;
     
    while(Choix!=4)
    {
    cout <<"1- Ajouter un contact" << endl;
    cout <<"2- Afficher tout les contacts" << endl;
    cout <<"3- Vider l'agenda" << endl;
    cout <<"4- Quitter" << endl;
    cout <<"Taper votre choix : ";
    cin >> Choix;
    cout << endl;
    getchar();
     
     
    	switch(Choix)
    	{
    	case 1:
    		AjouterContact(Tab, &NbContacts);
      cout<<endl;
    		break;
    	case 2:
    		AfficherContact(Tab, NbContacts);
    		cout << endl;
    		break;
    	case 3:
    		SupprimerContact(&NbContacts);
    		break;
    	case 4:
    		return 0;
    		break;
    	default:
    		cout <<"erreur de saisie" << endl;
    	}
    }
     
     
    } 
     
    void AjouterContact(char Tab[][20], int* NbContacts)
    {
    	char Nom[20];
     
    	cout<<"Veuillez entrer votre Nom et Prenom :\n";
    	cin.getline(Nom, 20);
    	strcpy(Tab[*NbContacts], Nom);
    	(*NbContacts)++;
     
     
    }
     
    void AfficherContact(char Tab[][20], int NbContacts)
    {
    int i=0;
     
    cout<<"Affichage de l'agenda :\n";
     
    	while(i<NbContacts)
    	{
    	cout<<i+1<<" - "<<Tab[i]<<endl;
    	i++;
    	}
     
    	if(NbContacts==0)
    	cout<<"L'agenda est vide.\n";
     
    }
     
    void SupprimerContact(int* NbContacts)
    {
    	*NbContacts=0;
    	cout<<"Contacts supprime.\n\n";
    }
    Dans mon cours normalement je devrais mettre :
    void AjouterContact(char** Tab, int* NbContacts);
    Et :
    AjouterContact(&&Tab, &NbContacts);

    Mais là c'est :
    AjouterContact(Tab[][20], &NbContacts);
    Et :
    AjouterContact(Tab, &NbContacts);

    Ça doit venir du fait que je met des caractères ou autre chose...

    J'ai éssayé de mettre dans le main :
    char Tab[10][20][20];
    Et ensuite :
    void AjouterContact(char Tab[][][20], int* NbContacts);
    Et là déjà ça compile plus.

    Mais de toute façon, j'aurais :
    strcpy(Tab[*NbContacts], Nom);
    De faux.
    Je sais pas exactement ce que je dois mettre pour remplit en [0][1][i].
    Surement un truc du genre :
    *(*(Tab+1)+0)
    Ça ferait :
    strcpy(*(*(Tab+1))[*NbContacts], Nom);

    Vous n'auriez pas une solution ?
    Merci, d'avance.
    Au revoir.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut, et bienvenue sur le forum

    As tu une raison de travailler avec un tableau à trois dimensions pour ceci

    En effet, il s'agit là de la pire des mauvaises idées, et ce, pour une séries de raisons dont voici les principales:

    • Il est toujours préférable d'utiliser la classe std::string plutôt que d'utiliser des chaines de caractères "C style" (tableau de caractères terminés par '\0')
    • Il est toujours préférable de regrouper les informations "qui vont bien" (ici, le nom, le prénom et l'E-mail) au sein d'une structure (qui serait logiquement nommée "Contact", par exemple) plutôt qu'au sein d'un tableau de chaines de caractères (selon l'exemple)
    • Lorsqu'il s'agit de représenter des "collections" d'objets (comprend: plusieurs objets de même types qui coexistent à un endroit donné), il est toujours préférable d'utiliser les conteneurs de la STL (ou de boost) dont le choix peut être fait en te basant sur ce diagramme
    • Sans doute d'autres raisons auxquelles je n'ai pas pensé

    Je peux, si tu le souhaite, justifier chacune de ces raisons mais, comme il s'agit ici de te faire partir sur une optique tout à fait différente, j'attendrai ta réponse avant de te présenter la manière de faire
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre prolifique
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    10 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 10 245
    Par défaut
    Merci d'avoir répondu aussi rapidement.
    Je pourrais facilement faire mieux et plus simple, mais c'est un exercice sur les tableaux en 3D.

    J'ai un niveau très bas en C/C++.
    En faite on a pas encore vu la programmation orienté objet, j'ai :
    Quelque part, mais c'est mon prof qui me la donner, parce que cin n'aime pas trop les espaces.

    Au pire si je ne trouve pas de solution ce n'est pas bien grave, je verrais bien à la rentrée, je suis déjà très en avance.

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par thierrybenji Voir le message
    Merci d'avoir répondu aussi rapidement.
    Je pourrais facilement faire mieux et plus simple, mais c'est un exercice sur les tableaux en 3D.
    Evidemment, si c'est un exercice sur les tableaux 3D
    J'ai un niveau très bas en C/C++.

    En faite on a pas encore vu la programmation orienté objet, j'ai :
    Quelque part, mais c'est mon prof qui me la donner, parce que cin n'aime pas trop les espaces.
    Quitte à ne pas travailler en "orienté objet", l'idée était surtout de t'inciter à travailler avec un concept qui existe pour tous les langages de programmation "procéduraux" dits "de troisième génération": les structures de données
    L'orientation objet ayant comme résultat (de manière très restrictive) de permettre aux différents type de disposer de fonctions membres ("méthode")
    Au pire si je ne trouve pas de solution ce n'est pas bien grave, je verrais bien à la rentrée, je suis déjà très en avance.
    Nous allons donc te permettre de "conforter" ton avance

    Mais, avant d'en arriver à ton travail sur les tableau à 3 dimensions, je voudrait revenir sur certains points qui me "chatouillent" au plus haut point dans le code que tu fournis pour le tableau à deux dimensions

    Tu devrais éviter de passer des tableaux en paramètres et préférer le passage de pointeurs (voir de pointeurs de pointeurs) lorsqu'il s'agit de passer des tableaux

    Cela apportera plus de souplesse dans le travaille (le jour où, par exemple, tu déciderais que le nom serait composé de ...30 caractères au lieu de 20 )

    Tu devrais réserver l'utilisation de pointeurs comme arguments aux cas où tu n'as vraiment pas le choix (ici, ce sont les tableaux "C style, en l'occurrence), et, si une fonction doit modifier une valeur, tu garde deux solutions qu'il faut essayer de préférer:
    • le passage par référence
    • le renvoi de la valeur modifiée (qu'il s'agit alors de récupérer dans la fonction appelante) pour autant que le retour de fonction ne soit pas utilisé pour autre chose

    En C++ une référence est en réalité un "alias" de la variable d'origine, ce qui fait que toutes les modifications apportées à la référence seront reportées à sur la variable d'origine

    L'avantage, c'est qu'elle t'évite de devoir travailler avec les indirections

    Dans le code que tu propose, les prototypes de AjouterContact et de SupprimerContact se transformeraient donc en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    /*version qui utilise les références */
    void AjouterContact(char Tab[][20], int& NbContacts);
    void SupprimerContact(int& NbContacts);
    /* version qui utilise le retour de fonction */
    int AjouterContact(char Tab[][20], int NbContacts);
    int SupprimerContact(int NbContacts);
    L'appel des fonctions se faisant alors sous la forme de
    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
     
    /* version utilisant les références */
            case 1:
    		AjouterContact(Tab, NbContacts);
                    cout<<endl; /* [1] */
    		break;
    	case 2:
    		AfficherContact(Tab, NbContacts);
    		cout << endl;/* [1] */
    		break;
    	case 3:
    		SupprimerContact(NbContacts);
    		break;
    	case 4:
                    /*...*/
     
    /* version utilisant le retour de fonction*/
            case 1:
    		NbContacts = AjouterContact(Tab, NbContacts);
                    cout<<endl; /* [1] */
    		break;
    	case 2:
    		AfficherContact(Tab, NbContacts);
    		cout << endl;/* [1] */
    		break;
    	case 3:
    		NbContacts = SupprimerContact(NbContacts);
    		break;
    	case 4:
                    /*...*/
    [1]Au fait, pourquoi ne pas rajouter le "cout<<endl;" directement dans la fonction en question

    Une autre erreur, bien plus dangereuse, que tu commet est de ne pas vérifier si... tu peux encore rajouter un nom avant de le faire...

    En effet, comme tu prévois d'origine que ton tableau ne contiendra que... 10 noms, si - l'utilisateur devant par défaut être considéré comme un imbécile distrait - par malheur, l'utilisateur vient à essayer d'en encoder 11, tu va provoquer une erreur qui fera planter lamentablement ton programme

    Comme le cas de figure est facile à prévoir, autant s'éviter cette mauvaise surprise

    En prenant en compte la remarque précédente, le code serait transformé en
    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
    /* version utilisant les références */
            case 1:
                    if(NbContacts>10)
    		{
                        AjouterContact(Tab, NbContacts);
                        cout<<endl; /* [1] */
                    }
                    else
                        cout<<"maximum de contacts atteint"<<endl;
    		break;
     
    /* version utilisant le retour de fonction*/
            case 1:
                    if(NbContacts>10)
    		{
                        NbContacts = AjouterContact(Tab, NbContacts);
                        cout<<endl; /* [1] */
                    }
                    else
                        cout<<"maximum de contacts atteint"<<endl;
    		break;
    Enfin, le dernier point (pour l'instant, après une lecture en diagonale de ton code) que je voudrais aborder avec toi est ce que j'appellerai la cohérence des données

    Le fait est que, idéalement, tes données doivent être cohérentes entre elles.

    Cela implique que, si NbContacts est à 0, les 10 chaines de caractères devraient être vides

    Cela impliquerait donc qu'il serait bon d'intialiser les 10 chaines de caractères à "vide" avant de commencer à travailler, et de prévoir de les réinitialiser à vide lorsque tu... supprimes les contacts

    Pour s'éviter des copies de code inutiles, je te conseillerais donc volontiers de créer une fonction "init" qui pourrait prendre la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void init(char** tab, int NbContacts)
    {
        for(int i=0;i<NbContacts;++i)
            tab[i][0]='\0';
    }
    qui serait appelée, en début de programme, juste après la déclaration de tes variables mais avant de commencer à proposer le choix de l'action et qui pourrait être appelée par... SupprimerContact, qui deviendrait
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    /* version utilisant les références */
    void SupprimerContact(char** tab, int& NbContacts)
    {
        init(tab, NbContacts);
        NbContacts = 0;
    }
    /* version utilisant le retour de fonction */
    void SupprimerContact(char** tab, int& NbContacts)
    {
        init(tab, NbContacts);
        return 0;
        NbContacts = 0;
    }
    Avant d'aborder ton problème réel (l'utilisation d'un tableau à 3 dimensions), et parce que (une fois de plus) j'ai écrit un véritable roman, je vais te laisser "cogiter" un peu sur ce que j'ai abordé ici, afin de te permettre de réagir dessus
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre prolifique
    Avatar de Ryu2000
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2008
    Messages
    10 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2008
    Messages : 10 245
    Par défaut

    Ça c'est de la réponse !

    Je vais besoin d'un peu de temps pour assimiler tout ça, je vais essayer de me mettre au boulot le plus rapidement possible.

    Je peux déjà vous dire que le fait de mettre le nombre de contact à 0, c'est ce que m'ont professeur m'avait dit de faire.
    Ça me semblait bizarre de ne pas vider les chaines de caractères.

    Si j'ai déclaré le tableau comme ça, c'était pour simplifier.

    Et ouais je vais mettre le cout<<endl; dans les fonctions ça fera un main plus petit.

    Une fois encore merci beaucoup.
    Je vous tiens au courant de l'avancement du code.

    =============================================
    Edit :
    Je suis en train de lire votre post depuis le début.
    J'ai pas encore les bons "réflexes", je n'avais pas pensé à mettre AjouterContact et SupprimerContact en int au lieu de void.
    On bossait les pointeurs juste avant, alors j'en ais ressortie partout...

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par thierrybenji Voir le message

    <snip>
    Je peux déjà vous dire que le fait de mettre le nombre de contact à 0, c'est ce que m'ont professeur m'avait dit de faire.
    Ça me semblait bizarre de ne pas vider les chaines de caractères.
    <snip>
    A vrai dire, les fonction qui manipulent des chaines de caractères "C style" considèrent le caractère '\0' comme étant la fin de la chaine.

    Et donc, si tu assigne la valeur 0 au premier caractère, tu obtiens... une chaine vide

    C'est pour cette raison que le plus facile pour "vider" une chaine de caractères en C est... de mettre le premier caractère (celui qui a l'indice 0) à... 0
    Et ouais je vais mettre le cout<<endl; dans les fonctions ça fera un main plus petit.
    Ce n'est pas tant pour faire une fonction main plus petite que je te conseille de le faire... c'est surtout ce que nous pourrions appeler le "principe de la délégation des tâches" :

    Si une fonction a pour résultat de provoquer un affichage sur la sortie standard, il est "normal" que cette fonction s'assure que le prochaine affichage soit "cohérent", et commence au niveau attendu (ici, sur une nouvelle ligne)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

Discussions similaires

  1. Problème Tableau Sous DW
    Par Lorik dans le forum Balisage (X)HTML et validation W3C
    Réponses: 7
    Dernier message: 04/10/2005, 11h55
  2. C++ Problème de fonctions et pointeurs
    Par zmatz dans le forum C++
    Réponses: 3
    Dernier message: 01/10/2005, 16h20
  3. [perl]Problème tableau indexé
    Par LE NEINDRE dans le forum Langage
    Réponses: 8
    Dernier message: 25/08/2005, 21h24
  4. Tableau 2 dimentions, pointeur
    Par DidierMesenbourg dans le forum C
    Réponses: 4
    Dernier message: 22/02/2005, 08h08
  5. [CR8] Problème tableau sur plusieurs pages???
    Par christophe28 dans le forum SAP Crystal Reports
    Réponses: 5
    Dernier message: 02/11/2004, 15h46

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