Léa-Linux & amis :   LinuxFR   GCU-Squad   GNU
Chaîne de carractères en C
Envoyé par: Dorian

Bonjour,

Quelqu'un pourrait me dire pourquoi ce petit programme ne marche pas ?


#include <stdio.h>

void main(void)
{
char *nom;
printf("\nEntrez un nom: ");
scanf("%s",nom);
printf("\nLe nom choisi est: %s\n",*nom);
}

Segmentation fault :-/

Poste le Wednesday 17 November 2004 14:04:17
Répondre     Citer    
Re: Chaîne de carractères en C
Envoyé par: Sve@r

Ton programme possède deux erreurs principales, l'une pas grave mais bien visible, l'autre plus importante et pis, totalement invisible

A) erreur n° 1
Ta variable "nom" est un pointeur sur un caractère. Il est évident en lisant ton pgm que ce caractère est suivi en mémoire d'autres et donc que tu cherches à manipuler une chaîne. Sauf que "nom" ne pointe que sur le premier octet de cette chaîne.
Si tu veux afficher toute la chaîne, tu devras aller afficher ce qui est pointé par "nom", c'est à dire "*nom" ou "nom[0]" (c'est pareil)
Puis tu devras passer à la case suivante, c'est à dire "nom[1]" ou "*(nom + 1)" puis "nom[2]" etc tant qu'il y a des caractères à afficher, c'est à dire tant qu'il n'y a pas de caractère nul.

La fonction "printf" fait ça automatiquement... mais tu dois lui passer l'adresse du début de ta chaîne, autrement dit tu dois lui passer "nom". A partir de cette adresse, "printf" fera elle-même la boucle pour afficher tous les octets qui se suivent.
Malheureusement, tu lui donnes "*nom", c'est à dire qu'au lieu de lui donner l'adresse du début de la chaîne, tu lui donnes le premier octet de cette chaîne. Pas bon !!! printf ne sait pas où aller chercher les octets suivants (en fait, il considère ce premier octet comme une adresse et va chercher ce qui se trouve à cette adresse => segmentation fault !!!
Voici la bonne syntaxe:
printf("\nLe nom choisi est %s\n", nom);

Comme je l'ai dit, ce n'est pas grave car tu vois immédiatement qu'il y a un soucis et, avec un peu d'habitude, tu peux le régler rapidement

cool smiley Erreur n° 2, vraiment très grave et quasiment invisible
Quand tu déclares "char *nom", tu déclares un pointeur destiné à pointer sur une zone mémoire qui servira à stocker la chaîne saisie. Le pb c'est que cette zone mémoire n'a pas encore été réservée pour ta chaîne. Autrement dit tu risques de stocker ta chaîne sur une zone déjà utilisée par une autre variable, ou stocker ta chaîne dans une zone qui sera utilisée plus tard par une autre variable.
Par exemple, si la variable "nom" vaut "0x1000" tu n'as aucune garantie que la case mémoire "0x1000" et ses suivantes sont réservées pour ta chaîne.
Pour que tu aies une zone mémoire garantie, tu n'as que 2 façons de faires
1) tu déclares "nom" comme un tableau de "n" octets (n choisi assez intelligemment pour stocker des noms de taille convenable)
char nom[1024]

2) tu déclares "nom" comme un pointeur, mais avant d'y mettre quelque chose tu lui alloues suffisemment d'octets pour stocker ta chaîne. Et une fois que tu n'en a splus besoin, tu libère la zone allouée
char *nom;
...
nom=(char*)malloc(1024);
...
scanf("%s", nom);
...
printf("...", nom);
...
free(nom);

Comme je l'ai dit, cette erreur est très grave car le compilateur ne la détecte pas. Et ton programme mal conçu peut fonctionner sans problème durant 10, 20, 10000 fois. Puis tu lui rajoutes une variable toute simple style "int i" et là il plante lamentablement paske "i" recouvre ta chaîne. Tu galèreras un max de temps avant de trouver le pourquoi du comment de l'erreur...

PS: La fonction "main" est de type "int" et pas "void"...

En PJ ton pgm corrigé
int main(void)
{
char nom[1024];
printf("\nEntrez un nom :");
scanf("%s", nom);
printf("\nVotre nom est %s\n", nom);
}



Poste le Wednesday 17 November 2004 15:34:30
Répondre     Citer    
Re: Chaîne de carractères en C
Envoyé par: Dorian

Merci beaucoup pour cette explication détaillée. Effectivement, avec un tableau de caractères, ça marche parfaitement :-)

Je mettais void en type de retour pour pas avoir à écrire return 0; que je trouvais inutile. Mais je me rends compte qu'il ne me demande même pas de valeur de retour quand on met int.

Poste le Wednesday 17 November 2004 16:23:56
Répondre     Citer    
Re: Chaîne de carractères en C
Envoyé par: Sve@r

Le "return" n'est pas obligatoire, même dans une fonction non "void". Sauf que la fonction renvoie qd-même une valeur aléatoire.

Pour éviter le pb d'aller pointer une adresse mémoire erronée qd tu manipules un pointeur style "char *pt", la règle est de ne jamais aller toucher à "*pt" si tu n'as pas fait auparavant "pt=qqchose"
Ex: Dans le post précédent, je faisais "pt=malloc(...)" donc pas de pb.

Tu verras que cette règle très simple t'éviteras à jamais les ennuis de zone mémoire inconnue...

Poste le Wednesday 17 November 2004 21:18:20
Répondre     Citer    

Veuillez vous authentifier auparavant pour commenter.

 

Ce forum !
Chaîne de carractères en C
Pour poser vos questions sur les scripts shell, le Perl, le C, etc... Attention : nous ne sommes pas des spécialistes du dev, ce forum est juste pour de petites aides ponctuelles concernant le développement et les outils de développement.

Sauf mention contraire, les documentations publiées sont sous licence Creative-Commons