Problème return char.

Problème return char. - C - Programmation

Marsh Posté le 27-03-2011 à 11:44:33    

Bonjour,

 

J'ai un problème avec une simple fonction saisir_mot();

 

Je n'arrive pas à comprendre le système de pointeur relier avec le type char, car lorsque je réutilise ma variable dans une autre fonction, elle affiche des caractères bizarres:

 

GDB affiche ces messages d'erreur :

  
Code :
  1. char saisir_mot()
  2. {
  3.     char *mot;
  4.     puts("Saisissez un mot" );
  5.     scanf("%s",mot);
  6.     mot = (char*)malloc(sizeof(char));
  7.     return mot; //warning: return makes integer from pointer without a cast|
  8. }
 

Dans mon main, j'ai ceci comme message d'erreur:

 

char *mot;
mot = saisir_mot(); //|warning: assignment makes pointer from integer without a cast|

 

Je vous remercie par avance de votre aide. :)

 

EDIT : Oups désolé, ce n'est pas le bon forum, à force de me balader sur le forum, je pensais avoir enregistrer le post dans la section Langage C. :/

 

Edité par Elmoricq : c'est réparé


Message édité par Elmoricq le 27-03-2011 à 11:53:50
Reply

Marsh Posté le 27-03-2011 à 11:44:33   

Reply

Marsh Posté le 27-03-2011 à 11:58:05    

1. C'est très simple :
La variable "mot" est de type char*
Ta fonction est censée retourner une variable de type char
Donc : erreur. Change ta fonction pour qu'elle retourne un char*

 

2. Un pointeur, c'est bêtement une adresse mémoire à partir de laquelle débute un stockage.
Donc, un "char *" est censé contenir une adresse pointant vers le début d'une zone mémoire dynamique allouée pour contenir des char.

 

Si l'on regarde ton code, on voit un autre souci : il n'y a pas de zone mémoire allouée au moment d'utiliser scanf. Ta variable *mot étant non-initialisée, elle contient soit NULL soit une valeur aléatoire, en fonction du mode de compilation (debug ou release). Donc au moment de saisir un mot, le programme va essayer de stocker soit vers NULL (segmentation violation) soit vers une adresse aléatoire (non valide et donc re-segfault ou, pire, valide).
Il faut donc utiliser malloc avait le scanf.

 

3. Autre chose :  en C, inutile de caster void*, donc pas besoin de caster le retour de malloc.
De plus, l'argument de malloc c'est la taille de la zone mémoire que tu alloues à ta variable. Ici, tu alloues "sizeof(char)". Donc, tu alloues pour 1 caractère. En vérité, 0 puisque, en C, une chaîne de caractère de longueur n doit être allouée de sorte à pouvoir stocker n+1 caractères (n caractères + 1 zéro terminal).
Donc, ton malloc devrait plutôt avoir cette tête-là :

mot = malloc((longueur_a_determiner + 1) * sizeof(char));

 

4. Enfin, dernière chose : utilise fgets plutôt que scanf, beaucoup plus facile à utiliser. La fonction scanf n'est pas une fonction simple à utiliser correctement.


Message édité par Elmoricq le 27-03-2011 à 12:05:03
Reply

Marsh Posté le 27-03-2011 à 12:44:45    

Merci de ta réponse rapide, je pense avoir compris quelques notions grâce à toi.
 
J'ai simplement changé la sortie de type char par un type char*.
Je pensais qu'en rajoutant un pointeur, ma fonction aurait buggué mais pourtant non, ça marche très bien.
 
Ensuite pour le malloc, j'ai changé son emplacement après avoir remarqué mon erreur.
Je comprends mieux le fonctionnement du malloc grâce à toi. J'avais vu dans des cours le code comme tu me le présentes, mais je ne savais pas du tout à quoi servit le +1
 
J'ai donc remplacer mon ancien malloc par ceci :
 

Code :
  1. mot = malloc((strlen(mot)+1)*sizeof(char));


 
Et maintenant, j'ai une fonction qui marche très bien.
 
Mais, j'ai un autre problème un peu plus compliqué maintenant.
Ce mot, je dois le placer dans une structure (qui est un arbre) :
 
Le problème est que, si je rentre le mot anticonstitutionnellement dans la structure, il n'affiche sur le terminal que la moitié du mot.
J'ai essayé plusieurs codes, avec par exemple  

Code :
  1. racine->mot = mot;


ou

Code :
  1. strcpy(racine->mot,mot);


 
Si, ça peut t'aider voici mon code intégrale.
 
 
 
 

Code :
  1. #include <stddef.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. typedef struct noeud
  6. {
  7. char *mot;
  8. struct noeud *fg;
  9. struct noeud *fd;
  10. }noeud;
  11. noeud cons (char *mot, noeud *racine)
  12. {
  13. racine = (noeud*)malloc(sizeof(noeud));
  14. racine->mot = malloc((strlen(mot)+1)*sizeof(char));
  15. if(racine == NULL);
  16. {
  17.  strcpy(racine->mot,mot);
  18.  racine->fg=NULL;
  19.  racine->fd=NULL;
  20.  printf("test" );
  21. }
  22. printf("%s", racine->mot);
  23. return *racine;
  24. }
  25. char* saisir_mot(char *mot)
  26. {
  27.     mot = malloc((strlen(mot)+1)*sizeof(char));
  28.     puts("Saisissez un mot" );
  29.     scanf("%s",mot);
  30.     printf("%s",mot);
  31.     return mot;
  32. }
  33. int main (int argc, char* argv[])
  34. {
  35. noeud *racine = NULL;
  36. char *mot;
  37. mot = saisir_mot(mot);
  38. cons(mot,racine);
  39. return 0;
  40. }

Reply

Marsh Posté le 27-03-2011 à 13:02:59    

Pikar a écrit :

Code :
  1. mot = malloc((strlen(mot)+1)*sizeof(char));


 
Et maintenant, j'ai une fonction qui marche très bien.


 
Par quel miracle ?
Je veux dire : tu alloues de l'espace à mot pour qu'il puisse contenir des choses. Comment peut-il avoir une longueur mesurable avec strlen si mot n'est pas encore alloué ?
 
strlen(mot), au moment du malloc, a une valeur aléatoire dans le meilleur des cas. Dans le pire, ton programme plantera directement parce que mot pointe vers une adresse mémoire qui ne signifie rien.
La fonction strlen se contente d'aller à l'adresse indiquée en paramètre, et de compter les caractères jusqu'à trouver un 0 terminal.  

Reply

Marsh Posté le 27-03-2011 à 13:29:18    

Oui, je vois ce que tu veux dire. Mais pour l'instant chacun de mes tests marchaient et je pensais que le malloc pouvait calculer l'espace à allouer en fonction du nombre de caractères que l'on rentrait. Le mieux serait d'allouer de l'espace en fonction du nombre de caractères rentrés, sinon je ne vois pas à quoi sert le malloc si on est obligé de rentrer un nombre n fixe. Autant faire un

Code :
  1. char *mot[50]

en ajoutant à la fin de la saisie un zéro terminal.

 

Peut-être qu'avec un tampon cela marcherait.

 

EDIT : Finalement, j'ai alloué 25+1 caractères, étant donné que mon sujet de TP consiste à rentrer un mot et à le classer dans un arbre binaire, j'ai pris le nombre de caractères maximum par rapport au mot le long de la langue française.

Message cité 1 fois
Message édité par Pikar le 27-03-2011 à 13:45:41
Reply

Marsh Posté le 27-03-2011 à 14:20:27    

Pikar a écrit :

Mais pour l'instant chacun de mes tests marchaient


Coup de chance ! Essaie de compiler en mode debug pour voir  [:rhetorie du chaos]

 
Pikar a écrit :

et je pensais que le malloc pouvait calculer l'espace à allouer en fonction du nombre de caractères que l'on rentrait.

 

Et non. :)
malloc alloue dynamiquement de la mémoire. Dynamique signifie "durant l'exécution", au contraire de statique où  tu alloues de la mémoire avant la compilation.
L'avantage de l'allocation dynamique, c'est que parfois tu ne sais pas avant compilation combien de mémoire tu auras besoin. Exemple simple : lecture du contenu d'un fichier en le stockant en mémoire : tu ne sais pas à l'avance quelle taille aura ton fichier. Tu dois donc gérer ta mémoire dynamiquement, durant l'exécution du programme.

 

La lecture de chaîne dynamique n'est pas très dure à faire en C, mais c'est toujours un peu lourdingue : il faut passer par de la mémoire dynamiquement allouée, et tu agrandis la zone au fur et à mesure de la lecture si le tampon est trop petit, en contrôlant le nombre de caractères lus : en gros tu lis soit jusqu'au prochain saut de ligne en 1 fois (tampon OK), soit jusqu'à ce que le tampon soit plein, auquel cas tu agrandis l'espace de stockage et tu poursuis la lecture. Rinse & repeat.
Avec fgets c'est facile : le caractère de saut de ligne étant stocké durant la lecture, il suffit de regarder s'il est présent dans la chaîne lue après l'appel à la fonction.

 

Mais pour débuter, le plus simple est de passer par de la mémoire dynamiquement allouée avant lecture avec une centaine de caractères. Pour un mot ce devrait être largement suffisant. Ça n'a pas grand intérêt je te l'accorde, sauf pour s'entraîner à utiliser ces mécaniques correctement.

 
Pikar a écrit :

Le mieux serait d'allouer de l'espace en fonction du nombre de caractères rentrés, sinon je ne vois pas à quoi sert le malloc si on est obligé de rentrer un nombre n fixe. Autant faire un

Code :
  1. char *mot[50]

en ajoutant à la fin de la saisie un zéro terminal.


Là ton "mot" est un tableau de pointeurs. :o
Tu voulais surement écrire "char mot[50]".

 
Pikar a écrit :

Peut-être qu'avec un tampon cela marcherait.


Bingo.

 
Pikar a écrit :

EDIT : Finalement, j'ai alloué 25+1 caractères, étant donné que mon sujet de TP consiste à rentrer un mot et à le classer dans un arbre binaire, j'ai pris le nombre de caractères maximum par rapport au mot le long de la langue française.


Bien joué, cf. ci-dessus. :)
Tu auras le temps en t'exerçant de mieux comprendre comment ça fonctionne et d'écrire des méthodes de lecture plus complètes.


Message édité par Elmoricq le 27-03-2011 à 14:22:32
Reply

Marsh Posté le 27-03-2011 à 19:56:25    

Pikar a écrit :


EDIT : Finalement, j'ai alloué 25+1 caractères, étant donné que mon sujet de TP consiste à rentrer un mot et à le classer dans un arbre binaire, j'ai pris le nombre de caractères maximum par rapport au mot le long de la langue française.

 

Attention si tu déclares dans ta fonction un char mot[26], lorsque tu quitte la fonction mot n'est plus un espace réservé et sera certainement écrasé plus tard.

 

L'idée ici serait de déclarer dans la fonction un char mot[26] par exemple si tu sais que 25 est la taille maximale du mot à saisir.

 

Ensuite après ton fgets tu peut faire un malloc d'un second buffer de la taille exacte de ton mot: strlen(mot) + 1 (ceci pour économiser un peu de mémoire), tu fait ensuite un strncpy dans ton nouveau buffer que ta fonction retourne à l'appelant.


Message édité par h3bus le 27-03-2011 à 19:56:37

---------------
sheep++
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed