Partage
  • Partager sur Facebook
  • Partager sur Twitter

Exercices pour débutants en C (suite)

Venez vous entrainer!

    22 mai 2010 à 19:26:04

    Citation : clad yus

    Slt à tous, je profite du fait que vous fassiez des exos pour vous exposez mon problème, je fais un jeu de poker et il me faut une fonction pour distribuer des cartes de façon aléatoire en mode graphique, j'ai cherché partout sur le net ms je ne trouve rien et la je suis complètement bloqué, je n'arrive plus à avancer.




    Ce n'est pas l'endroit pour poser ce genre de question. Ouvre un nouveau topic et sois plus précis dans ta demande.
    • Partager sur Facebook
    • Partager sur Twitter
      22 mai 2010 à 19:29:58

      Je me disais que c'étais pas nécessaire d'ouvrir un topic pr sa mais bon.
      • Partager sur Facebook
      • Partager sur Twitter
        1 juin 2010 à 18:02:18

        zTransforme - Correction



        Exercice 1



        Contraintes de l'énoncé : La matrice a pour taille maximale 1000x1000 ( static int matrice[1000][1000] )

        Cet exercice demandait d'inverser les colonnes et les lignes de la matrice reçues en entrée.

        Il suffisait donc d'inverser les coordonnées des valeurs de la matrice.

        Schéma :
        [a1 a2 a3 a4 a5]    [a1 b1 c1]
        [b1 b2 b3 b4 b5] => [a2 b2 c2] 
        [c1 c2 c3 c4 c5]    [a3 b3 c3] 
                            [a4 b4 c4] 
                            [a5 b5 c5]
        =======================================================
        [(0,0) (0,1) (0,2) (0,3) (0,4)]    [(0,0) (0,1) (0,2)]
        [(1,0) (1,1) (1,2) (1,3) (1,4)] => [(1,0) (1,1) (1,2)]
        [(2,0) (2,1) (2,2) (2,3) (2,4)]    [(2,0) (2,1) (2,2)]
                                           [(3,0) (3,1) (3,2)]
                                           [(4,0) (4,1) (4,2)]


        La fonction à réaliser était donc très simple (dans notre cas MAX_COLS vaut 1000) :
        void
        rows_become_cols (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i)
                for (j = i ; j < cols ; ++j)
                    if (i != j)
                        swap(matrix, i, j, j, i);
        }
        


        Exemple de fonction d'échange possible :
        void
        swap (int (*matrix)[MAX_COLS], size_t i1, size_t j1, size_t i2, size_t j2) {
            if (i1 != i2 || j1 != j2) {
                int tmp;
                tmp = matrix[i1][j1];
                matrix[i1][j1] = matrix[i2][j2];
                matrix[i2][j2] = tmp;
            }
        }
        


        L'affichage ne posait guère plus de problèmes :
        void
        print_matrix (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i) {
                for (j = 0 ; j < cols ; ++j)
                    printf("%c%d", j == 0 ? '[' : ' ', matrix[i][j]);
                puts("]");
            }
        }
        


        Solution complète :
        #include <stdio.h>
        #include <stdlib.h>
        
        #define MAX_ROWS 1000
        #define MAX_COLS 1000
        
        void
        clear_stdin () {
            int c;
            while ((c =getchar()) != '\n' && c != EOF);
        }
        
        int
        get_i (const char * msg) {
            int val;
            
            if (msg != NULL) {
                printf("%s ", msg);
            }
            while (scanf("%d", &val) != 1) {
                puts("Veuillez entrez un nombre entier");
                clear_stdin();
            }
            /* Decommentez la ligne suivante si vous voulez obtenir un buffer propre *
             * (ie. A la fin de la fonction le buffer clavier est vide)              */
            /*clear_stdin();*/
            return val;
        }
        
        void
        fill_matrix (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i)
                for (j = 0 ; j < cols ; ++j)
                    matrix[i][j] = get_i(NULL);
        }
        
        void
        swap (int (*matrix)[MAX_COLS], size_t i1, size_t j1, size_t i2, size_t j2) {
            if (i1 != i2 || j1 != j2) {
                int tmp;
                tmp = matrix[i1][j1];
                matrix[i1][j1] = matrix[i2][j2];
                matrix[i2][j2] = tmp;
            }
        }
        
        void
        print_matrix (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i) {
                for (j = 0 ; j < cols ; ++j)
                    printf("%c%d", j == 0 ? '[' : ' ', matrix[i][j]);
                puts("]");
            }
        }
        
         /**
          * Exercice 1 : Retourner une matrice :
          * Les  lignes deviennent les colonnes
          * et les colonnes deviennent les lignes.
          *  Exemple :
          *
          * [a1 a2 a3 a4 a5]    [a1 b1 c1]
          * [b1 b2 b3 b4 b5] => [a2 b2 c2]
          * [c1 c2 c3 c4 c5]    [a3 b3 c3]
          *                     [a4 b4 c4]
          *                     [a5 b5 c5]
          * Solution : Inverser les coordonnees des
          *            valeurs de la matrice.
          */
        void
        rows_become_cols (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i)
                for (j = i ; j < cols ; ++j)
                    if (i != j)
                        swap(matrix, i, j, j, i);
        }
        
        int
        main (void) {
        
            static int matrice[MAX_ROWS][MAX_COLS] = {{0}};
            int rows, cols;
        
            rows = cols = 0;
        
            rows = get_i(NULL);
            cols = get_i(NULL);
        
            fill_matrix(matrice, rows, cols)
        
            rows_become_cols(matrice, rows, cols);
            
            print_matrix(matrice, cols, rows);
        
            return EXIT_SUCCESS;
        }
        


        Exercice 2



        Pour cet exercice les contraintes sont les mêmes que pour l'exercice 1. Cette fois ci, il faut faire tourner la matrice 90° dans le sens des aiguilles d'un montre.
        Pour cela, il suffit de remarquer qu'une fois que l'on a appliqué la fonction crée dans l'exercice 1 à la matrice, il suffit d'échanger les colonnes selon un axe de symètrie qui est la colonne médiane.

        On arrivait donc à :
        void
        rotation90 (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i)
                for (j = i ; j < cols ; ++j)
                    swap(matrix, i, j, j, i);
        
           /*Mirroir vertical */
            for (i = 0 ; i < cols ; ++i)
                for (j = 0 ; j < div(rows, 2).quot ; ++j)
                    swap(matrix, i, j, i, rows-1-j);
        }
        


        L'échange et l'affichage sont gérés de la m^me manière que dans l'exercice 1.

        Solution complète :
        #include <stdio.h>
        #include <stdlib.h>
        
        #define MAX_ROWS 1000
        #define MAX_COLS 1000
        
        void
        clear_stdin () {
            int c;
            while ((c =getchar()) != '\n' && c != EOF);
        }
        
        int
        get_i (const char * msg) {
                int val;
        
            if (msg != NULL) {
                printf("%s ", msg);
            }
            while (scanf("%d", &val) != 1) {
                puts("Veuillez entrez un nombre entier");
                clear_stdin();
            }
            /* Decommentez la ligne suivante si vous voulez obtenir un buffer propre *
             * (ie. A la fin de la fonction le buffer clavier est vide)              */
            /*clear_stdin();*/
            return val;
        }
        
        void
        fill_matrix (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i)
                for (j = 0 ; j < cols ; ++j)
                    matrix[i][j] = get_i(NULL);
        }
        
        void
        swap (int (*matrix)[MAX_COLS], size_t i1, size_t j1, size_t i2, size_t j2) {
            if (i1 != i2 || j1 != j2) {
                int tmp;
                tmp = matrix[i1][j1];
                matrix[i1][j1] = matrix[i2][j2];
                matrix[i2][j2] = tmp;
            }
        }
        
        void
        print_matrix (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i) {
                for (j = 0 ; j < cols ; ++j)
                    printf("%c%d", j == 0 ? '[' : ' ', matrix[i][j]);
                puts("]");
            }
        }
        
         /**
          * Exercice 2 : Rotation d'une matrice :
          *  Faire pivaoter de 90° la matrice
          *
          *  Exemple :
          *
          * [a1 a2 a3 a4 a5]    [d1 c1 b1 a1]
          * [b1 b2 b3 b4 b5] => [d2 c2 b2 a2]
          * [c1 c2 c3 c4 c5] => [d3 c3 b3 a3]
          * [d1 d2 d3 d4 d5]    [d4 c4 b4 a4]
          *                     [d5 c5 b5 a5]
          *
          * Observations : La 1ere  col -> la 1ere  ligne
          *                La n-eme col -> la n-eme ligne
          * Solution : Inversion lignes/colonnes
          *            + mirroir vertical
          */
        void
        rotation90 (int (*matrix)[MAX_COLS], size_t rows, size_t cols) {
            size_t i, j;
        
            for (i = 0 ; i < rows ; ++i)
                for (j = i ; j < cols ; ++j)
                    swap(matrix, i, j, j, i);
        
           /*Mirroir vertical */
            for (i = 0 ; i < cols ; ++i)
                for (j = 0 ; j < div(rows, 2).quot ; ++j)
                    swap(matrix, i, j, i, rows-1-j);
        }
        
        int
        main (void) {
        
            static int matrice[MAX_ROWS][MAX_COLS] = {{0}};
            int rows, cols;
        
            rows = cols = 0;
        
            rows = get_i(NULL);
            cols = get_i(NULL);
        
            fill_matrix(matrice, rows, cols) == 0
        
            rotation90(matrice, rows, cols);
        
            print_matrix(matrice, cols, rows);
        
            return EXIT_SUCCESS;
        }
        


        Exercice 3



        Cet fois ci l'énoncé demandait :

        Citation : énoncé

        Vous définissez une valeur, par exemple 9. Votre but est d'afficher un carré de 9 de coté (dans notre exemple). Chaque case du tableau contient le numéro de sa colonne. Par contre si cette case appartient à une des diagonales du carré vous mettez un `#` à la place du numéro de la colonne.



        Solution :
        On affiche le numéro de la colonne sauf si :
        • le numéro de la ligne est égal à celui de la colonne. (On affiche un '#')
        • Le nombre de colonnes plus un moins le numéro de la ligne vaut le numéro de la colonne. (On affiche un '#')


        Soit :
        #include <stdio.h>
        
        #define MAX 9
        
        int
        main (void) {
            size_t i, j;
            
            for (i = 1 ; i <= MAX ; ++i) {
              for (j = 1 ; j <= MAX ; ++j) {
                    if (j == i  || j == MAX-i+1) {
                        printf("%s%c", "#", j == MAX ? ' ' : '-');
                    } else {
                        printf("%d%c", j, j == MAX ? ' ' : '-');
                    }
                }
                putchar('\n');
            }
            
          return 0;
        }
        


        Enjoy :)
        • Partager sur Facebook
        • Partager sur Twitter
          1 juin 2010 à 22:25:03

          Citation : Lithrein


          Solution complète



          Déjà si tu pouvais corriger ça :

          sdz.c: In function ‘rows_become_cols’:                                                                        
          sdz.c:82: warning: control reaches end of non-void function
          sdz.c: In function ‘fill_matrix’:
          sdz.c:37: warning: control reaches end of non-void function


          car je vois même pas quelle était ton intention.

          Sinon, à vue d'oeil, ça m'a l'air peu KISS.
          • Partager sur Facebook
          • Partager sur Twitter
            1 juin 2010 à 22:38:40

            Pour les fonctions sans retours j'ai corrigé (Mon intention était renvoyé 1 en cas de réussite et 0 en cas d'échec mais il n'y en a pas eu besoin).

            Citation : candide

            Sinon, à vue d'oeil, ça m'a l'air peu KISS.



            Ah, j'ai pourtant essayé d'être simple, tout du moins sur les fonctions principales, mais peut-être que je me suis fourvoyé.
            • Partager sur Facebook
            • Partager sur Twitter
              2 juin 2010 à 1:24:24

              Citation : Lithrein


              Citation : candide

              Sinon, à vue d'oeil, ça m'a l'air peu KISS.



              Ah, j'ai pourtant essayé d'être simple, tout du moins sur les fonctions principales, mais peut-être que je me suis fourvoyé.



              Non, je ne serais pas si sévère, et je n'ai pas envie d'être sévère avec toi, je trouve d'ailleurs que tu codes plutôt bien, tu es très sympathique, je suis rude voire peu aimable avec toi et tu gardes une courtoisie très élégante. Mais, bon il n'empêche que peut-être en voulant être trop rigoureux, ton code devient compliqué.

              Déjà, ta solution explique mieux la spécification de ton problème. On place (opération d'écriture et pas seulement d'affichage) les lignes en colonnes dans le tableau alloué.


              Echanger comme tu le fais n'est peut-être pas très heureux : supposons qu'on ait juste une seule ligne avec 500 fois le nombre 42. On veut placer cette ligne en colonne : on a aucune raison d'échanger 42 avec 0 (on a juste besoin de placer 42 là où il faut, le 0 osef), ce qu'on fait avec ta méthode qui coûterait 1500 affectations au lieu de 500. Au total, la meilleure solution ne serait-elle pas de faire comme avait fait Gurney je crois, à savoir
              1) échanger le petit carré commun au tableau et au tableau transposé
              2) placer les "bouts" restants dans l'autre sens
              ?

              Bon de toutes façons, je trouve que tu aurais dû donner l'exo avec un carré et pas un rectangle, c'était nettement plus simple.

              Ensuite, tu compliques la tâche du débutant en mettant en paramètre des pointeurs vers des tableaux au lieu de gentils tableaux 2D.

              Ton swap est inutilement compliqué puisque tu échanges deux positions quelconques alors qu'on a juste besoin d'échanger une position donnée avec sa symétrique. C'est particulièrement visible lors de l'appel swap(matrix, i, j, j, i); où i et j sont répétés.

              Tu mélanges parfois des signés et des non signés (et puis size_t est compliqué).

              Pourquoi initialises-tu un tableau static à 0, ça ne sert à rien ?

              Pourquoi "initialises"-tu rows et cols à part, autant initialiser vraiment à la déclaration ?

              Pourquoi surcharges-tu l'affichage avec tes crochets ?

              Les entrées/sorties, surtout sur l'entrée standard, ça fait chuter le rapport signal/bruit. Imagine que ton code sans la gestion des entrées et ses conséquences passe de 104 lignes à 66 lignes. Et franchement, on comprend tout aussi bien ton algo si on écrit :


              static int matrice[MAX_ROWS][MAX_COLS] = 
                  {
                      {4, 3, 7},
                      {1, 2, 5},
                  };
              



              Bon, finalement, je me suis résolu à écrire un code et même plutôt deux. Le premier code fait un swap indiscriminé :

              #include <stdio.h>
              
              #define MAX_ROWS 1000
              #define MAX_COLS 1000
              
              void inverser(int t[][MAX_COLS], int nl, int nc)
              {
                int lig, col;
              
                for (lig = 0; lig < nl || lig < nc; lig++)
                  for (col = lig + 1; col < nc || col < nl; col++)
                    {
                      int temp = t[lig][col];
              
                      t[lig][col] = t[col][lig];
                      t[col][lig] = temp;
                    }
              }
              
              void afficher(int t[][MAX_COLS], int nl, int nc)
              {
                int lig, col;
              
                for (lig = 0; lig < nl; lig++)
                  {
                    for (col = 0; col < nc; col++)
                      printf("%d ", t[lig][col]);
                    printf("\n");
                  }
              }
              
              int main(void)
              {
                int nl = 2, nc = 3;
              
                static int t[MAX_ROWS][MAX_COLS] = {
                  {4, 3, 7},
                  {1, 2, 5},
                  /* {0, 3, 6}, */
                  /* {8, 9, 4} */
                };
              
                afficher(t, nl, nc);
                printf("\n");
                inverser(t, nl, nc);
                afficher(t, nc, nl);
              
                return 0;
              }
              


              L'autre un peu plus fin qui ne fait que les swap nécessaires et utilise l'opérateur ternaire que les débutants n'aiment pas trop :

              #include <stdio.h>
              
              #define MAX_ROWS 1000
              #define MAX_COLS 1000
              
              void inverser(int t[][MAX_COLS], int nl, int nc)
              {
                int lig, col;
                int min = nl < nc ? nl : nc;
              
                for (lig = 0; lig < min; lig++)
                  for (col = lig + 1; col < min; col++)
                    {
                      int temp = t[lig][col];
              
                      t[lig][col] = t[col][lig];
                      t[col][lig] = temp;
                    }
              
                {
                  int a = nc == min ? min : 0;
                  int b = nc != min ? min : 0;
              
                  for (lig = a; lig < nl; lig++)
                    for (col = b; col < nc; col++)
                      t[col][lig] = t[lig][col];
                }
              }
              
              void afficher(int t[][MAX_COLS], int nl, int nc)
              {
                int lig, col;
              
                for (lig = 0; lig < nl; lig++)
                  {
                    for (col = 0; col < nc; col++)
                      printf("%d ", t[lig][col]);
                    printf("\n");
                  }
              }
              
              int main(void)
              {
                int nl = 4, nc = 3;
                static int t[MAX_ROWS][MAX_COLS] = {
                  {4, 3, 7},
                  {1, 2, 5},
                  {0, 3, 6}, 
                  {8, 9, 4}
                };
              
                afficher(t, nl, nc);
                printf("\n");
                inverser(t, nl, nc);
                afficher(t, nc, nl);
              
                return 0;
              }
              


              • Partager sur Facebook
              • Partager sur Twitter
                2 juin 2010 à 16:29:05

                zPointers - Du 2 Juin au 15 Juin


                Exercice 1 : Un problème de temps



                Le temps suit une norme tel que :
                • 1 semaine représente 7 jours.
                • 1 jour représente 24 heures.
                • 1 heure représente 60 minutes.
                • 1 minute représente 60 secondes.


                Vous devez donc faire une fonction qui prend en paramètre un nombre de semaines, de jours, d'heures, de minutes et de secondes et les équilibrer selon la norme ci-dessus.

                void equilibrer_temps (long * semaines, long * jours, long * heures, long * minutes, long * secondes);
                


                #include <stdlib.h>
                
                void equilibrer_temps (long * semaine, long * jours, long * heures, long * minutes, long * secondes);
                
                int
                main (void) {
                    long semaines, jours, heures, minutes, secondes;
                
                    semaines = 0;
                    jours = 8;
                    heures = 20;
                    minutes = 120;
                    secondes = 60;
                
                    equilibrer_temps (&semaines, &jours, &heures, &minutes, &secondes);
                    /* 1 semaine, 1 jour, 22 heures, 1 minutes */
                
                    return EXIT_SUCCESS;
                }
                


                Edit : Les paramètres de la fonction `equilibrer_temps ' deviennent de type long plutôt que size_t car ils sont mieux adaptés au problème.

                Exercice 2 : Quelques fonctions utiles



                La bibliothèque standard du C fournie quelques fonctions utiles dans le fichier d'entête string.h. Je parle bien sûr de :
                • void *memcpy(void * restrict dest, const void * restrict src, size_t n);
                • void *memmove(void *dest, const void *src, size_t n);
                • void *memset(void *s, int c, size_t n);


                Votre but va être de recoder ces fonctions pour vous familiariser avec l'arithmétique des pointeurs. Pour cela, je vous donne les pages qui décrivent le comportement de ces fonctions : memcpy, memmove, memset.

                Bonne chance.

                Exercice 3 : Bonus - Pointeurs de fonctions



                Les pointeurs sur variables c'est cool mais il existe aussi les pointeurs de ... fonctions.
                C'est pourquoi je propose en bonus, un exercice sur les pointeurs de fonctions.

                Premièrement, j'interdit le mot clé typedef (car sinon c'est moins cool :-° ).
                Deuxièmement : Vous avez quatres fonctions :
                float addition(float a, float b) { return a + b ;}
                float soustraction(float a, float b) { return a - b ;}
                float multiplication(float a, float b) { return a * b ;}
                float division(float a, float b) { return a / b ;}
                


                Votre but est d'écrire une fonction : opCode (prototype à trouver) qui renvoie un pointeur sur une des quatre fonctions ci-dessus, en fonction de l'opérateur passé en paramètre.

                type_a_trouver ptr_fct = NULL;
                
                ptr_fct = opCode('+'); /* ptr_fct pointe sur la fonction addition */
                ptr_fct = opCode('-'); /* ptr_fct pointe sur la fonction soustraction */
                ptr_fct = opCode('*'); /* ptr_fct pointe sur la fonction multiplication */
                ptr_fct = opCode('/'); /* ptr_fct pointe sur la fonction division */
                


                Mais ce n'est pas tout. Maintenant que cela est fait vous devez créer une autre fonction (prototype à trouver grâce à l'exemple) qui applique la fonction pointée par ptr_fct à 'a' et 'b' deux nombres réels (float ) et qui renvoie le résultat de cette application.

                type_a_trouver ptr_fct = NULL;
                float a = 2., b = 3., c = 0.;
                
                ptr_fct = opCode('+'); /* ptr_fct pointe sur la fonction addition */
                c = appliquer_fonction(ptr_fct, a, b);
                


                Oui, cet exercice est complètement inutile mais je n'ai pas trouvé mieux ;) .

                Bonne chance.

                Vous pouvez proposer vos solutions ou demander des conseil sur le sujet lié à l'exercice.
                __________________________________________________________________

                Candide,
                Je prend note de tes remarques sur la fonction d'inversement.

                Citation : candide

                Pourquoi "initialises"-tu rows et cols à part, autant initialiser vraiment à la déclaration ?



                Car je trouve plus clair d'initialiser après mais finalement cela n'a pas grande importance.

                Citation : candide

                Pourquoi surcharges-tu l'affichage avec tes crochets ?



                Car je pense que cela permet de mieux voir qu'il s'agit d'un tableau qui est affiché.
                • Partager sur Facebook
                • Partager sur Twitter
                  2 juin 2010 à 16:59:02

                  Salut Lithrein.

                  Quelques remarques.
                  Je trouve que les 3 exercices ne sont pas bien disctints.
                  Le débutant qui parcourt rapidement, et qui lit "pointeur de fonction", je pense qu'il est parti...loin. ;)

                  Le 2ème exercice à déjà été traité dans le tuto hormis que c'est strcpy, et pas memcpy, etc...

                  Effectivement le troisième, présente peu d'intérêt, mais ça peut être l'occasion d'aborder ces pointeurs de fonctions.

                  Et, tu n'as pas mis de lien vers le topic dédié au sujet.

                  a+
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Zeste de Savoir, le site qui en a dans le citron !
                    2 juin 2010 à 18:22:05

                    @GurneyH : J'ai rajouté un préfixe devant le nom de chaque exercice pour les séparer.
                    Pour le deuxième exercice : Je ne savais qu'il y avait cet exercice dans le tutoriel. Mais cela reste quand même intéressant car on travaille sur des pointeurs génériques et cela permet de faire d'autres fonctions qui font travailler l'arithmétique des pointeurs.
                    Et pour le dernier exercice, je ne voyais pas trop quoi faire, surtout que les pointeurs ont une utilisation assez spécifique. Enfin, l'exercice fait à peu près le tour des utilisations les plus courantes des pointeurs de fonctions.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      2 juin 2010 à 18:46:14

                      Bonjour Lithrein, pourquoi le type size_t dans le premier exercice de zPointers? Des unsigned, pourquoi pas (même si je trouve risqué l'usage des types non signés), mais pourquoi size_t?
                      • Partager sur Facebook
                      • Partager sur Twitter
                        2 juin 2010 à 18:54:27

                        Salut Marc,

                        J'ai choisi le type size_t car je souhaitais un type non signé (les heures négatives n'existant pas) et avec une valeur maximale supérieure à celle d'un unsigned (Bien que dans certaines implémentation size_t et unsigned soient équivalents).
                        • Partager sur Facebook
                        • Partager sur Twitter
                          2 juin 2010 à 20:14:18

                          Citation : Lithrein


                          J'ai choisi le type size_t car je souhaitais un type non signé (les heures négatives n'existant pas) et avec une valeur maximale supérieure à celle d'un unsigned (Bien que dans certaines implémentation size_t et unsigned soient équivalents).


                          Ah, pour faire ça, j'aurais pris unsigned long .
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Anonyme
                            2 juin 2010 à 22:28:12

                            Voilà je propose mon code pour l'exercice 1. Toute critique est la bienvenue ;) .
                            // zPointers
                            //	by benjamin -- June 2010
                            
                            #include <stdlib.h>
                            #include <stdio.h>
                            
                            void equilibrate_time(size_t *weeks, size_t *days, size_t *hours, size_t *minutes, size_t *seconds);
                            
                            int main(void)
                            {
                            	size_t weeks, days, hours, minutes, seconds;
                            
                            	weeks = 0;
                            	days = 8;
                            	hours = 20;
                            	minutes = 120;
                            	seconds = 60;
                            
                            	equilibrate_time(&weeks, &days, &hours, &minutes, &seconds);
                            	printf("%d weeks %d days %d hours %d minutes %d seconds\n", weeks, days, hours, minutes, seconds);
                            
                            	return EXIT_SUCCESS;
                            }
                            
                            void equilibrate_time(size_t *weeks, size_t *days, size_t *hours, size_t *minutes, size_t *seconds)
                            {
                            	*minutes += (*seconds/60);
                            	*seconds %= 60;
                            	*hours += (*minutes/60);
                            	*minutes %= 60;
                            	*days += (*hours/24);
                            	*hours %= 24;
                            	*weeks += (*days/7);
                            	*days %= 7;
                            }
                            

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              2 juin 2010 à 22:47:00

                              Oups! oO

                              Je vais le poster dans le bon topic.
                              • Partager sur Facebook
                              • Partager sur Twitter
                                3 juin 2010 à 8:21:31

                                Citation : Lithrein


                                J'ai choisi le type size_t car je souhaitais un type non signé (les heures négatives n'existant pas) et avec une valeur maximale supérieure à celle d'un unsigned



                                C'est un mauvais choix que d'avoir pris size_t qui est un type système utilisé pour mesurer la taille d'objets en mémoire ou des tailles de tableaux.

                                Et je ne comprends pas cette manie de choisir des types non signés lesquels engendrent beaucoup de confusion à cause des fréquentes conversions traitresses que leur utilisation entraîne. Je rappelle que le type naturel en C est le type int, ce n'est pas moi qui le dis c'est la Norme :

                                Citation : C99


                                A ‘‘plain’’ int object has the natural size suggested by the architecture of the execution environment



                                En outre, ne pas choisir int est une source de complication aussi pour les débutants (spécification de format pour printf moins habituelle).

                                Quant à des heures négatives c'est tout à fait envisageable dans des calculs de durées.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  9 juin 2010 à 14:31:59

                                  Merci pour les deux corrections (celle de lithrein, et celle de Candide)de l'exo zTransforme.
                                  Pour ma part le code de Candide est beaucoup plus comprehensible pour moi! j'ai vu mes erreurs....

                                  Pour l'exo du mois :
                                  1 : c'est calculatoire, ça m'a pas emballé
                                  pour les autres ce mois ci je vais me contenter de décortiquer les codes des participants et certainement ouvrir un autre post
                                  pour la compréhension "des pointeurs de fonction" pour eviter de polluer le topic pour les plus avancés :euh:
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    15 juin 2010 à 18:31:44


                                    «J'avoue avoir été très déçu par le manque de
                                    participants - débutants (un tout au plus).»

                                    zPointers - Correction



                                    Exercice 1 : Un problème de temps


                                    Citation : Énoncé

                                    Le temps suit une norme tel que :

                                    • 1 semaine représente 7 jours.
                                    • 1 jour représente 24 heures.
                                    • 1 heure représente 60 minutes.
                                    • 1 minute représente 60 secondes.



                                    Vous devez donc faire une fonction qui prend en paramètre un nombre de semaines, de jours, d'heures, de minutes et de secondes et les équilibrer selon la norme ci-dessus.

                                    void equilibrer_temps (long * semaines, long * jours, long * heures, long * minutes, long * secondes);
                                    


                                    L'exercice en soi n'était pas difficile - il fallait juste faire attention à la syntaxe des pointeurs , il suffisait simplement de faire des division euclidiennes et des additions dans un ordre précis.
                                    void
                                    equilibrer_temps (long * semaines, long * jours, long * heures, long * minutes, long * secondes) {
                                        *minutes += *secondes/60;
                                        *secondes %= 60;
                                        
                                        *heures += *minutes/60;
                                        *minutes %= 60;
                                        
                                        *jours += *heures/24;
                                        *heures %= 24;
                                        
                                        *semaines += *jours/7;
                                        *jours %= 7;
                                    }
                                    


                                    Exercice 2 : Quelques fonctions utiles



                                    Citation : Énoncé

                                    La bibliothèque standard du C fournie quelques fonctions utiles dans le fichier d'entête string.h. Je parle bien sûr de :

                                    • void *memcpy(void * restrict dest, const void * restrict src, size_t n);
                                    • void *memmove(void *dest, const void *src, size_t n);
                                    • void *memset(void *s, int c, size_t n);


                                    Encore une fois, la difficulté résidait dans la syntaxe liée aux pointeurs et à l'arithmétique de ces derniers.

                                    #include <stddef.h>
                                    
                                    void * /* Les zones mémoires à copier ne se chevauchent pas. */
                                    _memcpy (void * restrict dest, const void * restrict src, size_t n) {
                                        char * _dest = dest;
                                        const char * _src = src;
                                    
                                        while (n--)
                                            *_dest++ = *_src++;
                                    
                                        return dest;
                                    }
                                    
                                    void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                    _memmove (void * dest, const void * src, size_t n) {
                                        char *tmp = malloc(n);
                                        if (tmp == NULL) goto end;
                                    
                                        _memcpy(tmp, src, n);
                                        _memcpy(dest, tmp, n);
                                    
                                        free(tmp);
                                    
                                        end:
                                        return dest;
                                    }
                                    
                                    void *
                                    _memset (void * s, int c, size_t n) {
                                        char * _s = s;
                                        unsigned char _c = c;
                                    
                                        while (n--)
                                            *_s++ = _c;
                                        return s;
                                    }
                                    


                                    Par contre la fonction memmove ne devait pas être programmée de la façon suivante :
                                    void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                    _memmove (void * dest, const void * src, size_t n) {
                                        char * _dest = (char *)dest;
                                        const char * _src = (char *)src;
                                        
                                        if (src < dest)
                                            while (n--) {
                                                _dest = (char *)dest + n;
                                                _src = (char *)src + n;
                                    
                                                *--_dest = *--_src;
                                        }
                                        else
                                            while (n--)
                                                *_dest++ = *_src++;
                                    
                                        return dest;
                                    }
                                    

                                    Citation : n1124 : 6.5.8 §5

                                    When two pointers are compared, the result depends on the relative locations in the
                                    address space of the objects pointed to. If two pointers to object or incomplete types both
                                    point to the same object, or both point one past the last element of the same array object,
                                    they compare equal. If the objects pointed to are members of the same aggregate object,
                                    pointers to structure members declared later compare greater than pointers to members
                                    declared earlier in the structure, and pointers to array elements with larger subscript
                                    values compare greater than pointers to elements of the same array with lower subscript
                                    values. All pointers to members of the same union object compare equal. If the
                                    expression P points to an element of an array object and the expression Q points to the
                                    last element of the same array object, the pointer expression Q+1 compares greater than
                                    P. In all other cases, the behavior is undefined.


                                    Bien que l'on puisse utiliser le type (u)intptr_t pour palier à ce problème :
                                    void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                    _memmove (void * dest, const void * src, size_t n) {
                                        char * _dest = (char *)dest + n;
                                        const char * _src = (char *)src + n;
                                        
                                        if ((uintptr_t)src < (uintptr_t)dst)
                                            while (n--) {
                                                _dest = (char *)dest + n
                                                _src = (char *)src + n
                                    
                                                *--_dest = *--_src;
                                            }
                                        else
                                            while (n--)
                                                *_dest++ = *_src++;
                                    
                                        return dest;
                                    }
                                    

                                    Citation : n1124 : 7.18.1.4

                                    Integer types capable of holding object pointers
                                    1 The following type designates a signed integer type with the property that any valid
                                    pointer to void can be converted to this type, then converted back to pointer to void,
                                    and the result will compare equal to the original pointer:
                                    intptr_t
                                    The following type designates an unsigned integer type with the property that any valid
                                    pointer to void can be converted to this type, then converted back to pointer to void,
                                    and the result will compare equal to the original pointer:
                                    uintptr_t
                                    These types are optional.



                                    Exercice 3 : Bonus - Pointeurs de fonctions


                                    Citation : Énoncé

                                    Premièrement, j'interdit le mot clé typedef (car sinon c'est moins cool :-° ).
                                    Deuxièmement : Vous avez quatres fonctions :

                                    float addition(float a, float b) { return a + b ;}
                                    float soustraction(float a, float b) { return a - b ;}
                                    float multiplication(float a, float b) { return a * b ;}
                                    float division(float a, float b) { return a / b ;}
                                    



                                    Votre but est d'écrire une fonction : opCode (prototype à trouver) qui renvoie un pointeur sur une des quatre fonctions ci-dessus, en fonction de l'opérateur passé en paramètre.

                                    type_a_trouver ptr_fct = NULL;
                                    
                                    ptr_fct = opCode('+'); /* ptr_fct pointe sur la fonction addition */
                                    ptr_fct = opCode('-'); /* ptr_fct pointe sur la fonction soustraction */
                                    ptr_fct = opCode('*'); /* ptr_fct pointe sur la fonction multiplication */
                                    ptr_fct = opCode('/'); /* ptr_fct pointe sur la fonction division */
                                    



                                    Mais ce n'est pas tout. Maintenant que cela est fait vous devez créer une autre fonction (prototype à trouver grâce à l'exemple) qui applique la fonction pointée par ptr_fct à 'a' et 'b' deux nombres réels (float ) et qui renvoie le résultat de cette application.

                                    type_a_trouver ptr_fct = NULL;
                                    float a = 2., b = 3., c = 0.;
                                    
                                    ptr_fct = opCode('+'); /* ptr_fct pointe sur la fonction addition */
                                    c = appliquer_fonction(ptr_fct, a, b);
                                    


                                    Le type à trouver de ptr_func était : float (*)(float, float) , cela permettait de trouver le prototype de la fonction opCode : float (*opCode(unsigned int op))(float, float);

                                    La correction de la fonction opCode ne fonctionne qu'avec des jeux de caractères ASCII compatibles :
                                    float
                                    (*opCode(unsigned int op))(float, float) {
                                        if ('*' <= op && op <= '/' && op != '.' && op != ',') {
                                            float(*operation[4])(float, float) = 
                                            {
                                                &division, /* '/' -> 47 et 47 mod 4 = (47 mod 5) + 1 = 3 */
                                                &soustraction, /* '-' -> 45 et 45 mod 4 = 1 */
                                                &multiplication, /* '*' -> 42  et 42 mod 4 = 2*/
                                                &addition /* '+' -> 43 et 43 mod 4 = 3*/
                                            };
                                        
                                            if (op % 5 + 1 == 3)
                                                return operation[0];
                                    
                                            return operation[op%4];
                                        }
                                        
                                        return NULL;
                                    }
                                    


                                    Après cela, le plus dur est fait, il ne reste plus que la fonction appliquer_fonction qui est triviale.
                                    #include <stdlib.h>
                                    
                                    float addition (float a, float b) { return a + b; }
                                    float soustraction (float a, float b) { return a - b; }
                                    float multiplication (float a, float b) { return a * b; }
                                    float division (float a, float b) { return a / b; }
                                    
                                    float
                                    (*opCode(unsigned int op))(float, float) {
                                        if ('*' <= op && op <= '/' && op != '.' && op != ',') {
                                            float(*operation[4])(float, float) = 
                                            {
                                                &division, /* '/' -> 47 et 47 mod 4 = (47 mod 5) + 1 = 3 */
                                                &soustraction, /* '-' -> 45 et 45 mod 4 = 1 */
                                                &multiplication, /* '*' -> 42  et 42 mod 4 = 2*/
                                                &addition /* '+' -> 43 et 43 mod 4 = 3*/
                                            };
                                        
                                            if (op % 5 + 1 == 3)
                                                return operation[0];
                                    
                                            return operation[op%4];
                                        }
                                        
                                        return NULL;
                                    }
                                    
                                    float
                                    appliquer_fonction (float (*f)(float, float), float a, float b) {
                                        return f(a, b);
                                    }
                                    
                                    int
                                    main (void) {
                                        float (*ptr_fct)(float, float) = opCode('+');
                                        float a = 1.;
                                        float b = 2.;
                                        float c = appliquer_fonction(ptr_fct, a, b);
                                    
                                        return EXIT_SUCCESS;
                                    }
                                    
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      15 juin 2010 à 20:59:49

                                      Citation : Lithrein


                                      Encore une fois, la difficulté résidait dans la syntaxe liée aux pointeurs et à l'arithmétique de ces derniers.

                                      #include <stddef.h>
                                      
                                      
                                      void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                      _memmove (void * dest, const void * src, size_t n) {
                                          char *tmp = malloc(n * *tmp);
                                          if (tmp == NULL) goto end;
                                      
                                          _memcpy(tmp, src, n);
                                          _memcpy(dest, tmp, n);
                                      
                                          free(tmp);
                                      
                                          end:
                                          return dest;
                                      }
                                      




                                      Recoder une fonction de bibliothèque suppose en général qu'on utilise pas une autre fonction de bibliothèque. Ici, en plus tu utilises de l'allocation dynamique, or il est tout à fait légal (et possible) de ne pas en disposer.


                                      Citation : Lithrein


                                      void *
                                      _memset (void * s, int c, size_t n) {
                                          char * _s = s;
                                      
                                          while (n--)
                                              *_s++ = (unsigned char)c;
                                          return s;
                                      }
                                      




                                      Petit détail mais il est inutile de recaster toujours la même grandeur, autant la placer une bonne fois pour toutes quelque part.

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        15 juin 2010 à 21:15:52

                                        Citation : candide


                                        Recoder une fonction de bibliothèque suppose en général qu'on utilise pas une autre fonction de bibliothèque. Ici, en plus tu utilises de l'allocation dynamique, or il est tout à fait légal (et possible) de ne pas en disposer.



                                        En effet, j'avoue ne pas y avoir pensé. Ensuite, je propose tout de même deux autres implémentations de memmove (celle qui utilise uintptrt_t me semble la meilleure des trois pour du C90).
                                        Autrement :
                                        void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                        _memmove (void * dest, const void * src, size_t n) {
                                            char tmp[n];
                                        
                                            _memcpy(tmp, src, n);
                                            _memcpy(dest, tmp, n);
                                        
                                            return dest;
                                        }
                                        


                                        Citation : candide


                                        Petit détail mais il est inutile de recaster toujours la même grandeur, autant la placer une bonne fois pour toutes quelque part.



                                        Pas faux, je corrige.

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          15 juin 2010 à 22:20:52

                                          On trouve aussi une bonne banque d'exercices de C et d'algorithmique sur le site de de France IOI.
                                          http://www.france-ioi.org/train/prog/cours_c/
                                          Les exercices sont en bas de page.
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            17 juin 2010 à 16:42:26

                                            Merci pour la correction, j'ai quelques remarques/questions :

                                            void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                            _memmove (void * dest, const void * src, size_t n) {
                                                char * _dest = (char *)dest + n;
                                                const char * _src = (char *)src + n;
                                                
                                                if ((uintptr_t)dest < (uintptr_t)src)
                                                    while (n--)
                                                        *--_dest = *--_src;
                                                else
                                                    while (n--)
                                                        *_dest++ = *_src++;
                                            
                                                return dest;
                                            }
                                            
                                            Il me semble qu'il y a plusieurs erreurs.
                                            Tout d'abord
                                            if ((uintptr_t)dest < (uintptr_t)src) //c'est plutôt si dest > src
                                                    while (n--)
                                                        *--_dest = *--_src;
                                            

                                            else  //ici il ne faut pas avoir augmenter "dest + n"et " src
                                                    while (n--)
                                                        *_dest++ = *_src++; //du coup tu écris dans une zone non réservée
                                            

                                            void * /* Les zones mémoires à copier peuvent se chevaucher. */
                                            _memmove (void * dest, const void * src, size_t n) {
                                                char * _dest = (char *)dest;
                                                const char * _src = (char *)src;
                                            
                                                if ((uintptr_t)dest > (uintptr_t)src)
                                                {
                                                    _dest += n;
                                                    _src += n;
                                                    while (n--)
                                                        *--_dest = *--_src;
                                                }
                                                else
                                                {
                                                    while (n--)
                                                        *_dest++ = *_src++;
                                                }
                                            
                                                return dest;
                                            }
                                            




                                            char *tmp = malloc(n * *tmp);
                                            
                                            Tu as oublié le sizeof.
                                            if (tmp == NULL) goto end;
                                            
                                            Pourquoi pas un simple return?
                                            char * _dest = (char *)dest + n;
                                                const char * _src = (char *)src + n;
                                            
                                            Je me demande à quoi peuvent bien servir les cast?
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              17 juin 2010 à 17:01:27

                                              Merci pour tes remarques sur les erreurs sur la fonction _memmove (en même temps j'aurais du tester :honte: )

                                              Autrement pour le sizeof c'est en effet un oubli. Ensuite, le goto peut en effet être remplacé par un return, mais bon ça ne change pas grand chose.
                                              Par contre les casts sont obligatoires, car on ne peut pas faire de l'arithmétique sur des pointeurs sur void.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                17 juin 2010 à 17:21:51

                                                Citation : Lithrein

                                                Par contre les casts sont obligatoires, car on ne peut pas faire de l'arithmétique sur des pointeurs sur void.

                                                Oui c'est ce que je me suis dis aussi, mais vu que je n'avais pas de warning...

                                                D'ailleurs j'ai le même résultat avec ou sans cast, c'est pour ça que je me demandais si c'était vraiment quelque chose qui n'était définis.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                  18 juin 2010 à 4:20:36

                                                  Le type void est un type incomplet, sa taille n'est pas connue, donc on ne peux normalement pas faire pas d'arithmétique de pointeur avec.

                                                  Avec VC++ express 2008, une tentative donne
                                                  error C2036: 'void *' : taille inconnue

                                                  GCC donne une taille de 1 à ce type mais c'est discutable(et très discuté).
                                                  Il faut utiliser l'option pedantic pour avoir un warning de la part de GCC
                                                  warning: wrong type argument to increment|


                                                  le même code avec VC++ express 2008
                                                  #include <stdio.h>
                                                  
                                                  int main(void)
                                                  {
                                                  	printf("%lu\n", (unsigned long)sizeof(void));
                                                  
                                                  	return 0;
                                                  }
                                                  
                                                  0
                                                  Appuyez sur une touche pour continuer...

                                                  et GCC
                                                  1
                                                  
                                                  Process returned 0 (0x0)   execution time : 0.297 s
                                                  Press any key to continue.

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                  Zeste de Savoir, le site qui en a dans le citron !
                                                    18 juin 2010 à 12:51:06

                                                    GurneyH -> Ok, merci pour les précisions :) .
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      19 juin 2010 à 18:49:58

                                                      zChance - Du 19 juin au 15 juillet



                                                      Enoncé de base :



                                                      C'est bien connu : le vendredi 13 à 13:13:13 on a une chance incroyable (ou pas :-° ).

                                                      Je vous propose donc de réaliser une fonction qui renvoie la date du prochain Vendredi 13 puis qui l'affiche en Français.

                                                      Code source à compléter :
                                                      #include <stdio.h>
                                                      #include <stdlib.h>
                                                      #include <time.h>
                                                      
                                                      time_t
                                                      vendredi_13 (void) {
                                                          /* Votre code ici */
                                                      }
                                                      
                                                      int
                                                      main (void) {
                                                          
                                                          time_t vendredi = vendredi_13();
                                                          struct tm date = *localtime(&vendredi);
                                                          char const * const jours[] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};
                                                          char const * const mois[] = {"Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"};
                                                          
                                                          printf("%s %d %s %d\n", jours[date.tm_wday], date.tm_mday, mois[date.tm_mon], 1900+date.tm_year);
                                                          
                                                          return EXIT_SUCCESS;
                                                      }
                                                      


                                                      $ ./a.out
                                                      Vendredi 13 Aout 2010


                                                      Le sujet crée pour cet exercice se trouve ici.
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        19 juin 2010 à 19:10:31

                                                        J'ai pas vraiment compris l'énoncé...en plus je connaissais pas du tout struct tm et localtime(&vendredi);

                                                        Je trouve que tu pourrais expliquer un peu mieux, j'ai du mal là (et d'autres aussi peut-être).
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                          19 juin 2010 à 19:18:45

                                                          J'ai retouché l'énoncé le trouvez vous plus clair ou non ?
                                                          Si non, dites moi ce que vous ne comprenez pas et je tenterais d'éclaircir.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            19 juin 2010 à 19:33:42

                                                            Citation : Lithrein

                                                            vous devrez afficher cette date en français.


                                                            Dommage. :-°

                                                            #include <stdio.h>
                                                            #include <stdlib.h>
                                                            #include <time.h>
                                                            
                                                            int main (void) {
                                                              char s[50] = "";
                                                              time_t vendredi = time(NULL);
                                                              struct tm * date = localtime(&vendredi);
                                                              strftime(s, 50, "%A %B %e %Y", date);
                                                              puts(s);
                                                              return EXIT_SUCCESS;
                                                            }
                                                            

                                                            Saturday June 19 2010
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter

                                                            Exercices pour débutants en C (suite)

                                                            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                            • Editeur
                                                            • Markdown