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 :

Tab2d et pointeur


Sujet :

C

  1. #1
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut Tab2d et pointeur
    Bonjour à tous,

    Après une soirée de recherche je me décide à faire appel à votre aide, je ne capte pas quelque chose pour faire passer un tableau 2d dans un fonction, je pense que j'ai bien capté le principe des pointeurs mais je ne trouve pas pour le tableau 2D.

    Voici un petit truc rapide pour illustrer ma difficulté, je cherche à faire passer dans une fonction un tableau 2d et simplement faire le double des valeurs dans ce tableau.
    Bon on a pas vraiment d'utiliser les pointeurs pour faire ça mais je cherche à le faire avec pointeurs pour bien comprendre la base.

    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
    void doubleTab(int *pTab[2][2])
    {
        int i, j;
        for (i=0; i<4; i++) {
            for (j=0; j<4; j++) {
                *pTab[i][j] *= 2;
            }
        }
    }
     
    void affichageTab(int pTab[2][2])
    {
        int i, j;
        for (i=0; i<4; i++) {
            for (j=0; j<4; j++) {
                printf("%d", pTab[i][j]);
            }
        }
    }
     
    int main(int argc, const char * argv[]) {
     
        int tTab[2][2] = {{0,1},{2,3}};
        int (*pTab)[2][2] = &tTab;
     
        doubleTab((*pTab)[2][2]);
        affichageTab(pTab[2][2]);
     
    }
    Ce n'est qu'une version car j'ai essayé pas mal d'écriture sans vraiment capter ce qu'il ne va pas


    Merci d'avance pour votre aide
    Ersch

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Bonjour,

    • Dans tes fonctions, tes indices i et j parcourent chacune quatre positions alors que les dimensions de tes tableaux n'en comptent que deux ;
    • Dans la fonction doubleTab(), tu fais croire à ta fonction que tu lui passe un tableau [2][2] de « pointeurs sur des entiers » alors que ce n'est pas du tout le cas (il ne contient que les entiers eux-mêmes). Il aurait au minimum fallu ajouter les parenthèses comme pour la déclaration de pTab dans main.
    • En indexant le tableau et en le déréférençant avec « * », tu fais croire au compilateur que les éléments du tableau (les valeurs 0, 1, 2 et 3) sont les adresses en mémoire de ce que tu veux modifier. Tu sors de ton espace d'adressage et tu déclenches une segfault ;
    • Enfin, lorsque tu appelles tes fonctions, il ne faut pas re-spécifier les « [2][2] » après tes identifiants, sinon c'est l'élément se trouvant à cette position qui sera passé, et pas le tableau lui-même (ou plus précisément son adresse, ou bien la valeur de pTab), donc l'objet transmis à ta fonction n'aura rien à voir avec ce que tu penses lui passer ;
    • Comme les dimensions de ton tableau sont justement « [2][2] », les dimensions ne courent que de 0 à 1 et la case indexée sera en dehors de ton tableau. Tu risqueras à nouveau la segfault, même si c'est peu probable étant donné la faible excursion. Par contre la valeur extraite sera totalement indéfinie.

  3. #3
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Bonjour et merci pour ton aide,

    voici une version corrigé en fonction de tes remarques

    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
     
    void doubleTab(int (*pTab)[2][2])
    {
        int i, j;
        for (i=0; i<2; i++) {
            for (j=0; j<2; j++) {
                (*pTab)[i][j] *= 2;
            }
        }
    }
     
    void affichageTab(int pTab[2][2])
    {
        int i, j;
        for (i=0; i<2; i++) {
            for (j=0; j<2; j++) {
                printf("%d", pTab[i][j]);
            }
        }
    }
     
    int main(int argc, const char * argv[]) {
     
        int tTab[2][2] = {{0,1},{2,3}};
        int (*pTab)[2][2] = &tTab;
     
        doubleTab(pTab);
        affichageTab(*pTab);
    }
    J'ai cependant des points ou ce n'est pas clair

    Dans la fonction doubleTab(), tu fais croire à ta fonction que tu lui passe un tableau [2][2] de « pointeurs sur des entiers » alors que ce n'est pas du tout le cas (il ne contient que les entiers eux-mêmes). Il aurait au minimum fallu ajouter les parenthèses comme pour la déclaration de pTab dans main.
    J'ai compris pourquoi mettre les parenthèses sur (*pTab) mais tu dis qu'il aurait fallu au minimum ajouter les ajouter. Pourquoi au minimum, est ce qu'il y a une façon "plus propre" au niveau de l'écriture?

    Enfin, lorsque tu appelles tes fonctions, il ne faut pas re-spécifier les « [2][2] » après tes identifiants, sinon c'est l'élément se trouvant à cette position qui sera passé, et pas le tableau lui-même (ou plus précisément son adresse, ou bien la valeur de pTab), donc l'objet transmis à ta fonction n'aura rien à voir avec ce que tu penses lui passer ;
    Imaginons mon exercice, au lieu d'avoir des valeurs fixes, je passe par une fonction lecture ou je rentre les valeurs avant de faire doubleTab, quid de comment j'appelle ma fonction? En fait on m'a expliqué en classe quelque chose à propos des indices mais ce n'est plus très clair. De souvenir le second indice n'était pas obligatoire mais il permettait de préciser l'indice par après (pas très clair je te l'accorde) l'écriture donc ressemblerait à pTab[][indice]

    Merci encore pour ton aide

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Ersch Voir le message
    J'ai compris pourquoi mettre les parenthèses sur (*pTab) mais tu dis qu'il aurait fallu au minimum ajouter les ajouter. Pourquoi au minimum, est ce qu'il y a une façon "plus propre" au niveau de l'écriture?
    Bonjour

    Non, pas d'autre façon. Obsidian a (probablement) écrit "au minimum" dans un effet de style et non comme sous-entendu qu'il y avait une autre façon.

    Ou alors si, il y en avait bien une mais c'est en n'utilisant pas l'adresse du tableau mais le tableau lui-même

    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
    void doubleTab(int Tab[2][2])
    {
        int i, j;
        for (i=0; i<2; i++) {
            for (j=0; j<2; j++) {
                Tab[i][j] *= 2;
            }
        }
    }
     
    void affichageTab(int Tab[2][2])
    {
        int i, j;
        for (i=0; i<2; i++) {
            for (j=0; j<2; j++) {
                printf("%d", Tab[i][j]);
            }
        }
    }
     
    int main(int argc, const char * argv[]) {
     
        int tTab[2][2] = {{0,1},{2,3}};
     
        doubleTab(tTab);
        affichageTab(tTab);
    }
    Après-tout, ce que tu veux modifier c'est le contenu du tableau et non le tableau (qui restera un tableau de [2][2]). Donc inutile de passer l'adresse du tableau à ta fonction, le nom du tableau en lui-même suffit car ce nom correspond à l'adresse de son premier élément et comme les éléments se suivent, une fois qu'on a le premier on a alors tous les autres...

    Citation Envoyé par Ersch Voir le message
    Imaginons mon exercice, au lieu d'avoir des valeurs fixes, je passe par une fonction lecture ou je rentre les valeurs avant de faire doubleTab, quid de comment j'appelle ma fonction?
    Pareil. Ta fonction ne fait rien d'autre qu'écrire des valeurs dans le tableau reçu, et ce serait la même chose si les valeurs étaient saisies au clavier au lieu d'êtres prises dans celles déjà présentes dans le tableau.

    Citation Envoyé par Ersch Voir le message
    En fait on m'a expliqué en classe quelque chose à propos des indices mais ce n'est plus très clair. De souvenir le second indice n'était pas obligatoire mais il permettait de préciser l'indice par après (pas très clair je te l'accorde) l'écriture donc ressemblerait à pTab[][indice]
    Exact. Dans les tableaux à "n" dimensions, la valeur de la dernière dimension n'est pas utile et peut alors être omise ("dernière" prise dans le sens mathématique "de la droite vers la gauche").

    En fait, il faut bien comprendre qu'au niveau de la mémoire, il n'y a qu'une seule dimension. C'est une longue suite de cases qui se suivent.
    Prends par exemple un jeu d'échecs 8x8 où chaque case serait numérotée de 1 (A1) jusqu'à 64 (H8). Comment calculer la valeur de la case par exemple C5 ? Hé bien c'est la 5° ligne, chaque ligne faisant 8 colonnes donc ce sera déjà 5*8. Puis c'est la colonne C donc la 3° donc ce sera 5*8+3=43. Et dans ce calcul, le nombre de lignes "8" n'intervient absolument pas.

    Hé bien c'est pareil en C. Dans un tableau par exemple à 2 dimensions comme int tab[5][20], une case référencée [x][y] sera alors convertie en case indicée [z] et ce z est calculé à partir de x, de y et de la première dimension "20" sous la formule z=x*20+y. Et dans cette formule, la valeur "5" n'intervient pas et peut donc être oubliée. Et c'est pareil avec 3, 4, n dimensions.
    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]

  5. #5
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Un grand merci pour votre aide

    Ersch

  6. #6
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Je sollicite encore votre aide car il semble que ce n'est pas encore clair.

    Je veux encoder dans un tableau tTab[][3] une série de jours/mois/années mais pas moyen de trouver ce qui ne va pas dans mon code.

    Dans mon 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
    #include "stdafx.h"
    #include "fonctions.h"
    #define dMaxDate 5
     
     
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int tDate[dMaxDate][3] = { 0 };
    	char tDateConvert[dMaxDate][16];
    	int dNbrLues = 0;
    	int (*pDate)[dMaxDate][3] = &tDate;
     
    	ecLectDates(pDate, dMaxDate, &dNbrLues);
     
    	return 0;
    }
    fichier fonctions.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void ecLectDates(int (*pDate)[][3], int dMaxDate, int *pNbrLues);
    fichier fonctions.cpp

    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
    #include "stdafx.h"
    #include "fonctions.h"
     
    #define MSG_1   11
    #define MSG_2   12
    #define MSG_3   13
    #define jour    0
    #define mois    1
    #define annee   2
     
    void ecLectDates(int (*pDate)[][3], int dMaxDate, int *pNbrLues)
    {
    	do
    	{
    		/* encodage jour */
    		affichageMessage(MSG_1);
     
    		//scanf("%d", &dValeur);
    		scanf("%d", (*pDate)[*pNbrLues][jour]);
     
    		/* encodage mois */
    		affichageMessage(MSG_2);
    		scanf("%d", (*pDate)[*pNbrLues][mois]);
     
    		/* encodage annee */
    		affichageMessage(MSG_3);
    		scanf("%d", (*pDate)[*pNbrLues][annee]);
     
    		(*pNbrLues)++;
    	} while (*pNbrLues < dMaxDate);
    }

    Lorsque je compile ce code, le compliquer me dit:

    Erreur 1 error C2664: 'void ecLectDates(int (*)[][3],int,int *)'*: impossible de convertir l'argument 1 de 'int [5][3]' en 'int (*)[][3]' \\vmware-host\shared folders\drive\langage procédurale\prj24_visual\prj24_visual\prj24_visual.cpp 20 1 PRj24_visual
    J'avoue que je pensais avoir compris avec mon exemple et je ne vois pas trop la différence entre mon example et mon problème ici.

    Merci d'avance pour votre aide.

    Ersch

  7. #7
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Ersch Voir le message

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #define dMaxDate 5
    
    void ecLectDates(int (*pDate)[][3], int dMaxDate, int *pNbrLues)
    {
       ...
    }

    Lorsque je compile ce code, le compliquer me dit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Erreur 1 ...' \\vmware-host\shared folders\drive\langage procédurale\prj24_visual\prj24_visual\prj24_visual.cpp 20 1 PRj24_visual
    J'avoue que je pensais avoir compris avec mon exemple et je ne vois pas trop la différence entre mon example et mon problème ici.
    Tu dois probablement compiler en C++ et non en C car chez-moi, ça compile très bien (mis à part ce problème avec ta variable qui porte le même nom que ta macro que j'ai eu quand moi j'ai tout mis dans le même source).

    Donc même si le C++ a été construit à partir du C, ce ne sont plus du tout les mêmes langages. Certains raccourcis entre pointeurs et tableaux n'existent plus. Vérifie les options de ton compilateur. Ou si tu veux faire du C++ alors t'es pas dans le bon forum.

    Concernant les macros, prends l'habitude de les écrire en majuscules. Déjà pour éviter des confusions du même genre mais surtout d'autres trucs qui peuvent arriver quand on confond macro et fonction et qu'on appelle "i++" dans une macro dans lequel le paramètre est utilisé plusieurs fois.
    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]

  8. #8
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Salut et merci pour ton aide,

    je viens de recommencer un projet neuf dans visual studio avec tes remarques mais maintenant le programme compile mais à la première lecture j'ai une erreur:

    Exception non gérée à 0x5D09C28C (msvcr120d.dll) dans PRj24_visual.exe*: 0xC0000005*: Violation d'accès lors de l'écriture à l'emplacement 0xCCCCCCCC.
    Donc maintenant j'ai bien mes fichiers .c et dans la propriété du projet j'ai Compiler comme code C (/TC).


    Mon main.c

    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
    // PRj24_visual.cpp†: dÈfinit le point d'entrÈe pour l'application console.
    //
     
    #include "stdafx.h"
    #include "fonctions.h"
    #define DMAXDATE 5
     
     
     
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int tDate[DMAXDATE][3];
    	char tDateConvert[DMAXDATE][16];
    	int dNbrLues = 0;
    	int(*pDate)[DMAXDATE][3] = &tDate;
     
    	//  -------------------
    	//  Encondage des dates
    	//  -------------------
     
    	ecLectDates(pDate, DMAXDATE, &dNbrLues);
     
    	return 0;
    }
    foncions.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void ecLectDates(int(*pDate)[][3], int dMaxDate, int *pNbrLues);
    fonctions.c

    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
    #include "stdafx.h"
    #include "fonctions.h"
     
    #define MSG_1   11
    #define MSG_2   12
    #define MSG_3   13
    #define JOUR    0
    #define MOIS    1
    #define ANNEE   2
     
    void ecLectDates(int(*pDate)[][3], int dMaxDate, int *pNbrLues)
    {
    	do
    	{
    		/* encodage jour */
    		affichageMessage(MSG_1);
     
    		//scanf("%d", &dValeur);
    		scanf("%d", (*pDate)[*pNbrLues][JOUR]);
     
    		/* encodage mois */
    		affichageMessage(MSG_2);
    		scanf("%d", (*pDate)[*pNbrLues][MOIS]);
     
    		/* encodage annee */
    		affichageMessage(MSG_3);
    		scanf("%d", (*pDate)[*pNbrLues][ANNEE]);
     
    		(*pNbrLues)++;
    	} while (*pNbrLues < dMaxDate);
    }
     
    //  ----------------------------------------
    //  fonction affichage d'un tableau d'entier
    //  ----------------------------------------
     
    void affichageTabEntier(int (*pTab)[][3], int dNbrLues)
    {
    	int i;
     
    	for (i = 0; i < dNbrLues; i++)
    	{
    		printf("%s", (*pTab)[i][JOUR]);
    		printf("%s", (*pTab)[i][MOIS]);
    		printf("%s", (*pTab)[i][ANNEE]);
    	}
    }
     
     
    //  --------------------------
    //  fonction affichage message
    //  --------------------------
     
    void affichageMessage(int MSG_ID)
    {
    	switch (MSG_ID) {
    	case 11:
    		puts("Jour: ");
    		break;
    	case 12:
    		puts("Mois: ");
    		break;
    	case 13:
    		puts("Annee: ");
    		break;
    	default:
    		break;
    	}
    }

  9. #9
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Dans un scanf(), il faut mettre l'adresse de la donnée destination (alors que dans un printf() on met la donnée à afficher) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void ecLectDates(int(*pDate)[][3], int dMaxDate, int *pNbrLues)
    {
    	do
    	{
    		/* encodage jour */
    		affichageMessage(MSG_1);
     
    		//scanf("%d", &dValeur);
    		scanf("%d", &(*pDate)[*pNbrLues][JOUR]);
     
    		/* encodage mois */
    		affichageMessage(MSG_2);
    		scanf("%d", &(*pDate)[*pNbrLues][MOIS]);
     
    		/* encodage annee */
    		affichageMessage(MSG_3);
    		scanf("%d", &(*pDate)[*pNbrLues][ANNEE]);
     
    		(*pNbrLues)++;
    	} while (*pNbrLues < dMaxDate);
    }
    Maintenant, sur ta manière de gérer le tableau 2D, je reviendrai un peu plus tard.
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  10. #10
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    On se demande pourquoi tu passes l'adresse du tableau sous prétexte que c'est un tableau 2D alors que tu ne ferais jamais cela pour un tableau 1D. Pourtant, les tableaux 2D obéissent aux mêmes règles que les tableaux 1D. Ces règles sont communes à tous les tableaux :

    En général, si on veut accéder, dans une fonction, aux éléments d'un tableau extérieur à la fonction, on passe en argument, non pas l'adresse du tableau, mais l'adresse du premier élément du tableau. Dans le cas d'un tableau d'éléments de type T, on a :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    T tab[DIM]; //1 définition
     
    void fonc(T* tab) {...}; //2 fonction
     
    fonc(tab); //3 appel
    Commentaires :
    I- en 2 on peut aussi avoir void fonc(T tab[]) {...}; . C'est le seul cas (en déclaration d'un paramètre d'une fonction) où une écriture tableau équivaut à une écriture pointeur et le compilateur transcrit l'écriture tableau en écriture pointeur : la variable locale créée tab est un pointeur. Si dans l'écriture tableau, on ajoute une valeur entre les [], elle est ignorée.

    II- en 3, l'identificateur du tableau tab est interprété par le compilateur comme "adresse du premier élément du tableau", de type donc T* .
    C'est le cas le plus général de l'interprétation de cet identificateur, et il y a peu d'exception (tab est opérande de & ou de sizeof), ce qui explique le type utilisé en 2 dans la liste des paramètres de la fonction.

    III- tout cela est très général et est indépendant du type des éléments, en particulier cela reste vrai si T est lui-même un tableau (donc si on a un tableau à plusieurs dimensions).

    Dans le cas où le tableau est un tableau à deux dimensions, on aura donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    T tab[DIM1][DIM2]; //1 définition
     
    void fonc(T (* tab)[DIM2]) {...}; //2 fonction
     
    fonc(tab); //3 appel
    Commentaires :
    - en 2 les éléments du tableau sont des tableaux de DIM2 éléments de type T, T[DIM2], donc le paramètre doit être "adresse d'un tableau de DIM2 éléments T" : T (*)[DIM2] (les parenthèses sont obligatoires car sans elles on aurait un tableau de DIM2 pointeurs sur T). Comme précédemment, ceci peut également s'écrire sous une écriture tableau (uniquement dans une liste de paramètres) T tab[][DIM2].

    Dans ton programme, on a alors :
    Dans main() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	int tDate[DMAXDATE][3];
    	int dNbrLues = 0;
     
    	ecLectDates(tDate, DMAXDATE, &dNbrLues);
            affichageTabEntier(tDate, dNbrLues);
    Dans ecLectDates() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void ecLectDates(int(*pDate)[3], int dMaxDate, int *pNbrLues)
    {
    	do
    	{
    		/* encodage jour */
    		affichageMessage(MSG_1);
     
    		//scanf("%d", &dValeur);
    		scanf("%d", &pDate[*pNbrLues][JOUR]);
     
    		/* encodage mois */
    		affichageMessage(MSG_2);
    		scanf("%d", &pDate[*pNbrLues][MOIS]);
     
    		/* encodage annee */
    		affichageMessage(MSG_3);
    		scanf("%d", &pDate[*pNbrLues][ANNEE]);
     
    		(*pNbrLues)++;
    	} while (*pNbrLues < dMaxDate);
    }
    Et dans affichageTabEntier() (Attention ton code est faux : le format est incorrect)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void affichageTabEntier(int (*pTab)[3], int dNbrLues)
    {
    	int i;
     
    	for (i = 0; i < dNbrLues; i++)
    	{
    		printf("%d ",  pTab[i][JOUR]);
    		printf("%d ",  pTab[i][MOIS]);
    		printf("%d\n", pTab[i][ANNEE]);
    	}
    }
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  11. #11
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Merci pour ton aide, je vais mettre en application tes remarques

  12. #12
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    à tout hasard, une structure ne t'irai pas?

    quelque chose comme ceci?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct date {
        int jour;
        int mois;
        int annee;
    };
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  13. #13
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Hello, je ne sais pas vraiment répondre on n'a pas encore vu les structures

  14. #14
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    ah, ok. Dommage, c'est un bon cas d'usage.
    Ca viendra
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  15. #15
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Si je complique un peu mon exercice et que je décide de faire une allocation de mémoire des tableaux en fonction d'un nombre que l'utilisateur encode au départ, est ce que je dois initialiser mon tableau comme un tableau dans mon main ou comme un pointeur à qui je vais faire un malloc?

    Je suis un peu perdu pour transformer cet exercice vers cette solution

  16. #16
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    allocaton mémoire = pointeur
    Si tu veux un tableau 1D, alors
    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
    type *pt;
     
    // Allocation
    pt=malloc(dim1 * sizeof(type));
    if (pt == NULL)
    {
        // Gestion de l'erreur (généralement on quitte la fonction vu qu'il n'y a rien à faire)
        return;
    }
     
    // Traitement
    for (i=0; i < dim1; i++)
        pt[i]=...
     
    // Libération
    free(pt);

    Si tu veux un tableau 2D, alors
    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
    type **pt;
    // Allocation
    pt=calloc(dim2, sizeof(type*));  // calloc a un avantage, il met tout à 0 (ça servira plus tard)
    if (pt == NULL)
    {
        // Gestion de l'erreur (généralement on quitte la fonction vu qu'il n'y a rien à faire)
        return;
    }
     
    for (i=0; i < dim2; i++)
    {
        pt[i]=malloc(dim1 * sizeof(type));
        if (pt[i] == NULL)
            goto liberation;   // Un des rares cas où un goto peut avoir un avantage
    }
     
    // Traitement
    for (i=0; i < dim2; i++)
    {
        for (j=0; j < dim1; j++);
            pt[i][j]=...;
    }
     
    // Libération
    liberation:
    for (i=0; i < dim2; i++)
        free(pt[i]);
    free(pt);

    Le second exemple joue sur un point important: free(NULL), même s'il ne sert à rien, reste autorisé. Et comme tous les pointeurs alloués via calloc ont été mis à 0, ça me permet de programmer une "libération générale". Donc à ce moment là, 2 possibilités
    1. soit toute l'allocation et le traitement se sont bien déroulés et la libération traite alors tous les pointeurs alloués
    2. soit une allocation intermédiaire a échoué. Le goto a alors envoyé le code sur la libération qui traite aussi tous les pointeurs mais seuls ceux qui ont été correctement alloués seront alors réellement libérés. Un des rares cas où le goto peut avoir un avantage...


    On peut développer le système ainsi à l'infini (mais je n'ai jamais vu plus de 3D)...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  17. #17
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Si tu alloues dynamiquement un tableau par malloc() ou consoeurs, la fonction va te renvoyer, si tout de passe bien, l'adresse du début du tableau qu'elle a réservé.
    Puisque tu dois stocker cette adresse, il te faut un objet pointeur.

    Remarque la cohérence du C : Si tu déclares un tableau, son identificateur est (sauf exceptions) l'adresse du premier élément. Si tu alloues dynamiquement, tu obtiens aussi l'adresse du premier élément. Alors on peut utiliser une syntaxe similaire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int tab[10];
    tab[2]= ...
     
    int * ptab = malloc(10*sizeof *ptab);
    ptab[2] = ...
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  18. #18
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Merci pour vos réponses, juste une question pour revenir au pointeur, si je fais passer un pointeur de type int *tTab ou int **tTab pour un 2d dans la fonction je dois bien mettre l'opérateur & pour donner l'adresse du pointeur et dans le prototype de ma fonction je dois signer que je reçois un pointeur * ou ** c'est bien ça?

    dans le main:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int **pDate;
    	pDate = calloc(3,sizeof(int));
    dans mon fonction.h

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void ecLectDates(int **pDate, int *dNombreDate, int *pNbrLues);
    Encore un grand merci pour votre aide, le principe est clair mais la mise en pratique prend un peu de temps

  19. #19
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 690
    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 690
    Points : 30 985
    Points
    30 985
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Ersch Voir le message
    Merci pour vos réponses, juste une question pour revenir au pointeur, si je fais passer un pointeur de type int *tTab ou int **tTab pour un 2d dans la fonction je dois bien mettre l'opérateur & pour donner l'adresse du pointeur et dans le prototype de ma fonction je dois signer que je reçois un pointeur * ou ** c'est bien ça?
    Non, pas de "&", le nom de la variable étant déjà de type "pointeur". Donc si (dans mon second exemple) je passe "pt" à une fonction, celle-ci le stockera dans un "type **".
    Si je passe "&pt" (j'ai le droit) la fonction devra le stocker dans un "type ***". Ca ne sert que si la fonction a besoin de modifier "pt"...

    Citation Envoyé par Ersch Voir le message
    dans le main:

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int **pDate;
    	pDate = calloc(3,sizeof(int));
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int **pDate;
    	pDate = calloc(3,sizeof(int*));
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  20. #20
    Membre habitué
    Homme Profil pro
    Développeur Java
    Inscrit en
    Mars 2014
    Messages
    85
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Mars 2014
    Messages : 85
    Points : 143
    Points
    143
    Par défaut
    Décidément je dois rater quelque chose, j'ai une erreur pendant la lecture de la première date

    Exception non gérée à 0x69F3C28C (msvcr120d.dll) dans PRj27.exe*: 0xC0000005*: Violation d'accès lors de l'écriture à l'emplacement 0xCDCDCDCD.
    mon main:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int **pDate = NULL;
    	int *pDateConvert = NULL;
    	char **pDateString = NULL;
    	int dNbrLues = 0;
     
    	//  -------------------
    	//  Encondage des dates
    	//  -------------------
     
    	ecLectDates(pDate, &dNbrLues);
    fonction

    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
    #define MSG_1   11
    #define MSG_2   12
    #define MSG_3   13
    #define MSG_4	14
    #define JOUR    0
    #define MOIS    1
    #define ANNEE   2
    #define TRUE 1
    #define FALSE 0
     
    void ecLectDates(int **pDate, int *pNbrLues)
    {
    	/* encodage du nombre de jour */
    	int dNombreDate;
     
    	affichageMessage(MSG_4);
    	scanf("%d", &dNombreDate);
     
    	/* allocation mémoire du tableau */
     
    	pDate = malloc(dNombreDate * sizeof(int*));
     
    	int i;
     
    	for (i = 0; i < dNombreDate; i++)
    	{
    		pDate[i] = malloc(3 * sizeof(int));
    	}
     
    	/* fin allocation mémoire */
     
    	do
    	{
    		/* encodage jour */
    		affichageMessage(MSG_1);
    		scanf("%d", pDate[*pNbrLues][JOUR]);
     
    		/* encodage mois */
    		affichageMessage(MSG_2);
    		scanf("%d", pDate[*pNbrLues][MOIS]);
     
    		/* encodage annee */
    		affichageMessage(MSG_3);
    		scanf("%d", pDate[*pNbrLues][ANNEE]);
     
    		(*pNbrLues)++;
    	} while (*pNbrLues < dNombreDate);
    }

Discussions similaires

  1. pointeurs
    Par ghost74 dans le forum C
    Réponses: 3
    Dernier message: 14/12/2002, 02h52
  2. Pointeur vers un tableau
    Par Nikos dans le forum C
    Réponses: 3
    Dernier message: 09/12/2002, 00h43
  3. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14
  4. djgpp et pointeurs far -2
    Par elvivo dans le forum Autres éditeurs
    Réponses: 16
    Dernier message: 29/07/2002, 22h43
  5. djgpp et pointeurs far
    Par elvivo dans le forum C
    Réponses: 2
    Dernier message: 13/07/2002, 00h44

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