Le type char - un vrai casse tête
Résolu
hymenoptera
Messages postés
37
Statut
Membre
-
hymenoptera Messages postés 37 Statut Membre -
hymenoptera Messages postés 37 Statut Membre -
Bonjour,
Franchement j'ai vraiment besoin d'aide pour les types char en C, je trouve que c'est horrible à gérer et qu'on a des erreurs très facilement. Je cherche sur le net mais je ne comprends toujours pas les bases de ce type qui rend fou !
Pour commencer j'ai le code suivant :
Ca compile sans aucun soucis, ça s’exécute parfaitement... Maintenant je choisis une taille dynamique :
en compilant j'ai un seg fault, je change alors le print par :
j'obtiens un warning :
et quand j’exécute ça m'affiche n'importe quoi :'(
En fait le warning je l'ai compris, le souci c'est que je ne sais pas comment afficher simplement...
----------------------------------------------------------------------------
J'ai une autre question, cette fois ci ça concerne les char dans les structures. J'ai le code suivant :
Ca compile et ça s’exécute sans aucun souci et je n'ai aucune erreur. Je vous avoue que je comprends rien. Y a une base que je pige pas
Alors que si je déclare comme ça :
J'ai une erreur
Maintenant je change mon code en :
Et crotte ça marche... Je comprends encore moins...
J'en déduis que si je fais :
Et oui ça marche.
En fait mon problème c'est que j'ai cherché des solutions en faisant des tests mais à chaque fois je suis surprise par le résultat, je ne comprends pas vraiment ce qui se passe. Si je fais un "print phrase" et ça plante, je le remplace par "print &phrase" ça marche mais je ne comprends pas pourquoi.
Je ne sais pas c'est quoi la meilleur façon de faire pour que tout fonctionne normalement. J'ai peur qu'en trouvant des solutions comme ça en "trifouillant" je risque d'avoir des soucis avec mon code dans le futur.
Par exemple je ne vois pas pourquoi ce code plante :
alors que celui là marche parfaitement :
Je m'excuse pour le long poste et encore je n'ai pas écrit les autres cas qui m'énervait, je vous remercie de me lire et de m'apporter des clarifications.
Très bonne journée à tous :)
Franchement j'ai vraiment besoin d'aide pour les types char en C, je trouve que c'est horrible à gérer et qu'on a des erreurs très facilement. Je cherche sur le net mais je ne comprends toujours pas les bases de ce type qui rend fou !
Pour commencer j'ai le code suivant :
char phrase[1000];
strcpy(phrase, "bonjour je suis la");
printf("%s \n", phrase);
Ca compile sans aucun soucis, ça s’exécute parfaitement... Maintenant je choisis une taille dynamique :
char * phrase;
strncpy(phrase, "bonjour je suis la", 1000);
printf("%s \n", phrase);
en compilant j'ai un seg fault, je change alors le print par :
printf("%s \n", &phrase);
j'obtiens un warning :
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
printf("%s \n", &phrase);
et quand j’exécute ça m'affiche n'importe quoi :'(
En fait le warning je l'ai compris, le souci c'est que je ne sais pas comment afficher simplement...
----------------------------------------------------------------------------
J'ai une autre question, cette fois ci ça concerne les char dans les structures. J'ai le code suivant :
typedef struct test
{
char phrase1 [100];
char * phrase2;
} test;
test chaine=
{
.phrase1="bonjour !",
.phrase2="au revoir",
};
printf("%s \n %s\n", chaine.phrase1, chaine.phrase2);
Ca compile et ça s’exécute sans aucun souci et je n'ai aucune erreur. Je vous avoue que je comprends rien. Y a une base que je pige pas
Alors que si je déclare comme ça :
test chaine;
chaine.phrase1="bonjour !",
chaine.phrase2="au revoir",
J'ai une erreur
error: assignment to expression with array type
chaine.phrase1="bonjour !",
Maintenant je change mon code en :
test chaine;
strcpy(chaine.phrase1,"bonjour !");
chaine.phrase2="au revoir";
printf("%s \n %s\n", chaine.phrase1, chaine.phrase2);
Et crotte ça marche... Je comprends encore moins...
J'en déduis que si je fais :
char * phrase;
phrase="bonjour je suis la";
printf("%s \n", phrase);
Et oui ça marche.
En fait mon problème c'est que j'ai cherché des solutions en faisant des tests mais à chaque fois je suis surprise par le résultat, je ne comprends pas vraiment ce qui se passe. Si je fais un "print phrase" et ça plante, je le remplace par "print &phrase" ça marche mais je ne comprends pas pourquoi.
Je ne sais pas c'est quoi la meilleur façon de faire pour que tout fonctionne normalement. J'ai peur qu'en trouvant des solutions comme ça en "trifouillant" je risque d'avoir des soucis avec mon code dans le futur.
Par exemple je ne vois pas pourquoi ce code plante :
char * phrase;
strncpy(phrase, "bonjour je suis la", 1000);
printf("%s \n", phrase);
alors que celui là marche parfaitement :
char * phrase;
phrase="bonjour je suis la";
printf("%s \n", phrase);
Je m'excuse pour le long poste et encore je n'ai pas écrit les autres cas qui m'énervait, je vous remercie de me lire et de m'apporter des clarifications.
Très bonne journée à tous :)
2 réponses
-
Quand tu fais :
char * phrase; strncpy(phrase, "bonjour je suis la", 1000);
Tu déclare un pointeur, mais tu ne l'initalise pas, du coup, ça mets tes données dans un endroit non prévu.
Il faut l'assigner soit avec une chaine de longueur cohérente à ton usage ou avec une de ces lignes :char * phrase="Une chaine d'initialisation"; char phrase[20]; char * phrase=malloc(...)
-
Salut hymenoptera,
char
est un type entier, qui sert à représenter un seul caractère.
Une chaîne de caractères nécessite une zone mémoire où plusieurs char peuvent être stockés, y compris le caractère'\0'
qui signale la fin de la chaîne.
1.
Dans la première partie de ton post, tu nous dis :
Pour commencer j'ai le code suivant :char phrase[1000]; strcpy(phrase, "bonjour je suis la"); printf("%s \n", phrase);
Ca compile sans aucun soucis, ça s’exécute parfaitement...
En ligne 1, tu as définitphrase
comme étant un tableau de 1000char
. Tu as donc réservé un espace mémoire de 1000char
et tu n'as aucun problème pour y stocker ta chaîne et son affichage s'exécute comme il se doit lephrase
dans leprintf
passant à cette fonction le pointeur vers le premier élément du tableau.
Maintenant je choisis une taille dynamique :char * phrase; strncpy(phrase, "bonjour je suis la", 1000); printf("%s \n", phrase);
en compilant j'ai un seg fault
Le C ne va pas automatiquement allouer la mémoire nécessaire sur un pointeur, c'est à toi de la gérer.
En ligne 1 tu as définiphrase
comme étant un pointeur surchar
. Un pointeur est une variable qui sert à stocker une adresse mémoire. Un pointeur surchar
n'est donc pas, à lui seul, un type magique qui te permet de stocker quoi que ce soit d'autre ... qu'une seule adresse mémoire. A ce stade là, tu n'as donc rien réservé dynamiquement. De plus, ton pointeur (le contenu de la variablephrase
), n'est pas initialisé, et contient n'importe quoi (une adresse mémoire arbitraire constituée de ce qu'il y a en mémoire à cet endroit). Donc lorsqu'en ligne 2 du tentes de copier ton texte avec un pointeur pointant n'importe où, il en résulte une erreur de segmentation à l'exécution.
Pour utiliser le pointeur, tu dois l'initialiser en y mettant une adresse d'une mémoire allouée au programme. Pour réserver une quantité de mémoire déterminée à l'exécution, tu réserves de la mémoire sur le tas avecmalloc
et tu libères la mémoire avecfree
.
char * phrase = NULL; phrase = malloc(1000); if (phrase != NULL) { strncpy(phrase, "bonjour je suis la", 1000); printf("%s \n", phrase); } free(phrase);
Ensuite, tu dis :
je change alors le print par :printf("%s \n", &phrase);
j'obtiens un warning :
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
printf("%s \n", &phrase);
et quand j’exécute ça m'affiche n'importe quoi :'(
En fait le warning je l'ai compris, le souci c'est que je ne sais pas comment afficher simplement...
printf
avec%s
nécessite que tu passes un pointeur surchar
, or, là tu passes un pointeur sur un pointeur surchar
. Le compilateur t'avertit, mais tu ne vas rien afficher de cohérent, et ton programme plantera de toutes façon à la ligne précédente.
2.
Ce que tu constates avec tes tests dans la 2ème partie de ton post est dû à deux choses.
J'ai le code suivant :typedef struct test { char phrase1 [100]; char * phrase2; } test; test chaine= { .phrase1="bonjour !", .phrase2="au revoir", }; printf("%s \n %s\n", chaine.phrase1, chaine.phrase2);
Ca compile et ça s’exécute sans aucun souci et je n'ai aucune erreur. Je vous avoue que je comprends rien. Y a une base que je pige pas
Le C sait gérer les affectations lors des déclarations de variables.
De la même façon, en C, tu peux faire :char phrase[100] = "toto";
et cela va réserver un espace mémoire de 100, copier dans cette zone mémoire allouée "toto" avec le caractère terminateur '\0'. Tout cela est fait par le compilateur au stade de la compilation.
Tu dis aussi :
celui là marche parfaitement :char * phrase; phrase="bonjour je suis la"; printf("%s \n", phrase);
Là on n'est plus au stade de la déclaration en ligne 2. Cependant, cela "marche" car lorsque ce code est compilé, le compilateur va réserver un espace mémoire dans la pile pour le stockage de la chaîne littérale constante"bonjour je suis la"
. Dans ton code, lorsque tu faisphrase="bonjour je suis la";
, tu affectes à la variablephrase
l'adresse mémoire où ces données sont stockées.
Ce qui explique ceci :
Alors que si je déclare comme ça :test chaine; chaine.phrase1="bonjour !", chaine.phrase2="au revoir",
J'ai une erreur
error: assignment to expression with array type
chaine.phrase1="bonjour !",
Oui, tu as une erreur, car "bonjour !" est évalué par le compilateur C sous la forme d'une adresse mémoire pointant vers la chaîne littérale en question, alors que le typechaine.phrase1
est un type tableau. Tu ne peux pas faire cela, sauf lors de la déclaration. D'ailleurs, c'est mieux que cela ne marche pas, autrement, tu pourrais écraser l'adresse vers ton espace mémoire réservé à l'usage du tableau. Pour une fois, le C te défend contre ce type de risque.
Pourchaine.phrase2
, on affecte l'adresse mémoire pointant vers la chaîne littérale en question à une variable pointeur surchar
qui ne peut accueillir qu'une adresse (pointant sur des données de ce type), donc tout va bien.
Pour ajouter à la casuistique, lors de la déclaration, tu peux valablement faire :
char * phrase1 = "bonjour !"; char phrase2[] = "au revoir";
Dans le premier cas, tu as une chaîne littérale à ta disposition, dans le deuxième une chaîne modifiable sous forme de tableau, dont la taille et l'affectation au tableau sont gérées par le compilateur à la déclaration.
:-)
Dal-
ahhhh merci infiniment pour ces éclaircissements. Tu m'as vraiment éclairé comme t'as pas idée !
C'est bête, mais je n'ai pas pensé à allouer de la mémoire avec char, alors qu'avec un double ou int c'est automatique. Je comprends bien maintenant que les chaînes de caractères sont en fait des tableaux :D, un peu spéciaux ces tableaux quand même <.<"
Un grand merci. Je ferme le sujet car c'est très complet et super clair ^__^
Très bonne fin de journée
-