[C] soucis, char*, tableau, pointeur :)
Résolu
Isabelle
-
Isabelle -
Isabelle -
Bonjour,
J'ai un soucis avec le code se trouvant ci-dessous.
En particulier avec la fonction gestionEtiquettes.
Je passe un tableau de char* en paramètre, ainsi que d'autres char*
à un moment je souhaite mettre la valeur de etiq dans la case en cours du tableau
or, ce que je fais c'est que je fais pointer la case de mon tableau à la même case que le char*
ce qui ne m'arrange pas à dire vrai vu que je veux réutiliser mon tableau et ses nouvelles valeurs hors de ma fonction. Comment faire ?
voilà comment j'appelle ma fonction ainsi que les variables déclarées :
Tokensize correspond à 79 et est déclaré ailleurs
voici maintenant le code de ma fonction :
merci d'avance (j'ai eu beau chercher sur google je n'ai rien trouvé :( ou pas compris ce qui m'était proposé)
J'ai un soucis avec le code se trouvant ci-dessous.
En particulier avec la fonction gestionEtiquettes.
Je passe un tableau de char* en paramètre, ainsi que d'autres char*
à un moment je souhaite mettre la valeur de etiq dans la case en cours du tableau
or, ce que je fais c'est que je fais pointer la case de mon tableau à la même case que le char*
ce qui ne m'arrange pas à dire vrai vu que je veux réutiliser mon tableau et ses nouvelles valeurs hors de ma fonction. Comment faire ?
voilà comment j'appelle ma fonction ainsi que les variables déclarées :
char* etiquettes[512] ; char ligne[TOKENSIZE], op[TOKENSIZE], etiq[TOKENSIZE], ri[TOKENSIZE], rj[TOKENSIZE], rk[TOKENSIZE], nc[TOKENSIZE]; int tailleProg ; gestionEtiquettes(etiquettes, op, ri, rj, rk, nc, &tailleProg, ligne, etiq) ;
Tokensize correspond à 79 et est déclaré ailleurs
voici maintenant le code de ma fonction :
/* Compilation: + compiler poly_parser.c: gcc -c poly_parser.c + compiler assembleur.c: gcc -std=c99 -o assembleur assembleur.c poly_parser.o */ #include <stdio.h> // pour manier les fichiers #include <string.h> // pour manier les chaines de caractères #include "poly_parser.h" // pour utiliser la fonction poly parser void gestionEtiquettes(char* etiquettes[],char* op,char* ri, char* rj, char* rk, char* nc, int *tailleProg, char* ligne, char* etiq) { int cpt = 0 ; FILE* fic = fopen("essai.asm","r"); while(fgets(ligne,79,fic) != NULL) { if (poly_parsing(ligne,etiq,op,ri,rj,rk,nc)) { etiquettes[cpt] = etiq ; printf("nia etiquette : %s \n",etiquettes[cpt]) ; } cpt ++ ; } *tailleProg = cpt ; fclose(fic) ; } // Je fournirais la suite du code si besoin
merci d'avance (j'ai eu beau chercher sur google je n'ai rien trouvé :( ou pas compris ce qui m'était proposé)
A voir également:
- [C] soucis, char*, tableau, pointeur :)
- Tableau word - Guide
- Tableau ascii - Guide
- Trier un tableau excel - Guide
- Tableau croisé dynamique - Guide
- Imprimer tableau excel sur une page - Guide
6 réponses
Bonjour,
Je ne sais pas trop si ça va faire ce que tu veux et peut être que tu y a déjà pensé mais :
Si tu crée une variable temporaire dans la fonction, tu lui passerai son adresse est pas l'adresse etiq ?
char* etiq_temp;
etiq_temp=(char*)calloc(strlen(etiq),sizeof(char));
strcpy(etiq_temp,etiq);
while(fgets(ligne,79,fic) != NULL)
{
if (poly_parsing(ligne,etiq,op,ri,rj,rk,nc))
{
etiquettes[cpt] = etiq_temp ;
printf("nia etiquette : %s \n",etiquettes[cpt]) ;
}
cpt ++ ;
}
/*enlève le free si sa bug à la compilation*/
free(etiq_temp);
je sais pas si ça résoudra ton problème ...
Je ne sais pas trop si ça va faire ce que tu veux et peut être que tu y a déjà pensé mais :
Si tu crée une variable temporaire dans la fonction, tu lui passerai son adresse est pas l'adresse etiq ?
char* etiq_temp;
etiq_temp=(char*)calloc(strlen(etiq),sizeof(char));
strcpy(etiq_temp,etiq);
while(fgets(ligne,79,fic) != NULL)
{
if (poly_parsing(ligne,etiq,op,ri,rj,rk,nc))
{
etiquettes[cpt] = etiq_temp ;
printf("nia etiquette : %s \n",etiquettes[cpt]) ;
}
cpt ++ ;
}
/*enlève le free si sa bug à la compilation*/
free(etiq_temp);
je sais pas si ça résoudra ton problème ...
Salut,
etiquettes[cpt] = etiq ;
Comme tu le dis si bien, cela ne copie pas le tableau mais l'adresse du pointeur. Donc cela dépend fortement d'etiq.
Ce qu'il faut faire c'est recopier une à une les valeurs, et pour cela tu as la fonction strncpy à ta disposition.
Par contre, il ne faudra pas oublier de réaliser l'allocation dynamique d'etiquettes[cpt].
Cdlt,
etiquettes[cpt] = etiq ;
Comme tu le dis si bien, cela ne copie pas le tableau mais l'adresse du pointeur. Donc cela dépend fortement d'etiq.
Ce qu'il faut faire c'est recopier une à une les valeurs, et pour cela tu as la fonction strncpy à ta disposition.
Par contre, il ne faudra pas oublier de réaliser l'allocation dynamique d'etiquettes[cpt].
Cdlt,
Merci beaucoup à vous deux =)
j'ai donc changé ma fonction et cela donne :
ça marche parfaitement du coup
par contre je me demandais si c'était possible de m'expliquer plus en détail en terme pointeur/valeur ce que signifient ces deux lignes :
Je me le demande parce que j'ai du mal à comprendre comment elles marchent, n'étant pas encore très douée en C. merci d'avance pour votre réponse et merci encore pour celles que vous m'avez déjà apportée.
j'ai donc changé ma fonction et cela donne :
void gestionEtiquettes(char* etiquettes[],char* op,char* ri, char* rj, char* rk, char* nc, int *tailleProg, char* ligne, char* etiq) { int cpt = 0 ; FILE* fic = fopen("essai.asm","r"); while(fgets(ligne,79,fic) != NULL) { if (poly_parsing(ligne,etiq,op,ri,rj,rk,nc)) { etiquettes[cpt] = (char*)calloc(strlen(etiq),sizeof(char)) ; strcpy(etiquettes[cpt],etiq); } cpt ++ ; } *tailleProg = cpt ; fclose(fic) ; }
ça marche parfaitement du coup
par contre je me demandais si c'était possible de m'expliquer plus en détail en terme pointeur/valeur ce que signifient ces deux lignes :
etiquettes[cpt] = (char*)calloc(strlen(etiq),sizeof(char)) ; strcpy(etiquettes[cpt],etiq);
Je me le demande parce que j'ai du mal à comprendre comment elles marchent, n'étant pas encore très douée en C. merci d'avance pour votre réponse et merci encore pour celles que vous m'avez déjà apportée.
etiquettes[cpt] = (char*)calloc(strlen(etiq),sizeof(char)) ;
Cela signifie que tu alloues une zone dans le heap et que tu rattaches l'adresse à etiquette[cpt].
Cependant pour plus de performance, tu peux utiliser malloc tout simplement :
etiquettes[cpt]=malloc(strlen(etiq)+1);
Le +1 est important pour stocker le \0, tu l'as d'ailleurs oublier dans le calloc, il faut également le mettre.
De plus, tu n'es pas obligé de caster calloc ou malloc en char*.
strcpy(etiquettes[cpt],etiq);
Cela signifie string copy. En gros tu copies tous les caractères de etiq dans etiquettes[cpt] jusqu'au \0 final.
Le problème est que si la chaîne etiq est plus grande qu'etiquettes[cpt], cela causera un bug à ton programme. Tu n'auras pas ce problème ici puisque tu alloues la bonne taille avec ton allocation. Mais je te recommande de ne plus utiliser strcpy, mais strncpy qui donne une taille maximale à recopier.
De plus, n'oublie pas de toujours vérifier la valeur de retour du malloc (si différent de NULL), cela t'évitera bien des surprises.
Et enfin, qui dit allocation (malloc ou calloc, ou realloc) dit désallocation. Et il faudra donc mettre à un moment un free.
Cdlt,
Cela signifie que tu alloues une zone dans le heap et que tu rattaches l'adresse à etiquette[cpt].
Cependant pour plus de performance, tu peux utiliser malloc tout simplement :
etiquettes[cpt]=malloc(strlen(etiq)+1);
Le +1 est important pour stocker le \0, tu l'as d'ailleurs oublier dans le calloc, il faut également le mettre.
De plus, tu n'es pas obligé de caster calloc ou malloc en char*.
strcpy(etiquettes[cpt],etiq);
Cela signifie string copy. En gros tu copies tous les caractères de etiq dans etiquettes[cpt] jusqu'au \0 final.
Le problème est que si la chaîne etiq est plus grande qu'etiquettes[cpt], cela causera un bug à ton programme. Tu n'auras pas ce problème ici puisque tu alloues la bonne taille avec ton allocation. Mais je te recommande de ne plus utiliser strcpy, mais strncpy qui donne une taille maximale à recopier.
De plus, n'oublie pas de toujours vérifier la valeur de retour du malloc (si différent de NULL), cela t'évitera bien des surprises.
Et enfin, qui dit allocation (malloc ou calloc, ou realloc) dit désallocation. Et il faudra donc mettre à un moment un free.
Cdlt,
merci pour ces nouvelles précisions :
voici la dernière version de mon code :
Si j'ai bien compris, à chaque tour de boucle j'alloue de la mémoire (se trouvant dans la pile ?) à ma case de tableau, puis je copie ma chaine à cet endroit grâce à la fonction strncpy, puis je désalloue cette mémoire.
Je me demande juste quelle mauvaise surprise peut-on avoir si on ne teste pas si le résultat du malloc est NULL (cela voudrait dire qu'on ne pourrait pas lui allouer de mémoire ?)
merci encore pour ces réponses.
voici la dernière version de mon code :
void gestionEtiquettes(char* etiquettes[],char* op,char* ri, char* rj, char* rk, char* nc, int *tailleProg, char* ligne, char* etiq) { int cpt = 0 ; FILE* fic = fopen("essai.asm","r"); while(fgets(ligne,79,fic) != NULL) { if (poly_parsing(ligne,etiq,op,ri,rj,rk,nc)) { etiquettes[cpt] = malloc(strlen(etiq)+1) ; if (etiquettes[cpt] != NULL) { strncpy(etiquettes[cpt],etiq,strlen(etiq)+1); } free(etiquettes[cpt]) ; } cpt ++ ; } *tailleProg = cpt ; fclose(fic) ; }
Si j'ai bien compris, à chaque tour de boucle j'alloue de la mémoire (se trouvant dans la pile ?) à ma case de tableau, puis je copie ma chaine à cet endroit grâce à la fonction strncpy, puis je désalloue cette mémoire.
Je me demande juste quelle mauvaise surprise peut-on avoir si on ne teste pas si le résultat du malloc est NULL (cela voudrait dire qu'on ne pourrait pas lui allouer de mémoire ?)
merci encore pour ces réponses.
Je te conseille aussi de rajouter après le strncpy un '\0' à la position strlen(etiq)+1 dans etiquettes[cpt].
free(etiquettes[cpt]) ;
Il ne faut pas le mettre ici le free. Surtout pas ^^. Tu le mettras lorsque tu n'auras plus besoin d'accéder à cette case du tableau ou au pire à la fin du programme.
Si j'ai bien compris, à chaque tour de boucle j'alloue de la mémoire (se trouvant dans la pile ?) à ma case de tableau, puis je copie ma chaine à cet endroit grâce à la fonction strncpy, puis je désalloue cette mémoire.
Non la mémoire que tu alloues ne se trouve pas dans la pile mais le tas. Mais le reste, tu as compris. Par contre la désallocation de la mémoire doit se faire lorsque tu n'en as plus besoin (voir réponse ci-dessus).
Je me demande juste quelle mauvaise surprise peut-on avoir si on ne teste pas si le résultat du malloc est NULL
Si tu fais : etiquettes[cpt] = malloc(strlen(etiq)+1) ; et que malloc échoue alors etiquettes[cpt] vaudra NULL. L'allocation ne sera donc pas faite et donc strncpy provoquera l'écriture dans une zone allouée : segmentation fault.
free(etiquettes[cpt]) ;
Il ne faut pas le mettre ici le free. Surtout pas ^^. Tu le mettras lorsque tu n'auras plus besoin d'accéder à cette case du tableau ou au pire à la fin du programme.
Si j'ai bien compris, à chaque tour de boucle j'alloue de la mémoire (se trouvant dans la pile ?) à ma case de tableau, puis je copie ma chaine à cet endroit grâce à la fonction strncpy, puis je désalloue cette mémoire.
Non la mémoire que tu alloues ne se trouve pas dans la pile mais le tas. Mais le reste, tu as compris. Par contre la désallocation de la mémoire doit se faire lorsque tu n'en as plus besoin (voir réponse ci-dessus).
Je me demande juste quelle mauvaise surprise peut-on avoir si on ne teste pas si le résultat du malloc est NULL
Si tu fais : etiquettes[cpt] = malloc(strlen(etiq)+1) ; et que malloc échoue alors etiquettes[cpt] vaudra NULL. L'allocation ne sera donc pas faite et donc strncpy provoquera l'écriture dans une zone allouée : segmentation fault.
malloc c'est un peut comme le fork sous linux, on test toujours pour voir si la fonction n'échoue pas mais bon la fonction échoue 1 fois sur 10000, tu peux t'en passé si tu veux économiser 3 lignes
La fonction échoue 1 fois sur 10000
En cas de fonction normale, c'est vrai qu'elle échoue rarement. Mais l'utilisateur peut toujours s'amuser à provoquer un crash de programme, et si la valeur de retour n'a pas été prévu, il pourra exploiter la vulnérabilité.
En C, la règle est simple. Etant donné qu'il s'agit d'un langage bas niveau, il faut tout vérifier soi-même. Et, il faut pas avoir peur d'écrire des lignes en C. ;-))).
En cas de fonction normale, c'est vrai qu'elle échoue rarement. Mais l'utilisateur peut toujours s'amuser à provoquer un crash de programme, et si la valeur de retour n'a pas été prévu, il pourra exploiter la vulnérabilité.
En C, la règle est simple. Etant donné qu'il s'agit d'un langage bas niveau, il faut tout vérifier soi-même. Et, il faut pas avoir peur d'écrire des lignes en C. ;-))).
merci encore, donc voici une nouvelle modification de mon programme :
j'ai ajouté une autre fonction que j'appelle à la fin de mon programme :
je l'appelle comme ceci :
Je pense avoir mieux compris comment tout ça marchait
juste une dernière chose : je ne vois pas comment rajouter le '/0' (je sais que c'est assez stupide, mais je ne me le représente pas bien)
merci encore pour vos réponses et conseils
void gestionEtiquettes(char* etiquettes[],char* op,char* ri, char* rj, char* rk, char* nc, int *tailleProg, char* ligne, char* etiq) { int cpt = 0 ; FILE* fic = fopen("essai.asm","r"); while(fgets(ligne,79,fic) != NULL) { if (poly_parsing(ligne,etiq,op,ri,rj,rk,nc)) { etiquettes[cpt] = malloc(strlen(etiq)+1) ; if (etiquettes[cpt] != NULL) { strncpy(etiquettes[cpt],etiq,strlen(etiq)+1); } } cpt ++ ; } *tailleProg = cpt ; fclose(fic) ; }
j'ai ajouté une autre fonction que j'appelle à la fin de mon programme :
void desalloue_tableau(char* etiquettes[], int *tailleProg) { for (int i = 0 ; i < *tailleProg ; i++) { free(etiquettes[i]) ; } }
je l'appelle comme ceci :
desalloue_tableau(etiquettes, &tailleProg) ;
Je pense avoir mieux compris comment tout ça marchait
juste une dernière chose : je ne vois pas comment rajouter le '/0' (je sais que c'est assez stupide, mais je ne me le représente pas bien)
merci encore pour vos réponses et conseils
desalloue_tableau(etiquettes, &tailleProg) ;
Oui, mais pourquoi passer par un pointeur si tu n'as pas besoin de changer la valeur ?
juste une dernière chose : je ne vois pas comment rajouter le '/0'
strncpy(etiquettes[cpt],etiq,strlen(etiq)+1);
Tu rajoutes juste après : etiquettes[cpt][strlen(etiq)]='\0';
Et un dernier truc, tu fais très bien if (etiquettes[cpt]!=NULL), mais faut aussi agir lorsque malloc retourne NULL, par exemple un simple exit(EXIT_FAILURE) avec juste un avant un message d'erreur.
Sinon tout le reste est bien. Bravo ;-)))
Oui, mais pourquoi passer par un pointeur si tu n'as pas besoin de changer la valeur ?
juste une dernière chose : je ne vois pas comment rajouter le '/0'
strncpy(etiquettes[cpt],etiq,strlen(etiq)+1);
Tu rajoutes juste après : etiquettes[cpt][strlen(etiq)]='\0';
Et un dernier truc, tu fais très bien if (etiquettes[cpt]!=NULL), mais faut aussi agir lorsque malloc retourne NULL, par exemple un simple exit(EXIT_FAILURE) avec juste un avant un message d'erreur.
Sinon tout le reste est bien. Bravo ;-)))
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
le fonction strcat peut t'aider à faire sa:
char* ma_chaine="toto"
strcat(ma_chaine,"titi");
et la ma_chaine = tototiti
fais pareil avec '\0'
a++
char* ma_chaine="toto"
strcat(ma_chaine,"titi");
et la ma_chaine = tototiti
fais pareil avec '\0'
a++