Le langage SMS est exclu sur les forums ProgBoards, tout message ne respectant pas la charte sera déplacé, modifié, ou supprimé par nos modérateurs.

Forum Langages » C & Cie. » strtod en C

Amwus
ProgBoarder
Citer Linux Firefox 2 - Posté le 16/03/2007 à 18:40
Bonjour !

Voila, j'essaie de parser une chaine de caractère avec strtod en C.
En fait, quand il trouve un nombre, il le convertit en double, et j'aimerais m'arreter sur un caractère non numérique, afin de l'analyser.

J'ai tenté dans un premier temps de parser toute la chaine pour comprendre comment fonctionne la fonction de cette façon :


fgets(string, sizeof(string), stdin);
clean(string, stdin);

double number;
char* end;

number = strtod(string, &end);
printf("%.2f\n", number);

for (int count = 0; count <= strlen(string); count++) {
number = strtod(end, &end);

if (number == 0) {
printf("operator : %c\n", string[count]);
(*string) = string[count+1];
}
else {
printf("%.2f\n", number);
}
}



si la chaine contient 5 7 + 8 *, j'obtiens :


5 7 + 8 *
> 5 7 + 8 *
5.00
7.00
operator :
operator : 7
operator :
operator : +
operator :
operator : 8
operator :
operator : *



je précise que la chaine au départ est déclarée comme char string[1024]; (j'entre les données avec fgets). Pourquoi tous ces operator ? Je ne comprend pas d'où ils peuvent venir... en fait, je ne suis pas sur que j'utilise strtod convenablement. D'après moi, strtod lit la chaine passée en premier argument, et si le caractère est valide, elle stocke dans son second paramètre l'adresse de l'élement suivant...

Enfin, je planche un peu sur ce problème... Une idée serait la bienvenue !

Merci d'avance ! (cool)
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore
Francesco
Modérateur
RemonterCiter Linux Mozilla 5 - Posté le 16/03/2007 à 22:09
Soit ta chaine de départ :


5 7 + 8 *


Regardons chaque itération de la boucle for

Itération 1 :
count = 0
end = " 7 + 8 *"
strtod converti 7 en réel, ce que confirme l'affichage

Iteration 2 :
end = " + 8 *"
count = 1
strtod ne peut pas convertir le nombre en réel, et renvoi donc 0. Et string[count]=' ', d'où le "opérateur : " sur ta sortie standard.

Iteration 3 :
end = " + 8 *"
count = 2
end ne change plus ! Il est bloqué. Ainsi, ta variable number est toujours initialisé à 0. De ce fait, c'est le code suivant le "else" qui s'exécute".
Tout tes "opérator : x" viennent de là.


L'erreur que tu fais est un "classique", si je puis me permettre. Tu utilises une boucle for qui gère... 2 itérateurs ! :
- la variable "count" est le premier, et il est géré par la boucle elle-même ;
- la variable "end" représente le deuxième, que tu gère toi-même.
Le souci est que ces deux opérateurs ne sont pas "synchronisé". Je veux dire par là que si strtod converit "123" par exemple, alors ta variable "end" avance de 3 caractères, alors que ta variable count ne sera incrémenté que de 1.
Gates gave you the windows.
GNU gave us the whole house.(Alexandrin)
Amwus
ProgBoarder
RemonterCiter Linux Firefox 2 - Posté le 17/03/2007 à 13:23
ouf ! oui je pense que je comprend... heu, concrètement, y a -t- il moyen de corriger ça sans refaire totalement ma boucle ? Ou dois je intégrer le strtod dans la boucle ?

J'ai un projet utilisant cette fonction à rendre pour mercredi et je suis à la bourre ! Je dois absolument comprendre (sourire) ! Merci de ta réponse en tout cas.

(clein d'oeil)
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore
Amwus
ProgBoarder
RemonterCiter Linux Firefox 2 - Posté le 17/03/2007 à 13:38
Il y a qd même quelque chose que je ne comprend pas. Tu dis que ma variable est initialisée à 0, or le programme affiche qd même le reste de la chaine dans les opérator. Donc c'est qu'il fini par y accéder non...

C'est flou ce strtod. J'avais lu quelque part que si le caractère répéré est non valide, endp pointe vers le début de la chaine string.... Mais je n'en sais trop rien !
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore
Francesco
Modérateur
RemonterCiter Linux Mozilla 5 - Posté le 17/03/2007 à 15:07
Si tu regarde bien, lorsque number vaut 0, il t'affiche le caractère string[count]. C'est donc tout à fait normal.

strtod fait pointer ta variable "end" sur la chaine "end" elle-même, dans le cas où le caractère est invalide. Donc, comme ton pointeur "end" ne bouge plus, tu peux faire autant d'appel successif que tu veux à strtod, cela ne changera rien.

Pour résoudre ton problème, il y a un truc tout simple à faire, au niveau de ta boucle for, dans le if plus précisement


if (number == 0) {
printf("operator : %c\n", *end); // Affiche le caractère courant. Tu peux mettre end[0] aussi.
end++; // Le pointeur pointe maintenant sur le caractère suivant.
}
else {
printf("%.2f\n", number);
}



Cela devrait mieux marcher maintenant ^^.

Edité par Francesco ( 17/03/2007 15:08:47 )
Gates gave you the windows.
GNU gave us the whole house.(Alexandrin)
Amwus
ProgBoarder
RemonterCiter Linux Firefox 2 - Posté le 17/03/2007 à 16:23
D'accord... ok, là ça va déjà beaucoup mieux, mais j'ai un autre soucis, dans le même genre. Maintenant quand il trouve un nombre, il l'affiche bien normalement, et quand il trouve un caractère, il l'affiche avec operator, mais voila, si strtod détecte un nombre, elle va supprimer les espaces avant ce nombre, mais pas si ce n'est pas un nombre !

Donc, je me retrouve avec des espacements un peu partout :

A la première itération, j'ai " 7 + 8 *". Ici, strtod va supprimer l'espace devant le 7 et transformer 7 en double. Mais à l'itération suivante, j'aurai " + 8 *".
Ici, elle ne supprime pas l'espace devant le +, et ça va me poser problème dans l'analyse de ma chaine, si je ne veux prendre que le +.

Crois tu qu'en rajoutant un test du style
if (strcmp(*end, " ") == 0) {
"ne pas enregistrer le caractère et passer au suivant";
}

mon problème sera résolu ?

Merci (sourire)

EDIT : en faisant cela, j'ai l'erreur suivante :


stack-calc.c:45: warning: passing argument 1 of ‘strcmp’ makes pointer from integer without a cast



Edité par Amwus ( 17/03/2007 16:29:00 )
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore
Francesco
Modérateur
RemonterCiter Linux Mozilla 5 - Posté le 17/03/2007 à 16:48
alors, d'abord, si tu utilise strcmp, c'est strcmp(end, " ") et non strcmp(*end, " "). Tu ne devrais plus avoir le warning après cela.

Ensuite, strcmp ne convient pas, puisqu'il s'agit de comparer un seul caractère, avec un autre, et non 2 chaines de caractères. La condition à mettre dans le if est quelque chose du genre string[count] == ' '

Et sinon, oui, en enregistrant pas le caractère, cela devrait faire ce que tu souhaite...
Gates gave you the windows.
GNU gave us the whole house.(Alexandrin)
Amwus
ProgBoarder
RemonterCiter Linux Firefox 2 - Posté le 17/03/2007 à 17:11
oulaa ! je ne comprend plus rien moi !
Bon, si strtod renvois 0, alors end pointe vers le reste de la chaine ok ? Dans le cas ou j'ai "8 7 + 2 *", après le 7, end va pointer sur " + 2 *" j'ai bien compris ?

Donc, end pointe bien sur un caractère vide avant le plus. Et pourtant tu as raison, le strcmp déconne sur ce coup là... Mais on a dit plus haut que le count n'était pas synchronisé avec le end, donc ça va poser problème si je teste avec string[count]....

comprend pas...
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore
Francesco
Modérateur
RemonterCiter Linux Mozilla 5 - Posté le 17/03/2007 à 17:23
oups, erreur de ma part ^^
ce n'est pas string[count] == ' ' mais end[0] == ' ' qu'il faut lire (langue)

Sinon, pour le coup du strtod, je crois que tu as compris ^^
Gates gave you the windows.
GNU gave us the whole house.(Alexandrin)
Amwus
ProgBoarder
RemonterCiter Linux Firefox 2 - Posté le 17/03/2007 à 17:59
Haa oui j'aurais même du y penser moi même tiens ! Là ok ça roule... un dernier léger problème, tout à la fin j'obtiens ça :


> 6 7 8 * +
6.00
7.00
8.00
space : go to next element
operator : *
space : go to next element
operator : +
operator :
operator :
operator :
operator :



On dirait qu'à la fin, la boucle continue, pour je ne sais quelle raison.
Pourquoi rajoute -t- il des operator: à la fin ? c'est bizarre...
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore
Amwus
ProgBoarder
RemonterCiter Linux Firefox 2 - Posté le 17/03/2007 à 18:27
imaginons que je veuille tout faire en une seule boucle for.
par exemple :

char* end;
double number;

for (int count = 0; count <= strlen(string); count ++) {
number = strtod(string, &end);

etc.
}

A la fin de la boucle, string doit en fait pointer vers ce que pointe end non ? Ma question est : comment faire en sorte qu'à chaque itération, string pointe vers ce que pointe end, de façon à ne pas faire un test avant la boucle...

merci
"Engl Amps are the best i've ever used... Not only are they powerfull, but they have charachter too..." R. Blackmore

Poster une réponse

STOP aux fautes volontaires !
Message
Formatage
Note: pour partager du code source, merci d'utiliser le wall !
Smileys (sourire) (yekyek) (clein d'oeil) (désapprouve) (triste) (cool) (langue) (confus) (gêné) (neutre) (eek) (surpris) (diable) (flèche) (exclamation) (question) (diable) (idée) (méchant)
Pseudonyme
Recopiez le code
v6 © Computaid SPRL 2005-2008 - Tous droits réservés - Hébergé par eTigris - Page générée en 0,119 s - Crédits - Stats
1 connecté