Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2920 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Calculatrice notation scientifique

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Calculatrice notation scientifique

n°2164437
simius_com​putus
oh Gary boy
Posté le 17-11-2012 à 19:32:43  profilanswer
 

Salut

 

J'ai commencé le C en septembre, ça me faisait envie depuis longtemps mais j'avais la flemme de sortir de ce que je bidouillais en html/js ( [:inspecteur derrick] ). Evidemment c'est un autre univers, pour le moment je me limite à des trucs sur console, déjà il y a de quoi faire. Après avoir lu une bonne partie du Kernighan&Ritchie, plus le siteduzero, voici mon premier programme utile qui permet donc d'analyser et calculer la saisie de l'utilisateur en mode scientifique, avec les priorités d'opérateurs, les niveaux de parenthèses, la détection des erreurs de syntaxe et d'éventuelles divisions par zéro. Vlà le code :

 
Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #define MAXLGHT 50 //taille autorisée pour la saisie
  5. int getStr(char []); //enregistre la saisie jusqu'à \n en ignorant les espaces, renvoie le nombre de caractères (sauf \n)
  6. double calc(char [], int); //traite la saisie, repère les erreurs de syntaxe, et gère l'exécution du calcul par niveaux avant de renvoyer le résultat final
  7. int decp(int); //renvoie 10 puissance argument, utilisée pour lire les nombres dans la saisie
  8. double lvlCalc(double*, double*, char*, int*); //renvoie le résultat de calcul sur un niveau de parenthèses en gérant la priorité des opérateurs et d'éventuelles divisions par zéro
  9. int main()
  10. {
  11.     int i, max = MAXLGHT;
  12.     char read[MAXLGHT]; //stocke la saisie brute
  13.     printf("Calculatrice en notation scientifique.\nLimite de caracteres : %d\n\n",max);
  14.     for(;;)
  15.     {
  16.         i = getStr(read);
  17.         if(i <= MAXLGHT)
  18.             printf("%f\n\n",calc(read, i)); //appelle calc si la saisie ne dépasse pas la taille autorisée
  19.         else
  20.             printf("depassement : %d caracteres max\n", MAXLGHT);
  21.     }
  22.     return 0;
  23. }
  24. int getStr(char c[])
  25. {
  26.     char temp;
  27.     int i = 0;
  28.     for(;;)
  29.         if((temp = getchar()) != '\n')
  30.             c[(isspace(temp))?i:i++] = temp;
  31.         else
  32.             break;
  33.     c[i] = '\0';
  34.     return i;
  35. }
  36. int decp(int a)
  37. {
  38.     int i, p = 1;
  39.     for (i = 0; i < a; i++)
  40.         p = p * 10;
  41.     return p;
  42. }
  43. double calc(char str[], int cSize)
  44. {
  45.     double result = 0.0; //stocke résultat final
  46.     double curNb = 0.0; //variable temp pour lecture des nombres
  47.     double calcFormat[cSize]; //stocke la saisie sous sa forme calculable, opérateurs et opérandes uniquement
  48.     int lvls[cSize]; //stocke les niveaux de parenthèses de chaque opérateur ou opérande
  49.     char type[cSize]; //détermine la nature de chaque élément de calcFormat : 'o' pour opérateur, 'd' pour nombre, 'v' pour à ignorer (déjà pris en compte dans un niveau supérieur)
  50.     int zdiv = 0; //division par zéro
  51.     int decInd = 0; //variable temp pour calcul des nombres à partie décimale
  52.     int curLvl = 1; //niveau de parenthèses en cours de traitement
  53.     int topLvl = 1; //plus grand niveau de parenthèses (on commence par là)
  54.     int error = 0; //erreur(s)
  55.     int i, j, k = 0; //indices
  56.     for(i = 0; i < cSize && error == 0; i++) //construit calcFormat[], lvls[], type[], repère les erreurs de syntaxe
  57.     {
  58.         if(isdigit(str[i])) //calcule les nombres avec leur partie décimale éventuelle
  59.         {
  60.             if(i > 0 && str[i-1] == ')') //erreur si un nombre suit directement une parenthèse
  61.                 ++error;
  62.             for(j = 0; isdigit(str[i]) && error == 0; i++, j++)
  63.             {
  64.                 curNb = 10 * curNb + (str[i] - '0');
  65.                 if(str[i+1] == '.') //on rencontre un point de décimal
  66.                 {
  67.                     if(decInd == 0) //vérifie que c'est le premier rencontré pour le nombre courant
  68.                     {
  69.                         i++;
  70.                         decInd = j + 1; //mémorise sa place dans le nombre courant
  71.                     }
  72.                     else
  73.                         ++error;
  74.                 }
  75.             }
  76.             calcFormat[k] = (decInd > 0 && decInd != j) ? curNb / (decp(j - decInd)) : curNb; //si on a une partie décimale et qu'elle n'est pas vide (au moins un chiffre après le point), diviser le nombre par 10 puissance le nombre de décimales
  77.             type[k] = 'd'; //l'élément est un nombre
  78.             lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  79.             decInd = 0;
  80.             curNb = 0.0;
  81.             i--;
  82.         }
  83.         else if(str[i] == '(') //saute les parenthèses ouvrantes et incrémente le niveau en conséquence, repère d'éventuelles erreurs de syntaxe
  84.         {
  85.             if(i == 0 || (i > 0 && i < cSize - 1 && str[i-1] != ')' && !isdigit(str[i-1])))
  86.             {
  87.                 ++curLvl;
  88.                 if(curLvl > topLvl) //si le niveau est plus grand que le plus grand rencontré, mettre à jour ce dernier
  89.                     topLvl = curLvl;
  90.             }
  91.             else
  92.                 ++error;
  93.         }
  94.         else if(str[i] == ')') //saute les parenthèses fermantes et décrémente le niveau en conséquence, repère d'éventuelles erreurs de syntaxe
  95.         {
  96.             if(i > 0 && str[i-1] != '(' && str[i-1] != '+' && str[i-1] != '-' && str[i-1] != '*' && str[i-1] != '/')
  97.                 --curLvl;
  98.             else
  99.                 ++error;
  100.         }
  101.         else if(str[i] == '+' || str[i] == '*' || str[i] == '/') //les opérateurs +, * et / ont les mêmes règles de syntaxe
  102.         {
  103.             if(i > 0 && i < cSize - 1 && (isdigit(str[i-1]) || str[i-1] == ')'))
  104.             {
  105.                 calcFormat[k] = str[i];
  106.                 type[k] = 'o'; //l'élément est un opérateur
  107.                 lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  108.             }
  109.             else
  110.                 ++error;
  111.         }
  112.         else if(str[i] == '-') //règle de syntaxe pour l'opérateur -
  113.         {
  114.             if((i > 0 && i < cSize - 1 && (isdigit(str[i-1]) || str[i-1] == ')' || str[i-1] == '(')) || (i == 0 && cSize > 1))
  115.             {
  116.                 calcFormat[k] = str[i];
  117.                 type[k] = 'o'; //l'élément est un opérateur
  118.                 lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  119.             }
  120.             else
  121.                 ++error;
  122.         }
  123.         else //ni un nombre, ni une parenthèse, ni un opérateur
  124.             ++error;
  125.     }
  126.     calcFormat[k] = '\0';
  127.     lvls[k] = '\0';
  128.     type[k] = '\0';
  129.     if(curLvl != 1) //si il n'y a pas autant de '(' que de ')'
  130.         ++error;
  131.     if(error == 0) //si pas d'erreur
  132.     {
  133.         int left, right; //champ d'action de lclCalc dans calcFormat[]
  134.         for(; topLvl >= 1; topLvl--) //examine chaque niveau du plus élevé à 1
  135.         {
  136.             for(i = 0; i < k; i++) //repère les parties correspondant au niveau topLvl
  137.             {
  138.                 for(; lvls[i] < topLvl; ++i) //saute les niveaux inférieurs
  139.                     ;
  140.                 left = i;
  141.                 for(; lvls[i] >= topLvl; ++i)
  142.                     ;
  143.                 right = i-1;
  144.                 result = lvlCalc(&calcFormat[left], &calcFormat[right], &type[left], &zdiv); //calcule le niveau en cours
  145.                 calcFormat[left] = result; //stocke le résultat à gauche
  146.                 --lvls[left]; //décrémente le niveau de l'élément contenant le résultat afin qu'il soit pris en compte par le niveau suivant
  147.                 if(zdiv) //lvlCalc a indiqué une division par zéro
  148.                 {
  149.                     printf("division par zero !\n" );
  150.                     return 0.0;
  151.                 }
  152.             }
  153.         }
  154.     }
  155.     else
  156.         printf("erreur de syntaxe\n" );
  157.     return result;
  158. }
  159. double lvlCalc(double* start, double* end, char* opCheck, int* zdiv)
  160. {
  161.     double result = 0.0; //résultat pour la plage donnée à calculer
  162.     double* stemp = start; //compteur pour la 1ère boucle, pointe sur les éléments de calcFormat[]
  163.     double* first = start; //garde en mémoire l'élément de gauche
  164.     char* opStart = opCheck; //compteur pour la 1ère boucle, pointe sur les éléments de type[]
  165.     int leftSp = 0, rightSp = 0; //variables pour le saut les éléments de type 'v' situés autour des opérateurs * et /
  166.     for(; stemp <= end; stemp++, opStart++) //première boucle sur l'étendue indiquée
  167.     {
  168.         if(*stemp == '*' && *opStart == 'o') //rencontre un opérateur *
  169.         {
  170.             for(; *(opStart-1-leftSp) == 'v'; leftSp++) //saute les éléments de type 'v' à gauche
  171.                 ;
  172.             for(; *(opStart+1+rightSp) == 'v'; rightSp++) //saute les éléments de type 'v' à droite
  173.                 ;
  174.             *(stemp-1-leftSp) = *(stemp-1-leftSp) * *(stemp+1+rightSp); //stocke le résultat dans l'opérande de gauche
  175.             *opStart = 'v'; //indique l'opérateur comme déjà utilisé
  176.             *(opStart+1+rightSp) = 'v'; //indique l'opérande de droite comme déjà utilisé
  177.             opStart += 1+rightSp; //saute la plage qu'on vient de calculer
  178.             stemp += 1+rightSp; //pareil avec l'autre indice
  179.         }
  180.         else if(*stemp == '/' && *opStart == 'o') //rencontre un opérateur / (même méthode que pour *)
  181.         {
  182.             for(; *(opStart-1-leftSp) == 'v'; leftSp++)
  183.                 ;
  184.             for(; *(opStart+1+rightSp) == 'v'; rightSp++)
  185.                 ;
  186.             if(*(stemp+1+rightSp) != 0) //opérande de droite != 0
  187.                 *(stemp-1-leftSp) = *(stemp-1-leftSp) / *(stemp+1+rightSp);
  188.             else //division par zéro
  189.                 {
  190.                     *zdiv = 1;
  191.                     return 0.0;
  192.                 }
  193.             *opStart = 'v';
  194.             *(opStart+1+rightSp) = 'v';
  195.             opStart += 1+rightSp;
  196.             stemp += 1+rightSp;
  197.         }
  198.     } //les opérations prioritaires ont été effectuées, reste que des additions et soustractions dans l'étendue indiquée
  199.     if(*opCheck == 'd') //additionne au résultat l'élément tout à gauche si c'est un nombre (ça pourrait être un opérateur -)
  200.         result += *start;
  201.     for(; start <= end; start++, opCheck++) //seconde boucle sur l'étendue indiquée
  202.     {
  203.         if(*start == '+' && *opCheck == 'o') //rencontre un opérateur +
  204.         {
  205.             for(; *(opCheck+1) == 'v'; opCheck++, start++) //saute les éléments déjà utilisés à droite jusqu'à rencontrer un opérande
  206.                 ;
  207.             result += *(start+1); //additionne l'opérande au résultat
  208.             *opCheck = 'v'; //l'opérateur est marqué comme déjà utilisé
  209.             *(opCheck+1) = 'v'; //l'opérande est marqué comme déjà utilisé
  210.         }
  211.         if(*start == '-' && *opCheck == 'o') //même principe pour -
  212.         {
  213.             for(; *(opCheck+1) == 'v'; opCheck++, start++)
  214.                 ;
  215.             result -= *(start+1);
  216.             *opCheck = (start > first)?'v':'d'; //comme l'opérateur - peut se trouver en premier élément, on veille à le marquer comme nombre pour que le résultat stocké dedans ne soit pas ignoré par les niveaux suivants
  217.             *(opCheck+1) = 'v';
  218.         }
  219.     }
  220.     return result;
  221. }
 

Alors déjà, si vous voulez le tester dans tous les sens, j'ai peut-être négligé des choses.
Et puis au niveau du code il y a sûrement moyen d'optimiser, tant en volume de code source (utiliser des macros ?) qu'en performances dans l'exécution, je suis preneur de vos conseils. J'ai essayé de mettre des commentaires qui rendent la chose plus facile à examiner   :o

 

Merci,


Message édité par simius_computus le 17-11-2012 à 22:40:48

---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
mood
Publicité
Posté le 17-11-2012 à 19:32:43  profilanswer
 

n°2164448
Sve@r
Posté le 17-11-2012 à 21:54:10  profilanswer
 

Salut
 
Pour un programme de débutant c'est plus qu'excellent. Bon ta façon de faire n'est pas super claire mais c'est inhérent à tout le monde (on a toujours l'impression que nos commentaires sont super explicites et que ceux des autres ne le sont pas assez) et je suis sûr qu'en s'y attelant une dizaine de minutes on perçoit facilement ta méthode.
 
Sinon j'ai tapé qq essais

Citation :

C:\temp>a.exe
Calculatrice en notation scientifique.
Limite de caracteres : 50
 
(2+3)*5
25.000000
 
(2+(3*5)+2)
19.000000
 
((2+6)*(1+1))
16.000000
 
^C
C:\temp>
C:\temp>


Et comme tu vois, pour moi zéro souci...
 
Pour l'optimisation bien entendu faut d'abord avoir compris ton algo. Mais ne compte pas sur les macros pour ça car celles-ci sont intégralement retraduites avant compilation.
 
Maintenant (après une seconde lecture) petite erreur que j'ai remarqué dans decp(). Tu mets p à 1 si a > 0 sinon tu mets p à 0 puis tu multiplies ce p "a" fois. Là il y a une maladresse car il faut relire ce code 2 ou 3 fois pour comprendre que dans le cas où a vaut 0, la boucle ne sera pas traitée et la valeur renvoyée sera finalement 0.
 
Une façon d'écrire que je trouve plus claire aurait pu être celle-ci

Code :
  1. int decp(int a)
  2. {
  3.    int i, p;
  4.  
  5.    if (a == 0) return 0;
  6.    for (i=0, p=1; i < a; i++)
  7.        p = p * 10;
  8.    return p;
  9. }


Ainsi je commence toujours par éliminer les cas particuliers ou erronés avant de m'attaquer au cas général. Je sais que le puriste va hurler devant cette fonction ayant plus d'un return mais ma philosophie est de dire qu'un bon programmeur respecte les règles tandis qu'un programmeur brillant les transgresse parfois.
 
Sinon, accessoirement, 10^0=1 ...;)


Message édité par Sve@r le 17-11-2012 à 21:56:10
n°2164450
simius_com​putus
oh Gary boy
Posté le 17-11-2012 à 22:51:36  profilanswer
 

Merci d'avoir pris le temps de regarder ! pour les tests, j'ai dû imaginer pas mal de cas, ce qui m'a amener à compléter le code au fur et à mesure.. La partie chiante quoi, avec des printf partout pour contrôler ce qui se passe.  
 
Effectivement decp() était pas terrible. Je sais pas trop ce que j'ai foutu, pas besoin de cette condition sur p, tout simplement :
 

Code :
  1. int decp(int a)
  2. {
  3.     int i, p = 1;
  4.     for (i = 0; i < a; i++)
  5.         p = p * 10;
  6.     return p;
  7. }


 
Fonctionne très bien.  
J'ai édité mon post, en rajoutant des commentaires qui me semblaient utiles justement autour de l'unique appel à cette fonction, au début de calc() :
 

Code :
  1. if(isdigit(str[i])) //calcule les nombres avec leur partie décimale éventuelle
  2.         {
  3.             if(i > 0 && str[i-1] == ')') //erreur si un nombre suit directement une parenthèse
  4.                 ++error;
  5.             for(j = 0; isdigit(str[i]) && error == 0; i++, j++)
  6.             {
  7.                 curNb = 10 * curNb + (str[i] - '0');
  8.                 if(str[i+1] == '.') //on rencontre un point de décimal
  9.                 {
  10.                     if(decInd == 0) //vérifie que c'est le premier rencontré pour le nombre courant
  11.                     {
  12.                         i++;
  13.                         decInd = j + 1; //mémorise sa place dans le nombre courant
  14.                     }
  15.                     else
  16.                         ++error;
  17.                 }
  18.             }
  19.             calcFormat[k] = (decInd > 0 && decInd != j) ? curNb / (decp(j - decInd)) : curNb; //si on a une partie décimale et qu'elle n'est pas vide (au moins un chiffre après le point), diviser le nombre par 10 puissance le nombre de décimales
  20.             type[k] = 'd'; //l'élément est un nombre
  21.             lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  22.             decInd = 0;
  23.             curNb = 0.0;
  24.             i--;
  25.         }


 
Donc, de toute façon decp() ne peut pas recevoir zéro vu qu'on l'appelle avec pour argument (j - decInd) avec la condition decInd != j   :o
Mais c'est plus cohérent d'avoir une fonction qui renvoie 1 pour 10^0, oui !
 
Sinon, pourquoi c'est mal d'avoir plusieurs return ?


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164452
simius_com​putus
oh Gary boy
Posté le 17-11-2012 à 23:17:56  profilanswer
 

Ah merde, bug détecté. Va falloir ressortir les printf   :/
Je pense que ma méthode est un peu tordue, il doit y avoir des chemins plus simples.


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164453
Farian
Posté le 17-11-2012 à 23:26:17  profilanswer
 

Bonsoir !
 
Vous devriez passer le paramètre MAXLGHT à la fonction "GetStr", car en l'état, si la personne saisit plus de caractères que prévu, vous obtenez un dépassement mémoire, alors que vous pourriez facilement faire le test dans la fonction GetStr pour régler le problème à la source.
 
Bon courage pour votre bug !

n°2164454
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 00:25:25  profilanswer
 

Salut,
Effectivement, je vais modifier GetStr, merci pour la remarque !
Et j'ai déniché le bug : une simple histoire de variables temporaires pas remises à zéro, demain je posterai le code corrigé
 
Au fait, y a-t-il un moyen de coller du texte dans ma console, à partir d'une expression copiée dans windows ?


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164460
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 09:54:09  profilanswer
 

Version corrigée :

 
Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #define MAXLGHT 50 //taille autorisée pour la saisie
  5. int getStr(char []); //enregistre la saisie jusqu'à \n en ignorant les espaces, renvoie le nombre de caractères (sauf \n)
  6. double calc(char [], int); //traite la saisie, repère les erreurs de syntaxe, et gère l'exécution du calcul par niveaux avant de renvoyer le résultat final
  7. int decp(int); //renvoie 10 puissance argument, utilisée pour lire les nombres dans la saisie
  8. double lvlCalc(double*, double*, char*, int*); //renvoie le résultat de calcul sur un niveau de parenthèses en gérant la priorité des opérateurs et d'éventuelles divisions par zéro
  9. int main()
  10. {
  11.     int i;
  12.     char read[MAXLGHT]; //stocke la saisie brute
  13.     printf("Calculatrice en notation scientifique.\nLimite de caracteres : %d\n\n", MAXLGHT);
  14.     for(;;)
  15.     {
  16.         i = getStr(read);
  17.         if(i <= MAXLGHT)
  18.             printf("%f\n\n",calc(read, i)); //appelle calc si la saisie ne dépasse pas la taille autorisée
  19.         else
  20.             printf("depassement : %d caracteres max\n\n", MAXLGHT);
  21.     }
  22.     return 0;
  23. }
  24. int getStr(char c[])
  25. {
  26.     char temp;
  27.     int i = 0;
  28.     for(;;)
  29.         if((temp = getchar()) != '\n')
  30.             if(i < MAXLGHT)
  31.                 c[(isspace(temp)) ? i : i++] = temp;
  32.             else
  33.                 i++;
  34.         else
  35.             break;
  36.     c[i] = '\0';
  37.     return i;
  38. }
  39. int decp(int a)
  40. {
  41.     int i, p = 1;
  42.     for (i = 0; i < a; i++)
  43.         p = p * 10;
  44.     return p;
  45. }
  46. double calc(char str[], int cSize)
  47. {
  48.     double result = 0.0; //stocke résultat final
  49.     double curNb = 0.0; //variable temp pour lecture des nombres
  50.     double calcFormat[cSize]; //stocke la saisie sous sa forme calculable, opérateurs et opérandes uniquement
  51.     int lvls[cSize]; //stocke les niveaux de parenthèses de chaque opérateur ou opérande
  52.     char type[cSize]; //détermine la nature de chaque élément de calcFormat : 'o' pour opérateur, 'd' pour nombre, 'v' pour à ignorer (déjà pris en compte dans un niveau supérieur)
  53.     int zdiv = 0; //division par zéro
  54.     int decInd = 0; //variable temp pour calcul des nombres à partie décimale
  55.     int curLvl = 1; //niveau de parenthèses en cours de traitement
  56.     int topLvl = 1; //plus grand niveau de parenthèses (on commence par là)
  57.     int error = 0; //erreur(s)
  58.     int i, j, k = 0; //indices
  59.     for(i = 0; i < cSize && error == 0; i++) //construit calcFormat[], lvls[], type[], repère les erreurs de syntaxe
  60.     {
  61.         if(isdigit(str[i])) //calcule les nombres avec leur partie décimale éventuelle
  62.         {
  63.             if(i > 0 && str[i-1] == ')') //erreur si un nombre suit directement une parenthèse
  64.                 ++error;
  65.             for(j = 0; isdigit(str[i]) && error == 0; i++, j++)
  66.             {
  67.                 curNb = 10 * curNb + (str[i] - '0');
  68.                 if(str[i+1] == '.') //on rencontre un point de décimal
  69.                 {
  70.                     if(decInd == 0) //vérifie que c'est le premier rencontré pour le nombre courant
  71.                     {
  72.                         i++;
  73.                         decInd = j + 1; //mémorise sa place dans le nombre courant
  74.                     }
  75.                     else
  76.                         ++error;
  77.                 }
  78.             }
  79.             calcFormat[k] = (decInd > 0 && decInd != j) ? curNb / (decp(j - decInd)) : curNb; //si on a une partie décimale et qu'elle n'est pas vide (au moins un chiffre après le point), diviser le nombre par 10 puissance le nombre de décimales
  80.             type[k] = 'd'; //l'élément est un nombre
  81.             lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  82.             decInd = 0;
  83.             curNb = 0.0;
  84.             i--;
  85.         }
  86.         else if(str[i] == '(') //saute les parenthèses ouvrantes et incrémente le niveau en conséquence, repère d'éventuelles erreurs de syntaxe
  87.         {
  88.             if(i == 0 || (i > 0 && i < cSize - 1 && str[i-1] != ')' && !isdigit(str[i-1])))
  89.             {
  90.                 ++curLvl;
  91.                 if(curLvl > topLvl) //si le niveau est plus grand que le plus grand rencontré, mettre à jour ce dernier
  92.                     topLvl = curLvl;
  93.             }
  94.             else
  95.                 ++error;
  96.         }
  97.         else if(str[i] == ')') //saute les parenthèses fermantes et décrémente le niveau en conséquence, repère d'éventuelles erreurs de syntaxe
  98.         {
  99.             if(i > 0 && str[i-1] != '(' && str[i-1] != '+' && str[i-1] != '-' && str[i-1] != '*' && str[i-1] != '/')
  100.                 --curLvl;
  101.             else
  102.                 ++error;
  103.         }
  104.         else if(str[i] == '+' || str[i] == '*' || str[i] == '/') //les opérateurs +, * et / ont les mêmes règles de syntaxe
  105.         {
  106.             if(i > 0 && i < cSize - 1 && (isdigit(str[i-1]) || str[i-1] == ')'))
  107.             {
  108.                 calcFormat[k] = str[i];
  109.                 type[k] = 'o'; //l'élément est un opérateur
  110.                 lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  111.             }
  112.             else
  113.                 ++error;
  114.         }
  115.         else if(str[i] == '-') //règle de syntaxe pour l'opérateur -
  116.         {
  117.             if((i > 0 && i < cSize - 1 && (isdigit(str[i-1]) || str[i-1] == ')' || str[i-1] == '(')) || (i == 0 && cSize > 1))
  118.             {
  119.                 calcFormat[k] = str[i];
  120.                 type[k] = 'o'; //l'élément est un opérateur
  121.                 lvls[k++] = curLvl; //le niveau de l'élément est le niveau courant
  122.             }
  123.             else
  124.                 ++error;
  125.         }
  126.         else //ni un nombre, ni une parenthèse, ni un opérateur
  127.             ++error;
  128.     }
  129.     calcFormat[k] = '\0';
  130.     lvls[k] = '\0';
  131.     type[k] = '\0';
  132.     if(curLvl != 1) //si il n'y a pas autant de '(' que de ')'
  133.         ++error;
  134.     if(error == 0) //si pas d'erreur
  135.     {
  136.         int left, right; //champ d'action de lclCalc dans calcFormat[]
  137.         for(; topLvl >= 1; topLvl--) //examine chaque niveau du plus élevé à 1
  138.         {
  139.             //printf("\nlevel %d\n",topLvl);
  140.             for(i = 0; i < k; i++) //repère les parties correspondant au niveau topLvl
  141.             {
  142.                 for(; lvls[i] < topLvl; i++) //saute les niveaux inférieurs
  143.                     ;
  144.                 left = i;
  145.                 for(; lvls[i] >= topLvl; i++) //détermine la plage à prendre en compte, qui sera encadrée par left et right
  146.                     ;
  147.                 right = i-1;
  148.                 //printf("left = %d  right = %d\n",left,right);
  149.                 result = lvlCalc(&calcFormat[left], &calcFormat[right], &type[left], &zdiv); //calcule le niveau en cours
  150.                 calcFormat[left] = result; //stocke le résultat à gauche
  151.                 --lvls[left]; //décrémente le niveau de l'élément contenant le résultat afin qu'il soit pris en compte par le niveau suivant
  152.                 if(zdiv) //lvlCalc a indiqué une division par zéro
  153.                 {
  154.                     printf("division par zero !\n" );
  155.                     return 0.0;
  156.                 }
  157.             }
  158.             //for(i=0;i<k;i++)
  159.                 //printf("val = %f  lvl = %d  type = %c\n",calcFormat[i],lvls[i],type[i]);
  160.         }
  161.     }
  162.     else
  163.         printf("erreur de syntaxe\n" );
  164.     return result;
  165. }
  166. double lvlCalc(double* start, double* end, char* opCheck, int* zdiv)
  167. {
  168.     double result = 0.0; //résultat pour la plage donnée à calculer
  169.     double* stemp = start; //compteur pour la 1ère boucle, pointe sur les éléments de calcFormat[]
  170.     double* first = start; //garde en mémoire l'élément de gauche
  171.     char* opStart = opCheck; //compteur pour la 1ère boucle, pointe sur les éléments de type[]
  172.     int leftSp, rightSp; //variables pour le saut les éléments de type 'v' situés autour des opérateurs * et /
  173.     for(; stemp <= end; stemp++, opStart++) //première boucle sur l'étendue indiquée
  174.     {
  175.         if(*stemp == '*' && *opStart == 'o') //rencontre un opérateur *
  176.         {
  177.             for(leftSp = 0; *(opStart-1-leftSp) == 'v'; leftSp++) //saute les éléments de type 'v' à gauche
  178.                 ;
  179.             for(rightSp = 0; *(opStart+1+rightSp) == 'v'; rightSp++) //saute les éléments de type 'v' à droite
  180.                 ;
  181.             *(stemp-1-leftSp) = *(stemp-1-leftSp) * *(stemp+1+rightSp); //stocke le résultat dans l'opérande de gauche
  182.             *opStart = 'v'; //indique l'opérateur comme déjà utilisé
  183.             *(opStart+1+rightSp) = 'v'; //indique l'opérande de droite comme déjà utilisé
  184.             opStart += 1+rightSp; //saute la plage qu'on vient de calculer
  185.             stemp += 1+rightSp; //pareil avec l'autre indice
  186.         }
  187.         else if(*stemp == '/' && *opStart == 'o') //rencontre un opérateur / (même méthode que pour *)
  188.         {
  189.             for(leftSp = 0; *(opStart-1-leftSp) == 'v'; leftSp++)
  190.                 ;
  191.             for(rightSp = 0; *(opStart+1+rightSp) == 'v'; rightSp++)
  192.                 ;
  193.             if(*(stemp+1+rightSp) != 0) //opérande de droite != 0
  194.                 *(stemp-1-leftSp) = *(stemp-1-leftSp) / *(stemp+1+rightSp);
  195.             else //division par zéro
  196.                 {
  197.                     *zdiv = 1;
  198.                     return 0.0;
  199.                 }
  200.             *opStart = 'v';
  201.             *(opStart+1+rightSp) = 'v';
  202.             opStart += 1+rightSp;
  203.             stemp += 1+rightSp;
  204.         }
  205.     } //les opérations prioritaires ont été effectuées, reste que des additions et soustractions dans l'étendue indiquée
  206.     if(*opCheck == 'd') //additionne au résultat l'élément tout à gauche si c'est un nombre (ça pourrait être un opérateur -)
  207.         result += *start;
  208.     for(; start <= end; start++, opCheck++) //seconde boucle sur l'étendue indiquée
  209.     {
  210.         if(*start == '+' && *opCheck == 'o') //rencontre un opérateur +
  211.         {
  212.             for(; *(opCheck+1) == 'v'; opCheck++, start++) //saute les éléments déjà utilisés à droite jusqu'à rencontrer un opérande
  213.                 ;
  214.             result += *(start+1); //additionne l'opérande au résultat
  215.             *opCheck = 'v'; //l'opérateur est marqué comme déjà utilisé
  216.             *(opCheck+1) = 'v'; //l'opérande est marqué comme déjà utilisé
  217.         }
  218.         if(*start == '-' && *opCheck == 'o') //même principe pour -
  219.         {
  220.             for(; *(opCheck+1) == 'v'; opCheck++, start++)
  221.                 ;
  222.             result -= *(start+1);
  223.             *opCheck = (start > first)?'v':'d'; //comme l'opérateur - peut se trouver en premier élément, on veille à le marquer comme nombre pour que le résultat stocké dedans ne soit pas ignoré par les niveaux suivants
  224.             *(opCheck+1) = 'v';
  225.         }
  226.     }
  227.     return result;
  228. }
 

Après moult tests sur des calculs bien fournis, je pense que cette version est correcte.
Il faudrait ajouter quelques opérateurs comme racine carrée et fonctions trigo mais pfff.. On verra plus tard   [:clooney9]


Message édité par simius_computus le 18-11-2012 à 10:21:47

---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164461
Farian
Posté le 18-11-2012 à 10:15:19  profilanswer
 

Tout d'abord bravo pour votre apprentissage réussi !
 
J'émets toutefois quelques doutes sur la capacité à rajouter beaucoup de fonctionnalités, notamment à cause de l'analyse syntaxique faite "à la main". Si vous voulez réellement poursuivre dans cette voie, je ne saurais que vous conseiller de vous tourner vers des outils particulièrement adaptés : lex/yacc (ou flex/bison, en version GNU, j'ai l'habitude d'utiliser la vieille dénomination UNIX), qui permettent de faire de l'analyse syntaxique/grammaticale.  La programmation d'une calculatrice est d'ailleurs l'un des premiers exercices pour ces outils.
 
Mais cela déborde peut-être (sûrement ?) de votre but, qui est de vous mettre au C.
 
Bon courage en tous cas !

n°2164463
Profil sup​primé
Posté le 18-11-2012 à 10:47:31  answer
 

Je préfère les balise C pour le code C.
/Forte tête.

n°2164465
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 10:58:42  profilanswer
 

Farian a écrit :

Tout d'abord bravo pour votre apprentissage réussi !

 

J'émets toutefois quelques doutes sur la capacité à rajouter beaucoup de fonctionnalités, notamment à cause de l'analyse syntaxique faite "à la main". Si vous voulez réellement poursuivre dans cette voie, je ne saurais que vous conseiller de vous tourner vers des outils particulièrement adaptés : lex/yacc (ou flex/bison, en version GNU, j'ai l'habitude d'utiliser la vieille dénomination UNIX), qui permettent de faire de l'analyse syntaxique/grammaticale.  La programmation d'une calculatrice est d'ailleurs l'un des premiers exercices pour ces outils.

 

Mais cela déborde peut-être (sûrement ?) de votre but, qui est de vous mettre au C.

 

Bon courage en tous cas !

 

Merci  ;)

 

J'ai regardé un peu la doc sur cet outil, c'est clair que ça doit simplifier vachement.
Mon truc ça reste un exercice, pour appliquer les bases, manipuler les chaînes, les tableaux, un peu de manips sur les pointeurs..
Pour le moment je découvre les possibilités du langage, il faudrait que j'installe une partition linux déjà  :o
Rien qu'avec la librairie standard il y a de quoi faire, après j'aurai probablement envie de développer des applis graphiques, on verra  :D

 

Je pense faire un bts IRIS l'an prochain en alternance, ça devrait être plus facile de trouver une bonne boîte en ayant déjà des acquis.


Message édité par simius_computus le 18-11-2012 à 10:59:00

---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
mood
Publicité
Posté le 18-11-2012 à 10:58:42  profilanswer
 

n°2164466
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 11:00:58  profilanswer
 


 
Où en est ton IA ?  :o


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164467
Profil sup​primé
Posté le 18-11-2012 à 11:11:22  answer
 

simius_computus a écrit :


 
Où en est ton IA ?  :o


 
J'écris un compositeur pour instrument MIDI actuellement.
Celui ci exploite les réseaux de neurones.
Si non, il y a jovalise.net, toujours au même point.

n°2164468
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 11:43:44  profilanswer
 

le jovalise.net n'a pas changé effectivement
 

Citation :


Votre requête
 
Bonjour monsieur.
 
Ma réponse
 
rassasiées retournerais


 
 [:marllt2]  
 
Je suis curieux de savoir comment tu procèdes, avoue, c'est juste du random sur une banque de mots ?  :o  
Appliqué à la composition de musique ça peut donner des trucs intéressants remarque


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164470
Profil sup​primé
Posté le 18-11-2012 à 11:46:12  answer
 

Du tout. ça passe réellement par un réseau de neurone.
L'aléatoire en musique... C'est pas la panacée.

n°2164472
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 11:48:57  profilanswer
 

Mais comment ton machin apprend-il ?
On ne peut pas lui signaler ses incohérences.


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164473
Profil sup​primé
Posté le 18-11-2012 à 11:56:02  answer
 

simius_computus a écrit :

Mais comment ton machin apprend-il ?
On ne peut pas lui signaler ses incohérences.


 
Il a d'abord appris un ficher d'exemple. puis au bout d'un certain nombre de requête il repart en apprentissage avec les requête et les réponse qu'il a donné.

n°2164481
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 12:32:38  profilanswer
 

Je ne connais rien en réseaux de neurones, mais ça m'intéresse. Tout ce qui est IA, apprentissage   [:zero pm:5]
 
(pour la théorie musicale, par contre je connais  :o )


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2164491
Sve@r
Posté le 18-11-2012 à 14:12:45  profilanswer
 

simius_computus a écrit :

pour les tests, j'ai dû imaginer pas mal de cas, ce qui m'a amener à compléter le code au fur et à mesure..


Aïe, ça c'est embêtant. Parce qu'en procédant ainsi, tu risques de rater certains cas...
 

simius_computus a écrit :

Ah merde, bug détecté. Va falloir ressortir les printf   :/


Et voilà
 

simius_computus a écrit :

Je pense que ma méthode est un peu tordue, il doit y avoir des chemins plus simples.


Peut-être. Par exemple qu'est-ce qu'une expression ? C'est
1: nombre opérande nombre => 2 + 2
Ou bien
2: nombre opérande "définition 1" => 2 + 3 + 4 => 2 + 3 + 4 + 5 ...
Ou bien
3: ( "définition 2" ) => (2 + 3 + 4 + 5)
 
En utilisant la définition 3, qui elle-même se base sur la définition 2 qui est basée sur la définition 1, tu couvres tous les cas possibles. Imagine donc une fonction ayant pour but de calculer le résultat d'une expression définie en 2 (que des nombres et des opérandes) et qui, dès qu'elle détecte une parenthèse, se met en attente du résultat de ce qu'il y a entre parenthèses avant de continuer. Et ce résultat pourrait être donné par un clone de cette même fonction mais exécuté dans un sous-contexte.
Ben toute cette manipulation est rendue possible par l'utilisation astucieuse de la récursivité. Avec en amont de tout ça une première fonction dédiée à vérifier la syntaxe générale (surtout au niveau de la parité des parenthèses) et là tu es certain que ton code couvre toutes les combinaisons...
 
Et, accessoirement, il a été cité dans ce topic lex et yacc, outils justement dédiés à ce genre de problème. Tu décris dans un fichier texte comment tu définis une expression (comme je l'ai fait au dessus) et yacc génère automatiquement le code C correspondant pour traiter une expression. Et lex te permet de programmer le vérificateur de syntaxe. Malheureusement ces outil sont issus du monde Unix et je ne sais pas s'ils existent pour zindow. Mais bon, rien n'interdit de programmer tout ça manuellement surtout si c'est pour se faire un bon exercice...


Message édité par Sve@r le 18-11-2012 à 14:32:38

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°2164497
simius_com​putus
oh Gary boy
Posté le 18-11-2012 à 14:59:38  profilanswer
 

La récursion en partant du bas (1er niveau dans les parenthèses), ouais.. Moi j'ai procédé à l'inverse :

 

1- chercher la ou les expression(s) appartenant au dernier niveau;
2- calculer le(s) résultat(s) et le(s) placer à gauche dans l'expression correspondante, les autres éléments de l'expression étant marqués comme à ignorer pour la suite;
3- décrémenter la valeur "dernier niveau" et retourner à l'étape 1, ou terminer si on a parcouru tous les niveaux

 

A mon avis ce système est gourmand avec des boucles qui parcourent l'ensemble de la chaîne, à voir si la récursion offre un avantage, en tout cas j'ai pas dû prendre les options les plus efficaces c'est clair.
C'est dans les détails du calcul de chaque expression que j'ai eu des problèmes de cas particuliers à détecter, pour le dernier bug c'est une étourderie qui avait la mauvaise idée de se compenser d'elle-même dans la majorité des cas   [:fabriceboue]

 

Je compte pas m'éterniser sous windows  :D

 

Je vais essayer d'autres trucs, et reviendrai sur ce code probablement plus tard pour trouver plus élégant. Merci pour les infos  ;)


Message édité par simius_computus le 18-11-2012 à 15:01:20

---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2165074
rufo
Pas me confondre avec Lycos!
Posté le 22-11-2012 à 11:14:53  profilanswer
 

Lex/yacc, bonne idée. Si c'est dans un but d'apprentissage, cet article sur la grammaire LL devrait t'aider : http://fr.wikipedia.org/wiki/Analyse_LL
 
Un codage à base d'arbre serait pas mal : tu décomposes ton expression en feuilles (nombres) et les noeuds sont les opérateurs.
 
J'ai un souci avec ton for( ; ; ) qui pourrait être remplacé de manière plus lisible (à mon avis) par un while. D'un point de vue purement algorithmique, c'est plus logique, donc probablement plus lisible ;)
 
mais c'est du très bon niveau pour qq'un qui pratique le C depuis qq mois seulement :jap:

Message cité 1 fois
Message édité par rufo le 22-11-2012 à 11:15:20

---------------
Astres, outil de help-desk GPL : http://sourceforge.net/projects/astres, ICARE, gestion de conf : http://sourceforge.net/projects/icare, Outil Planeta Calandreta : https://framalibre.org/content/planeta-calandreta
n°2165079
gilou
Modérateur
Modzilla
Posté le 22-11-2012 à 11:36:22  profilanswer
 

Simius,
Pour quelqu'un qui a démarré le C en Septembre, ce que tu as fait est très bien.
Ne t'inquiètes pas du commentaires 'c'est mieux avec lex/yacc (ou flex/bison plutôt)' ou  de celui critiquant ton 'ce qui m'a amener à compléter le code au fur et à mesure', quand on a démarré la programmation, on a tous procédé ainsi, les manières pour mieux faire, on les apprends avec l'expérience (qui permet de comprendre pourquoi une méthode est meilleure qu'une autre).

 

Une petite remarque: quand tu veux auto-incrémenter une valeur, pré-incrémentes la: ++i
N'utilises la post-incrémentation (i++) que quand ça a un sens dans le programme de d'abord évaluer la valeur puis de l'incrémenter (j = i++ etc).
C'est une bonne habitude à prendre dès le début (et autrefois, de plus, sur certaines architectures, la pré-incrémentation était plus rapide).

 

Bon, je vais lire le code un peu plus en détail...

 

A+,


Message édité par gilou le 22-11-2012 à 11:45:15

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2165092
gilou
Modérateur
Modzilla
Posté le 22-11-2012 à 12:47:01  profilanswer
 

Bon, alors ce qui ne me plait pas dans ce code:
 
- Il n'est pas prévu de sortir du programme autrement que avec Ctrl+C apparemment. Le faire sur une ligne entrée vide me semblerait logique.
- int getStr(char c[]) Tu passes une variable cachée à cette fonction, MAXLGHT.
   définis la plutôt comme int getStr(char c[], int maxlen) et appelles la avec i = getStr(read, MAXLGHT);
   Note: une autre définition possible pourrait être int getStr(char (*c)[MAXLGHT]); avec un appel i = getStr(&read); mais c'est un niveau un poil plus avancé, ou on dit explicitement que le paramètre est l'adresse d'un tableau de MAXLGHT chars.
 
Bon, je vais manger.
 
Bon, il y a sans doute des choses à améliorer dans l'algo, car en traçant un peu:
/* * */ printf("left = %f  right = %f  type = %c  ", calcFormat[left], calcFormat[right], type[left]);
result = lvlCalc(&calcFormat[left], &calcFormat[right], &type[left], &zdiv); //calcule le niveau en cours
/* * */ printf("result = %f\n", result);
je vois ceci, avec un appel inutile manifestement:
1+(2.1*3)-2
left = 2.100000  right = 3.000000  type = d  result = 6.300000
left = 0.000000  right = 0.000000  type = ¶  result = 0.000000
left = 1.000000  right = 2.000000  type = d  result = 5.300000
5.300000
 
il pourrait peut être aussi être moins strict sur ce qui passe en entrée:
+2
erreur de syntaxe
0.000000
 
3 * -1
erreur de syntaxe
0.000000
 
A+,

Message cité 1 fois
Message édité par gilou le 22-11-2012 à 14:40:38

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2165177
simius_com​putus
oh Gary boy
Posté le 22-11-2012 à 17:45:19  profilanswer
 

Merci pour votre expertise  :jap:
 

rufo a écrit :

Lex/yacc, bonne idée. Si c'est dans un but d'apprentissage, cet article sur la grammaire LL devrait t'aider : http://fr.wikipedia.org/wiki/Analyse_LL
 
Un codage à base d'arbre serait pas mal : tu décomposes ton expression en feuilles (nombres) et les noeuds sont les opérateurs.
 
J'ai un souci avec ton for( ; ; ) qui pourrait être remplacé de manière plus lisible (à mon avis) par un while. D'un point de vue purement algorithmique, c'est plus logique, donc probablement plus lisible ;)
 
mais c'est du très bon niveau pour qq'un qui pratique le C depuis qq mois seulement :jap:


 
Quel for( ; ; ) ? J'en ai mis deux, conscient que c'était une solution pas forcément élégante   :whistle:  
Dans main() je pourrais le remplacer par un truc qui met fin au programme comme l'a suggéré Gilou.
Pour la grammaire, je regarde ça, intéressant mais c'est quand même assez abstrait   [:altherac:1]
(wikipédia ne m'a jamais semblé didactique)
 
Je note pour la place de l'incrément, c'est en effet logique.
 
En quoi l'utilisation de MAXLGHT est-elle gênante dans getStr ? ("variable cachée" ?)
 
Alors pour l'erreur dans ton traçage, je crois avoir remarqué ce truc avant mais j'ai oublié de chercher une correction vu que ça n'empêchait pas le fonctionnement.
Un problème de référence à des éléments de tableau pas encore définis je pense. Vais essayer d'arranger ça !


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2165183
simius_com​putus
oh Gary boy
Posté le 22-11-2012 à 18:22:07  profilanswer
 

gilou a écrit :


je vois ceci, avec un appel inutile manifestement:
1+(2.1*3)-2
left = 2.100000  right = 3.000000  type = d  result = 6.300000
left = 0.000000  right = 0.000000  type = ¶  result = 0.000000
left = 1.000000  right = 2.000000  type = d  result = 5.300000
5.300000


 
Bon, c'est corrigé, quelques conditions en plus dans la boucle qui appelle lvlCalc() :
 

Code :
  1. for(i = 0; i < k; i++) //repère les parties correspondant au niveau topLvl
  2.             {
  3.                 for(; lvls[i] < topLvl && i < k; i++) //saute les niveaux inférieurs
  4.                     ;
  5.                 if(i == k)
  6.                     break;
  7.                 left = i;
  8.                 for(; lvls[i] >= topLvl; i++) //détermine la plage à prendre en compte, qui sera encadrée par left et right
  9.                     ;
  10.                 right = i-1;
  11.                 result = lvlCalc(&calcFormat[left], &calcFormat[right], &type[left], &zdiv); //calcule le niveau en cours
  12.                 calcFormat[left] = result; //stocke le résultat à gauche
  13.                 --lvls[left]; //décrémente le niveau de l'élément contenant le résultat afin qu'il soit pris en compte par le niveau suivant
  14.                 if(zdiv) //lvlCalc a indiqué une division par zéro
  15.                 {
  16.                     printf("division par zero !\n" );
  17.                     return 0.0;
  18.                 }
  19.             }


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2165209
Farian
Posté le 22-11-2012 à 22:05:15  profilanswer
 

Citation :


En quoi l'utilisation de MAXLGHT est-elle gênante dans getStr ? ("variable cachée" ?)


 
La variable est cachée dans le sens où vous déclarez votre tableau avec cette taille-là, mais vous ne l'utilisez pas dans la fonction getStr, puis vous comparez le résultat à cette valeur en sortie de la fonction.
 
Si l'utilisateur rentre une "phrase" trop longue, vous aurez tout d'abord un écrasement mémoire dans la fonction getStr à cause du dépassement du nombre de valeurs allouées, puis, si le dépassement n'a pas tout déstabilisé, vous affichez une erreur en disant que le nombre maximum de caractères autorisés est dépassé, mais le mal est (peut-être) déjà fait.


Message édité par Farian le 22-11-2012 à 22:06:00
n°2165213
simius_com​putus
oh Gary boy
Posté le 22-11-2012 à 23:10:54  profilanswer
 

Pourtant j'utilise MAXLGHT dans getStr()
 

Code :
  1. int getStr(char c[])
  2. {
  3.     char temp;
  4.     int i = 0;
  5.     for(;;)
  6.         if((temp = getchar()) != '\n')
  7.             if(i < MAXLGHT)
  8.                 c[(isspace(temp)) ? i : i++] = temp;
  9.             else
  10.                 i++;
  11.         else
  12.             break;
  13.     c[i] = '\0';
  14.     return i;
  15. }


 
En toute logique, si l'utilisateur dépasse MAXLGHT caractères en entrée, le tableau passé en argument ne sera plus rempli, seul i sera incrémenté non ?
Je pense qu'il y a un truc que je ne saisis pas..


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
n°2165218
Farian
Posté le 22-11-2012 à 23:58:08  profilanswer
 

En effet, j'avais mal vu ! La façon de faire n'est pas la plus élégante (pour que la fonction soit plus facilement réutilisable, il faudrait passer la taille à laquelle la chaîne a été allouée en paramètre à la fonction getStr).

n°2165219
gilou
Modérateur
Modzilla
Posté le 22-11-2012 à 23:59:38  profilanswer
 

Justement, tu l'utilises alors que c'est une variable externe à ta fonction. Ta variable est cachée: c'est un paramètre de ta fonction (modifier sa valeur modifie le comportement de ta fonction), mais elle n'est pas déclarée dans la liste des paramètres de ta fonction.
C'est une mauvaise habitude de ne pas expliciter tous les paramètres d'une fonction. Sur un petit programme comme cela, ça semble anodin, mais avoir ce genre de pratique finit toujours par jouer des tours.

 

Tu pouvais soit déclarer

Code :
  1. int getStr(char (*c)[MAXLGHT])
  2. {
  3.     char temp;
  4.     int i = 0;
  5.     for(;;)
  6.         if((temp = getchar()) != '\n')
  7.             if(i < sizeof (*c))
  8.                 (*c)[(isspace(temp)) ? i : i++] = temp;
  9.             else
  10.                 i++;
  11.         else
  12.             break;
  13.     (*c)[i] = '\0';
  14.     return i;
  15. }


et faire un appel i = getStr(&read);
C'est complexe, mais c'est la manière dont il faut déclarer le paramètre afin que sizeof retourne la taille effective du tableau.

 

ou bien tu peux faire avec le paramètre explicite:

Code :
  1. int getStr(char c[], int maxlen)
  2. {
  3.     char temp;
  4.     int i = 0;
  5.     for(;;)
  6.         if((temp = getchar()) != '\n')
  7.             if(i < maxlen)
  8.                 c[(isspace(temp)) ? i : i++] = temp;
  9.             else
  10.                 i++;
  11.         else
  12.             break;
  13.     c[i] = '\0';
  14.     return i;   
  15. }
 

et faire un appel i = getStr(read, MAXLGHT);

 

A+,


Message édité par gilou le 23-11-2012 à 00:05:15

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2165223
gilou
Modérateur
Modzilla
Posté le 23-11-2012 à 00:28:35  profilanswer
 

Et en remplacement de ton gerStr, pour lire l'input utilisateur, tu peux sauvegarder cette fonction 'la plus blindée possible' dans ta bibliothèque de code perso:
 

Code :
  1. int read_input(char *s, int n) {
  2.     int last = 0;
  3.     if (n > 0) {
  4.         char *p;
  5.         if ((p = fgets(s, n, stdin))) {
  6.             last = strlen(s) - 1;
  7.             if (s[last] == '\n') {
  8.                 s[last] = '\0';
  9.             }
  10.             else {
  11.                 scanf("%*[^\n]" );
  12.                 getchar();
  13.                 last = n - 1;
  14.             }
  15.         }
  16.     }
  17.     return last;
  18. }


que tu appelles avec
char buffer[BUFSIZE];
.....
read_input(buffer, sizeof buffer);
 
et qui copiera dans buffer au plus les BUFSIZE-1 premiers caractères entrés par l'utilisateur, ajoute un  \0 en dernière position si nécessaire, et nettoiera les caractères restant dans le buffer d'entrée. La valeur retournée est le nombre de caractères copiés dans buffer.
 
Note: la variante suivante

Code :
  1. int read_input(char *s, int n) {
  2.     int last = 0;
  3.     if (n > 0) {
  4.         char *p;
  5.         if ((p = fgets(s, n, stdin))) {
  6.             last = strlen(s) - 1;
  7.             if (s[last] == '\n') {
  8.                 s[last] = '\0';
  9.             }
  10.             else {
  11.                 int m = 0;
  12.                 scanf("%*[^\n]%n", &m);
  13.                 getchar();
  14.                 last = n + m - 1;
  15.             }
  16.         }
  17.     }
  18.     return last;
  19. }


fait la même chose (au cas n = 0 près, qui n'a guère de sens), mais a pour valeur de retour le nombre de caractères tapés par l'utilisateur (ce qui permet de savoir s'il a dépassé la capacité autorisée).
 
A+,


Message édité par gilou le 23-11-2012 à 11:51:17

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2165237
simius_com​putus
oh Gary boy
Posté le 23-11-2012 à 10:02:56  profilanswer
 

D'accord, j'ai compris. Merci   :jap:
 
Faudra que je lise la doc sur la bibli standard, pour le moment je suis jamais sorti des printf et getchar   :D


---------------
IWH  ---  Le forum de toute une génération : http://losersiv.1fr1.net (losers, sans-ami, dépressifs, allez on va faire cette merde)
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Calculatrice notation scientifique

 

Sujets relatifs
Erreur Calculatricecalculatrice textuelle
Systeme de notationMettre cours sur calculatrice
recuperer une police d une calculatriceNotation romaine décroissante en langage C
calculatrice flottante en javaAccès à un array dans un objet / notation
Acheter une solution de type "notation des produits par le public"lire un nombre en notation scientifique dans un fichier
Plus de sujets relatifs à : Calculatrice notation scientifique


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR