[C] soucis, char*, tableau, pointeur :)

Résolu/Fermé
Isabelle - 6 déc. 2009 à 09:46
 Isabelle - 6 déc. 2009 à 21:15
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 :

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:

6 réponses

jaky1212 Messages postés 126 Date d'inscription mardi 25 août 2009 Statut Membre Dernière intervention 4 mars 2013 8
6 déc. 2009 à 11:41
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 ...
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
6 déc. 2009 à 14:42
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,
0
Merci beaucoup à vous deux =)

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.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
6 déc. 2009 à 16:02
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,
0
Isabelle > fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022
6 déc. 2009 à 16:34
merci pour ces nouvelles précisions :

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.
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844 > Isabelle
6 déc. 2009 à 17:32
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.
0
jaky1212 Messages postés 126 Date d'inscription mardi 25 août 2009 Statut Membre Dernière intervention 4 mars 2013 8
6 déc. 2009 à 17:36
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
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
6 déc. 2009 à 17:47
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. ;-))).
0
Isabelle > fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022
6 déc. 2009 à 20:27
merci encore, donc voici une nouvelle modification de mon programme :

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
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844 > Isabelle
6 déc. 2009 à 20:35
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 ;-)))
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
jaky1212 Messages postés 126 Date d'inscription mardi 25 août 2009 Statut Membre Dernière intervention 4 mars 2013 8
6 déc. 2009 à 17:49
entièrement d'accord
0
jaky1212 Messages postés 126 Date d'inscription mardi 25 août 2009 Statut Membre Dernière intervention 4 mars 2013 8
6 déc. 2009 à 20:30
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++
0
fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022 1 844
6 déc. 2009 à 20:37
fais pareil avec '\0'
Non pas besoin de rajouter explicitement le '\0' avec strcat. Il s'ajoute automatiquement dans tous les cas.
Par contre, il vaut mieux utiliser strncat que strcat. Même raison que pour strncpy.

Cdlt
0
Isabelle > fiddy Messages postés 11069 Date d'inscription samedi 5 mai 2007 Statut Contributeur Dernière intervention 23 avril 2022
6 déc. 2009 à 21:15
J'ai fais les dernières modifications que tu m'as suggérée.
Merci encore et bonne continuation

problème totalement résolu =)
0