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 :

Le jeu de la vie - compréhension des pointeurs


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2021
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 23
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2021
    Messages : 2
    Par défaut Le jeu de la vie - compréhension des pointeurs
    Bonjour, je débute en c. je me suis intéressé au jeu de la vie et ai trouvé un programme de ce jeu sur ce même site. Cependant une partie du programme m'échappe car je ne suis pas encore très à l'aise avec les pointeurs.
    Je vous remercie pour votre aide et m'excuse pour les fautes d'orthographe.
    La partie que je ne comprends pas est la fonction nb_voisin.
    Ci-dessous le code :

    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
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #define TAILLE 10
    void init_damier(int (*damier)[TAILLE][TAILLE]); //initialisation du damier
    void afficher_matrice(int (*damier)[TAILLE][TAILLE]); //affichage du damier
    int nb_voisin(int i, int j, int (*damier)[TAILLE][TAILLE]); //comptage du nombre de voisins vivants/morts
    void cel_vivante(int* cellule, int nb_voisin);  //changement des cellules en fonction du nb voisins
    void next_gen(int (*damier)[TAILLE][TAILLE]); //generation suivante
    #define VIVANTE 1
    #define MORTE 0
    int main()
    {
        int damier[TAILLE][TAILLE];
        srand(time(NULL));
        init_damier(&damier);
        afficher_matrice(&damier);
        next_gen(&damier);
        afficher_matrice(&damier);
        return 0;
    }
    void init_damier(int (*damier)[TAILLE][TAILLE])
    {
        int i, j;
        for (i = 0; i < TAILLE; ++i) {
            for (j = 0; j < TAILLE; ++j) {
                if((rand()%100) < 20) {
                    (*damier)[i][j] = VIVANTE;
                } else  {
                    (*damier)[i][j] = MORTE;
                }
            }
        }
    }
    void afficher_matrice(int (*damier)[TAILLE][TAILLE])
    {
        int i, j;
        for (i = 0; i < TAILLE; ++i) {
            for (j = 0; j < TAILLE; ++j) {
                if ((*damier)[i][j] == VIVANTE) {
                    printf("0" );
                } else {
                    printf("-" );
                }
            }
            printf("\n" );
        }
        printf("\n" );
    }
    #define MODT(i)  ((TAILLE + (i)) % TAILLE)
    int nb_voisin(int i, int j, int (*damier)[TAILLE][TAILLE])
    {
        return (*damier)[MODT(i-1)][MODT(j-1)] + (*damier)[MODT(i-1)][MODT(j)]
               + (*damier)[MODT(i-1)][MODT(j+1)] + (*damier)[MODT(i)][MODT(j-1)]
               + (*damier)[MODT(i)][MODT(j+1)] + (*damier)[MODT(i+1)][MODT(j-1)]
               + (*damier)[MODT(i+1)][MODT(j)] + (*damier)[MODT(i+1)][MODT(j+1)];
    }
    void cel_vivante(int* cellule, int nb_voisin)
    {
        if (*cellule == VIVANTE) {
            if ((nb_voisin <= 1) || (nb_voisin >=4)) {
                *cellule = MORTE;
            }
        } else {
            if (nb_voisin == 3) {
                *cellule = VIVANTE;
            }
        }
    }
    void next_gen(int (*damier)[TAILLE][TAILLE])
    {
        int i,j;
        for(i = 0; i < TAILLE; ++i) {
            for (j = 0; j < TAILLE; ++j) {
                cel_vivante(&(*damier)[i][j], nb_voisin(i,j,damier)); //on change la cellule si elle satisfait les conditions
            }
        }
    }

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,
    C'est difficile d'expliquer les pointeurs à partir d'un code écrit par quelqu'un qui ne les a pas bien compris. Il y a systématiquement une indirection de trop dans ce code. Commençons par réécrire correctement la fonction.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #define MODT(i)  ((TAILLE + (i)) % TAILLE)
     
    int  nb_voisin( int i, int j, int const damier[][TAILLE] ) {
        return   damier[MODT(i-1)][MODT(j-1)] + damier[MODT(i-1)][j]
               + damier[MODT(i-1)][MODT(j+1)] + damier[i][MODT(j-1)]
               + damier[i][MODT(j+1)] + damier[MODT(i+1)][MODT(j-1)]
               + damier[MODT(i+1)][j] + damier[MODT(i+1)][MODT(j+1)];
    }
    Cette fonction examine les 8 cases contiguës à la case (i,j), elle utilise le fait que VIVANTE vaut 1 et MORTE vaut 0, et donc en ajoutant ces cases on obtient bien le nombre de VIVANTEs autour de (i,j).
    Par exemple, la case à gauche est damier[i-1][j]. Mais que faire si i vaut 0, il n'y a pas de case à gauche. On est ici dans le cas où on considère que la table est cyclique, et donc que la case à considérer à gauche est la case [TAILLE-1][j]. Pour cela il force par un modulo à rester entre 0 et TAILLE-1. la formule (TAILLE+i)%TAILLE dans la macro MODT() gère cette conversion.

    Je n'ai pas parlé de pointeur. Pourtant damier est bien ici un pointeur. Il pointe sur le premier élément d'un tableau de tableaux, et s'utilise comme s'il était un tableau de tableaux.

  3. #3
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    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 832
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Tu ne peux pas comprendre les pointeurs sans avoir appris les pointeurs. Et tu n'apprendras pas les pointeurs en lisant un code qui est présumé fait pour quelqu'un qui les connait déjà. Apprendre les pointeurs c'est faire tes propres essais avec éventuellement des exemples simples qui expliquent les notions de base.

    Pour comprendre les pointeurs, il faut savoir
    1. sur quels principes ils s'appuient
    2. à quoi ils servent
    3. leur syntaxe


    Sur quoi ils s'appuient: ils s'appuient sur le fait que le programme a beau être découpé en fonction, il n'y a qu'une seule grosse zone mémoire pour tout ça. Et donc même si une fonction n'a qu'une petite partie de cette mémoire qui lui est allouée pour ses propres variables (variables locales à la fonction), si elle connait l'adresse d'une autre partie elle a tout à fait le droit d'aller à cette adresse voir ce qu'il y a, bien que cette autre adresse soit dans une partie de la mémoire utilisée par une autre fonction.

    A quoi ils servent: principalement pour qu'une fonctionX puisse modifier une variable située dans une fonctionY. Car même si la fonctionY passe la variable à la fonctionX, cette dernière n'en reçoit qu'une copie et donc même si elle la modifie, elle ne modifie que la copie. Si elle veut modifier l'original, elle doit aller à l'adresse correspondant à cet original pour le modifier. Or une adresse en C se stocke dans un pointeur.
    Une autre utilité est de pouvoir accéder très rapidement à un élément [x] d'un tableau. En effet, tous les éléments d'un tableau se suivent en mémoire. Or l'accès par indice (par crochets) est long (enfin "long" du point de vue processeur mais si tu fais du C c'est parce que tu veux aller vite donc autant ne rien perdre bêtement). Or si tu places un pointeur sur ledit élément, l'accès par pointeur est alors immédiat. Et pour placer un pointeur sur un élément X d'un tableau, suffit de le placer sur le tableau et ensuite l'incrémenter. Le C "reconnaissant" la nature "tableau" du pointeur remplacera cet incrément par un décalage approprié ce qui fait que chaque incrément placera le pointeur sur l'élément suivant du tableau.

    La syntaxe: c'est le plus compliqué à comprendre car celle-ci utilise l'étoile de deux façons différentes. Dans une déclaration, l'étoile signifie "ceci est un pointeur" tandis que dans une expression, elle signifie "la case mémoire pointée par ce pointeur". Donc si j'écris int *pt cela signifie "pt est un pointeur" tandis qu'écrire *pt=123 signifie "à la case pointée par pt j'y mets la valeur 123".
    Mais pourquoi mettre une étoile? Puisqu'une adresse est un simple nombre, ne pourrait-on pas utiliser un simple int pour le stocker? Malheureusement non car l'étoile permet aussi de montrer autre chose: dans l'écriture int *pt, cela indique "pt est un pointeur (il va stocker une adresse)" et aussi "à cette adresse *pt il y a un int" (par opposion au fait qu'il pourrait y avoir un float, un long ou autre) ; chose qu'on ne pourrait pas avoir avec un simple int pour stocker cette adresse.

    Et enfin un exemple: une fonction qui permute 2 int.

    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
    #include <stdio.h>
     
    // La fonction va permuter deux int
    // Elle va donc recevoir les adresses de ces variables pour pouvoir les modifier
    // Elle stockera ces adresses dans des pointeurs
    void permut(int *x, int *y) {
    	// Une variable de transfert
    	int tmp;
     
    	// On sauvegarde la valeur de la première
    	tmp=(*x);
     
    	// On place la seconde dans la première
    	*x=(*y);
     
    	// On remet la sauvegarde dans la seconde
    	*y=tmp;
    }
     
    // Test
    int main() {
    	int a=123;
    	int b=456;
     
    	// Affichage initial
    	printf("a=%d, b=%d\n", a, b);
     
    	// Permutation - On passe les adresses des variables à la fonction
    	permut(&a, &b);
     
    	// Vérification
    	printf("a=%d, b=%d\n", a, b);
    }

    Et un exemple qui montre comment on peut utiliser un pointeur pour traiter un tableau
    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
    #include <stdio.h>
     
    // Test
    int main() {
    	int tab[]={10, 20, 30, 40, 50, -1};
    	size_t i;
     
    	// Affichage classique
    	printf("\n");
    	for (i=0; tab[i] != -1; i++)
    		printf("Tab[%hu]=%d (carré=%d)\n", i, tab[i], tab[i] * tab[i]);
    		// Quatre appels à tab[i] => quatre fois le même calcul pour se placer sur l'indice [i]
     
    	// Utilisation d'un pointeur
    	int *pt;
    	printf("\n");
    	for (pt=tab, i=0; *pt != -1; pt++, i++)
    		printf("Tab[%hu]=%d (carré=%d)\n", i, *pt, (*pt) * (*pt));
    		// Le pointeur est incrémenté une seule fois - On peut l'utiliser quatre fois cela ne coûte rien
    }
    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]

Discussions similaires

  1. besoin d'aide pour jeu d'awalé
    Par Dabech dans le forum Débuter avec Java
    Réponses: 6
    Dernier message: 12/04/2008, 22h41
  2. Besoin d'aide jeu du morpion
    Par narcis60floyjo dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 28/02/2008, 15h14
  3. besoin d'aide sur 1 jeu :(
    Par dani_fr dans le forum Flash
    Réponses: 3
    Dernier message: 25/05/2007, 10h13
  4. [Débutant] Besoin d'aide pour modifier un jeu
    Par stoff66 dans le forum Assembleur
    Réponses: 9
    Dernier message: 31/08/2006, 18h24
  5. Besoin d'aide pour un projet de jeu en ligne
    Par FLEO dans le forum Projets
    Réponses: 1
    Dernier message: 21/10/2005, 08h55

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