Bonsoir,
Comme indiqué dans le titre, je souhaite implémenter en C des tableaux de taille variable. Ils fonctionneraient de cette manière : on déclare une variable de type Liste (qui n'est pas vraiment une liste chaînée mais je n'avais pas d'autre nom), qui est en réalité une structure contenant : la taille du tableau (int) et les données (char *).
On l'initialise via la fonction init, qui se contente de mettre la taille à 0 et d'allouer une case de mémoire de la taille d'un char.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 typedef struct{ int longueur; //La taille de la liste char *valeur; //Les données dans la liste }Liste;
Ensuite, je souhaite modifier la chaîne de caractères via une fonction qui en appelle deux autres :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 void init(Liste *l) { l->longueur = 0; //On met la taille (= nombre de caractères) à 0 l->valeur = calloc(1, sizeof(char)); //On utilise calloc pour allouer dynamiquement et mettre à 0 if (l->valeur == NULL) exit(EXIT_FAILURE); //En cas d'erreur, on quitte le programme }
Voici l'implémentation de la fonction changerValeur :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 void scanListe(Liste *l) { char c[2] = {0}; //Chaine qui servira a stocker ce qui est entré par l'utilisateur changerValeur(l, ""); //On vide la chaine (voir après) while(c[0] != '\n') { c[0] = getchar(); //On récupère le dernier caractère if(c[0] != '\n') //Si ce n'est pas un retour à la ligne concatener(l, c); //On met à la fin de la chaine } }
Et enfin la fonction concatener
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 void changerValeur(Liste *l, char* str) { realloc(l->valeur, (strlen(str) + 1) * sizeof(char)); /*On réalloue le tableau avec la taille de la nouvelle chaine. Pas besoin de réallouer à la fin puisque on veut écraser l'ancienne valeur de la chaine */ if (l->valeur == NULL) exit(EXIT_FAILURE); //On quitte en cas d'erreur strcpy(l->valeur, str); //Enfin on copie la nouvelle chaine dans l'ancienne... l->longueur = strlen(str); //... et on met à jour la taille du tableau }
J'ai en plus fait une fonction qui renvoie seulement la chaine de caractère contenue dans une structure Liste :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 void concatener(Liste *l, char* str) { realloc(l->valeur, (l->longueur + (strlen(str) + 1)) * sizeof(char)); /*On réalloue, mais cette fois avec la taille initiale en plus*/ if (l->valeur + l->longueur + 1 == NULL) exit(EXIT_FAILURE); //On quitte en cas d'erreur strcpy((l->valeur + l->longueur), str); //On copie la chaine à partir de la fin l->longueur += strlen(str); //Et on met à jour la taille de la chaine }
Enfin, voici ma fonction qui libère la mémoire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 char* chaine(Liste *l) { return l->valeur; }
La totalité du code est donc :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 void liberer(Liste *l) { free(l->valeur); l->valeur = NULL; }
Ce programme est une boucle qui permet de changer la valeur de Chaine jusqu'a ce qu'on entre "exit", auquel cas l'application se ferme.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 #include <stdio.h> #include <stdlib.h> typedef struct{ int longueur; //La taille de la liste char *valeur; //Les données dans la liste }Liste; void init(Liste *l); void changerValeur(Liste *l, char* str); void concatener(Liste *l, char* str); char* chaine(Liste *l); void liberer(Liste *l); void scanListe(Liste *l); int main() { Liste Chaine; init(&Chaine); while(strcmp(chaine(&Chaine),"exit") != 0) { printf("La liste chainee vaut \"%s\".\nModifiez sa valeur : ", chaine(&Chaine)); scanListe(&Chaine); } liberer(&Chaine); return 0; } void init(Liste *l) { l->longueur = 0; //On met la taille (= nombre de caractères) à 0 l->valeur = malloc(sizeof(char)); //On utilise calloc pour allouer dynamiquement et mettre à 0 *(l->valeur) = '\0'; if (l->valeur == NULL) exit(EXIT_FAILURE); //En cas d'erreur, on quitte le programme } void scanListe(Liste *l) { char c[2] = {0}; //Chaine qui servira a stocker ce qui est entré par l'utilisateur changerValeur(l, ""); //On vide la chaine (voir après) while(c[0] != '\n') { c[0] = getchar(); //On récupère le dernier caractère if(c[0] != '\n') //Si ce n'est pas un retour à la ligne concatener(l, c); //On met à la fin de la chaine } } void changerValeur(Liste *l, char* str) { realloc(l->valeur, (strlen(str) + 1) * sizeof(char)); /*On réalloue le tableau avec la taille de la nouvelle chaine. Pas besoin de réallouer à la fin puisque on veut écraser l'ancienne valeur de la chaine */ if (l->valeur == NULL) exit(EXIT_FAILURE); //On quitte en cas d'erreur strcpy(l->valeur, str); //Enfin on copie la nouvelle chaine dans l'ancienne... l->longueur = strlen(str); //... et on met à jour la taille du tableau } void concatener(Liste *l, char* str) { realloc(l->valeur, (l->longueur + (strlen(str) + 1)) * sizeof(char)); /*On réalloue, mais cette fois avec la taille initiale en plus*/ if (l->valeur + l->longueur + 1 == NULL) exit(EXIT_FAILURE); //On quitte en cas d'erreur strcpy((l->valeur + l->longueur), str); //On copie la chaine à partir de la fin l->longueur += strlen(str); //Et on met à jour la taille de la chaine } void liberer(Liste *l) { free(l->valeur); l->valeur = NULL; } char* chaine(Liste *l) { return l->valeur; }
Il réside plusieurs bugs lors de l'éxecution de ce programme que je ne parviens pas à résoudre :
- Une et une seule fois, lorsque ce que je rentre dépasse les 7 caractères, l'affichage me sors une chose du type "h>ù" (3 caractères spéciaux généralement)
- Lorsque la liste est de longue taille (plus de deux lignes environ), le programme plante (SEGMENTATION FAULT) lors de la fermeture, pas avant, et ce même si je remodifie la chaîne en quelque chose de plus court.
- Le problème précédant est observé après le return 0; lorsque j'utilise le debugger de Code::Blocks. Je suppose donc que c'est que la chaîne a mal été libérée de la mémoire, mais la fonction free() ne renvoyant rien, je ne peux pas tester son succès avec la valeur de retour.
J'ai bien sûr plusieurs fois vérifié et modifié mon code mais sans succès et sans même trouver d'où peuvent venir ces problèmes, surtout que lorsqu'il est dans la boucle principale, ce code semble fonctionner (hormis le 1er bug qui n’apparaît qu'une fois lors de l’exécution).
Je remercie par avance toute aide et j'espère que vous ferez preuve d'indulgence, je ne suis pas encore très expérimenté.
Partager