L'approche en deux passes me semblait plus simple à mettre en oeuvre dans un premier temps (dans la mesure où c'est possible).Citation:
Envoyé par Médinoc
Thierry
Version imprimable
L'approche en deux passes me semblait plus simple à mettre en oeuvre dans un premier temps (dans la mesure où c'est possible).Citation:
Envoyé par Médinoc
Thierry
:) Oui jusqu'à là ça va.. je pense, à la lecture j'ai compris. Merci !!Citation:
Envoyé par mujigka
:king:
Mais comment faire pour passer :
en paramètre dans une fonction ?Code:
1
2 char (*p_date)[50]=NULL;
Nous allons donc mettre tout cela en fonctions avec:
- une fonction de création du tableau (constructeur)
- une fonction de destruction du tableau (destructeur: en principe un free suffit, mais bon!)
- une fonction permettant d'afficher le contenu du tableau
Fonction d'affichage du tableau:
La principale difficulté de cette fonction réside au niveau du propotype. Comment déclarer une fonction qui retourne un pointeur sur 50 caractères. C'est je l'avoue un peu complexe:
une fonction qui retourne un caractère s'écrit:
Maintenant, une fonction qui retourne un pointeur sur un caractère s'écrit:Code:char fonction(void);
Jusque là, c'est facile. Maintenant, une fonction qui retourne un pointeur sur un tableau de caractère s'écrit:Code:char *fonction(void);
Nous voulons un fonction qui retroune un pointeur sur un tableau de caractères, et qui prend en paramètre le nombre d'éléments que doit contenir le tableau, c'est à dire le nombre de chaines de caractères contenues dans ton fichier. On a donc:Code:char ( *fonction() )[50];
Le plus difficile est fait. Nous avons plus qu'à encapsuler le code responsable de l'allocation mémoire et de l'initialisation dans la fonction. Il vient:Code:char ( *fonction(int nombre_chaines) )[50];
Code:
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 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 50 /* Longueur maximale de tes chaines de caractères */ /** * Crée un tableau de n_chaines chaines de MAXLEN caractères */ char (*tableau_creer(int n_chaines))[MAXLEN] { char (*p_tableau)[MAXLEN] = NULL; if (n_chaines > 0) { p_tableau = malloc(n_chaines * sizeof *p_tableau); if (p_tableau != NULL) { /* Toutes les cases du tableau sont initialisées à 0 */ memset(p_tableau, 0, n_chaines * sizeof *p_tableau); } } return p_tableau; }
Fonction permettant d'afficher le contenu du tableau:
La valeur du pointeur n'étant pas modifiée au sein de cette fonction, on
peut se contenter du prototype suivant:
Ce qui nous donne en vrai:Code:void fonction(char (*tableau)[50], int nombre_chaines);
Je ne pense pas qu'il y ait de problème particulier avec cette fonction, mais n'hésite pas à poser des questions si c'est le cas.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 /** * Affiche un tableau de n_chaines chaines de MAXLEN caractères */ void tableau_afficher(char (*p_tab)[MAXLEN], int n_chaines) { if (p_tab != NULL && n_chaines > 0) { int i; for (i = 0; i < n_chaines; ++i) { if (p_tab[i][0] == '\0') { puts("(chaine vide)"); } else { puts(p_tab[i]); } } } }
Fonction de destruction du tableau:
Pour terminer, regardons la fonction de destruction. En principe, un appel à free() nous suffit pour libérer la mémoire allouée pour le tableau. Voici le comportement de notre fonction de destruction. Nous voulons que cette fonction libère l'espace alloué au tableau, ET qu'elle ré-initialise la valeur du pointeur passé en argument à NULL. Comme le passage d'un argument à fonction se fait par copie en C, nous devons utiliser un niveau d'indirection suuplémentaire. Exemple:
Cette fonction n'est pas capable de modifier la valeur de nombre à cause du passage par copie.Code:
1
2
3
4
5
6
7
8 void fonction(int a) { a = 10; } /* ... */ int nombre = 0; fonction(nombre); printf("%d\n", nombre); /* Ici, nombre vaut 0 */
En utilisant un niveau d'indirection supplémentaire, on parvient à modifier la valeur de nombre à l'intérieur de la fonction. Et bien, c'est la même chose avec notre pointeur sur chaine de caractère:Code:
1
2
3
4
5
6
7
8 void fonction(int *a) { *a = 10; } /* ... */ int nombre = 0; fonction(nombre); printf("%d\n", nombre); /* Ici, nombre vaut 10 */
Voici donc notre fonction destructeur:Code:
1
2
3
4
5
6
7
8
9 void fonction(char (**pp_tab)[50]) { *pp_tab = NULL; } /* ... */ char un_tableau[50] = "Bienvenue sur developpez!"; char (*notre_pointeur)[50] = &un_tableau; fonction(¬re_pointeur); printf("%p\n", (void *) notre_pointeur); /* Ici, notre_pointeur vaut NULL */
Voilà, nous donc vu toutes les manières de passer notre pointeur sur MAXLEN (vaut 50 dans ton cas) caractères en argument d'une fonction, et pour récupérer sa valeur en retour d'une fonction (voir tableau_creer()). Voici un récapitulatif du code complet:Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 /** * détruit un tableau de chaines de MAXLEN caractères */ void tableau_detruire(char (**pp_tab)[MAXLEN]) { if (pp_tab != NULL && *pp_tab != NULL) { char (*p_tableau)[MAXLEN] = *pp_tab; free(p_tableau); /* Il faut un niveau d'indirection supplémentaire pour ré-initialiser le pointeur pointé par pp_tab à NULL */ *pp_tab = NULL; } }
Si tu ne comprends pas, n'hésite pas à poser des questions. Maintenant, il te reste à déterminer combien de chaines sont contenues dans ton fichier, puis à réaliser des saisies sécurisées (c'est relativement facile, comme tu es sûr qu'aucune chaine ne sera plus longue que 50 caractères). A toi de jouer... poste ton code...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 50 /** * Crée un tableau de n_chaines chaines de MAXLEN caractères */ char (*tableau_creer(int n_chaines))[MAXLEN] { char (*p_tableau)[MAXLEN] = NULL; if (n_chaines > 0) { p_tableau = malloc(n_chaines * sizeof *p_tableau); if (p_tableau != NULL) { /* Toutes les cases du tableau sont initialisées à 0 */ memset(p_tableau, 0, n_chaines * sizeof *p_tableau); } } return p_tableau; } /** * détruit un tableau de chaines de MAXLEN caractères */ void tableau_detruire(char (**pp_tab)[MAXLEN]) { if (pp_tab != NULL && *pp_tab != NULL) { char (*p_tableau)[MAXLEN] = *pp_tab; free(p_tableau); /* Il faut un niveau d'indirection supplémentaire pour ré-initialiser le pointeur pointé par pp_tab à NULL */ *pp_tab = NULL; } } /** * Affiche un tableau de n_chaines chaines de MAXLEN caractères */ void tableau_afficher(char (*p_tab)[MAXLEN], int n_chaines) { if (p_tab != NULL && n_chaines > 0) { int i; for (i = 0; i < n_chaines; ++i) { if (p_tab[i][0] == '\0') { puts("(chaine vide)"); } else { puts(p_tab[i]); } } } } int main(void) { int err = EXIT_SUCCESS; int n_chaines = 3; char (*p_mon_tableau)[MAXLEN] = NULL; /* On crée le tableau */ p_mon_tableau = tableau_creer(n_chaines); if (p_mon_tableau != NULL) /* Si pas d'erreur d'allocation mémoire */ { /* On affiche le tableau */ tableau_afficher(p_mon_tableau, n_chaines); /* Et lorsqu'on a plus besoin du tableau, on libère la mémoire */ tableau_detruire(&p_mon_tableau); } else { fprintf(stderr, "Erreur d'allocation!\n"); err = EXIT_FAILURE; } return err; }
Thierry
Merci, à la première lecture je n'ai pas encore tout cerné mais ce n'est pas du chinois ! C'est déjà ça! :D Il faudra aussi que je digère la fonction suivie par [50] ... étonnant !:P Je n'aurais pas pu le trouver toute seule.
Je vais relire tout demain, et je vais également essayer d'intégrer tout cela à mon code. C'est en faisant qu'on apprend non ?
J'ai déjà écrit la partie du code qui définit le nombre de chaîne, et ça a l'air de fonctionner.
Je posterai également mon code plus tard.
Encore merci ! :D
J'admets que c'est une notation barbare. Il est possible de faire autrement. A lire que lorsque tu auras compris le reste de mon exemple, sous peine de t'embrouiller avec 15 méthodes différentes.Citation:
Envoyé par acryline
Tu peux te simplifier la vie par exemple en retournant simplement une adresse générique au lieu d'un pointeur sur tableau de caractères (ATTENTION: cette méthode présente des dangers):
Là, il n'y aucune modification au niveau de l'utilisation de la fonction, si ce n'est qu'il faut faire TRES attention à affecter la valeur retournée à un pointeur du bon type (personnellement, je déconseille cette façon de faire).Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 /** * Crée un tableau de n_chaines chaines de MAXLEN caractères */ void *tableau_creer(int n_chaines) { char (*p_tableau)[MAXLEN] = NULL; if (n_chaines > 0) { p_tableau = malloc(n_chaines * sizeof *p_tableau); if (p_tableau != NULL) { /* Toutes les cases du tableau sont initialisées à 0 */ memset(p_tableau, 0, n_chaines * sizeof *p_tableau); } } return (void *) p_tableau; }
Tu peux également faire comme avec la fonction tableau_detruire(), et retourner le tableau alloué, via les paramètre de la fonction. Cela te permet d'utiliser la valeur de retour de la fonction pour retourner des codes d'erreur bienvenus. Voici un exemple remanié de la fonction tableau_creer():
Bonne lectureCode:
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 /* Constantes utilisées pour les codes d'erreurs retournés par la fonction */ typedef enum Tableau_err_ { TABLEAU_OK, TABLEAU_ERR_TAILLE, TABLEAU_ERR_NULL_ARG, TABLEAU_ERR_MEMOIRE, TABLEAU_ERR_INCONNU } Tableau_err_e; /** * Crée un tableau de n_chaines chaines de MAXLEN caractères */ Tableau_err_e tableau_creer(char (**pp_tab)[MAXLEN], int n_chaines) { Tableau_err_e err = TABLEAU_OK; if (pp_tab != NULL) { if (n_chaines > 0) { char (*p_tableau)[MAXLEN] = *pp_tab; p_tableau = malloc(n_chaines * sizeof *p_tableau); if (p_tableau != NULL) { /* Toutes les cases du tableau sont initialisées à 0 */ memset(p_tableau, 0, n_chaines * sizeof *p_tableau); } else { err = TABLEAU_ERR_MEMOIRE; } *pp_tab = p_tableau; } else { err = TABLEAU_ERR_TAILLE; } } else { err = TABLEAU_ERR_NULL_ARG; } return err; }
Thierry
Voilà enfin j'y suis arrivée avec ton aide ! Encore merci.
Voici une partie de mon code (mais j'ai bcp pompé ton code --> Je l'ai intégré ;) ) Autrement tout n'est pas encore terminé, comme les message d'erreur par exemple. Je compte aussi retourner un code d'erreur pour chaque fonction. A noter que je travaille avec la bibliothèque GTK+:
Fonction pour afficher les chaînes
Trouver le nombre de chaînes dans le fichierCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 void afficherDate (GADGET *p_gadget) { gchar (*p_mon_tableau)[MAXLEN] = NULL; glong enreg =0,i=0; //Charger le nombre d'entrées pour la question nombreEnregistrement (p_gadget,&enreg); // On crée le tableau p_mon_tableau = tableau_creer(enreg); // Afficher toutes les dates dans la fenêtre bilan chargerAfficherDates (&p_mon_tableau, enreg); // Et lorsqu'on a plus besoin du tableau, on libère la mémoire tableau_detruire(&p_mon_tableau); }
La fonction de mujigka pour créer le tableauCode:
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 void nombreEnregistrement(GADGET *p_gadget,glong *enreg) { FILE* fichier = NULL; glong i=0 ; gchar enregistrement[TAILLE_TEXTE]={0}; //lire jusqu'à la question -1(4 lignes à chaque fois) fichier = fopen("question.qt", "r+"); if (fichier != NULL) { for(i=0;i<p_gadget->question-1;i++) { fgets(enregistrement,TAILLE_TEXTE,fichier); fgets(enregistrement,TAILLE_TEXTE,fichier); fgets(enregistrement,TAILLE_TEXTE,fichier); fgets(enregistrement,TAILLE_TEXTE,fichier); } fgets(enregistrement,TAILLE_TEXTE,fichier); fgets(enregistrement,TAILLE_TEXTE,fichier); //convertir la chaîne enregistrement en nombre *enreg = strtol(enregistrement,NULL,10); fclose(fichier); } else { //message pour dire qu'il n'y a pas de fichier } }
Fonction de mujigka pour détruire le tableauCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 gchar (*tableau_creer(int n_chaines))[MAXLEN] { char (*p_tableau)[MAXLEN] = NULL; if (n_chaines > 0) { p_tableau = malloc(n_chaines * sizeof *p_tableau); if (p_tableau != NULL) { // Toutes les cases du tableau sont initialisées à 0 memset(p_tableau, 0, n_chaines * sizeof *p_tableau); } } return p_tableau; }
Affichage des chaîne de caractères, pour l'instant seulement dans la console.Code:
1
2
3
4
5
6
7
8
9
10
11
12 void tableau_detruire(gchar (**pp_tab)[MAXLEN]) { if (pp_tab != NULL && *pp_tab != NULL) { gchar (*p_tableau)[MAXLEN] = *pp_tab; free(p_tableau); // Il faut un niveau d'indirection supplémentaire pour // ré-initialiser le pointeur pointé par pp_tab à NULL *pp_tab = NULL; } }
Code:
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 void chargerAfficherDates (gchar (**pp_tab)[MAXLEN], glong enreg) { FILE* fichier = NULL; glong i=0; if (pp_tab != NULL && pp_tab!=NULL && enreg !=0) { gchar (*p_tableau)[MAXLEN] = *pp_tab; fichier = fopen("reponses.txt", "r+"); if (fichier != NULL) { for(i=0;i<enreg;i++) { fgets(p_tableau[i],MAXLEN,fichier); printf("%s",p_tableau[i]); } fclose(fichier); } else { printf("erreur"); } } else { //message d'erreur } }