fork download
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <math.h>
  6. #define LENGTH(x) (sizeof(x) / sizeof(x[0]))
  7.  
  8. int hasPar (char *); //Überprüft, ob Klammern im String sind und gibt Position der ersten Klammer zurück
  9. char* subStr (char* , char* , int , int ); //Funktion, die Substring zurückgibt
  10. double calcStr(char *); //Wertet Terme ohne Klammern aus
  11. double calc (char *); //Rekursive Berechnung des Terms
  12.  
  13.  
  14. int main(/*int argc, char *argv[]*/) {
  15. char *s/*, c*/;
  16. double ergebnis;
  17.  
  18. do {
  19. puts("Taschenrechner. Ignoriert alles, au\xe1""er 0-9,.,+,-,*,/,^,(,)");
  20.  
  21. fflush(stdin);
  22. s= calloc(100,1);
  23. scanf("%99[^\n]", s); //[^\n] bedeutet, dass alle Zeichen außer Zeilenumbruch eingelesen werden sollen
  24.  
  25. printf("Erkannter Ausdruck:\n%s\n", s);
  26.  
  27. ergebnis= calc(s);
  28. printf("Berechnetes Ergebnis:\n%f\n", ergebnis);
  29.  
  30.  
  31. puts("Erfolg!");;
  32. free(s);
  33. fflush(stdin);
  34. //if (getc(stdin) == 'c') {break;}
  35. } while (0);
  36.  
  37. return 0;
  38. }
  39.  
  40.  
  41.  
  42. /*************************************
  43. * Überprüfen, ob Klammern im Term sind
  44. * gibt Position der ersten Klammer
  45. * oder -1 zurück
  46. **************************************/
  47. int hasPar (char *s) {
  48. for (unsigned int k=0; k<strlen(s); k++) { //k verwendet, da mit i Interferenzen mit calc() aufgetreten sind
  49. if ( s[k] == '(' ) {
  50. return k;
  51. }
  52. }
  53.  
  54. return (-1);
  55. }
  56.  
  57.  
  58. /*****************************************************
  59. * Funktion, die Substring zurückgibt
  60. * s: Ursprungsstring
  61. * offset: Position, an der Substring beginnt
  62. * len: Länge des Substrings
  63. * t: Variable, in der Substring gespeichert wird
  64. ******************************************************/
  65. char* subStr (char* dest, char* src, int offset, int len) {
  66. int input_len = strlen (src);
  67.  
  68. if ( offset+len > input_len ) { //Wenn Substring größer sein sollte als Usprungsstring oder Substring Null Zeichen enthalten soll
  69. return NULL;
  70. } else if (len <= 0) {
  71. dest[0]= '\0';
  72. }
  73.  
  74. strncpy(dest, src + offset, len); //len Zeichen werden aus s ab offset in t kopiert
  75. dest[len]= '\0';
  76. return dest;
  77. }
  78.  
  79.  
  80. /*****************************************************
  81. * Wertet Terme ohne Klammern aus
  82. ******************************************************/
  83. double calcStr (char *s) {
  84. char *t, *t_first;
  85. int len_s= strlen(s), len_first=0;
  86. t= calloc(len_s, sizeof(char)); //Kopie von s zum Arbeiten erstellen, Schritt 1
  87. strcpy(t,s); //Kopie von s zum Arbeiten erstellen, Schritt 2
  88.  
  89. //ACHTUNG: REIHENFOLGE WICHTIG FÜR KORREKTE ANWENDUNG VON RECHENREGELN
  90.  
  91. if(t[0] != '+') { //+ als unärer Operator
  92. t_first= strtok(t,"+"); //String auf + prüfen, Nach Ausführung von strtok: t_first: String bis exklusiv +
  93. len_first=strlen(t_first); //Länge des Ergebnisstrings berechnen zum Vergleich mit Länge des Ursprungsstrings
  94. if (len_first != len_s) { //Wenn Länge gleich, dann ist hier auch der Inhalt gleich, also kein Plus enthalten
  95. switch ( t_first[len_first-1] ) { //Wenn + unär, also vor dem + ein anderes OpSym
  96. case '+':
  97. t[len_first-1]= '\0';
  98. return calcStr(t) + (calcStr(s+len_first));
  99. case '-':
  100. t[len_first-1]= '\0';
  101. return calcStr(t) - (calcStr(s+len_first));
  102. case '*':
  103. t[len_first-1]= '\0';
  104. return calcStr(t) * (calcStr(s+len_first));
  105. case '/':
  106. t[len_first-1]= '\0';
  107. return calcStr(t) / (calcStr(s+len_first));
  108. case '^':
  109. t[len_first-1]= '\0';
  110. return pow(calcStr(t), (calcStr(s+len_first)));
  111. default:
  112. return calcStr(t_first) + (calcStr(s+len_first+1)); //Rekursives Aufrufen der Strings links und rechts des Operationszeichens
  113. }
  114. }
  115. }
  116.  
  117. strcpy(t,s); //da t bei Überprüfung auf + verändert wurde, Wiederherstellung der Arbeitskopie aus Ursprungsstring
  118. if(t[0] != '-') { //- als unärer Operator
  119. t_first= strtok(t,"-"); //analog oben
  120. len_first=strlen(t_first);
  121. if (len_first != len_s) {
  122. switch ( t_first[len_first-1] ) {
  123. case '+':
  124. t[len_first-1]= '\0';
  125. return calcStr(t) + (calcStr(s+len_first));
  126. case '-':
  127. t[len_first-1]= '\0';
  128. return calcStr(t) - (calcStr(s+len_first));
  129. case '*':
  130. t[len_first-1]= '\0';
  131. return calcStr(t) * (calcStr(s+len_first));
  132. case '/':
  133. t[len_first-1]= '\0';
  134. return calcStr(t) / (calcStr(s+len_first));
  135. case '^':
  136. t[len_first-1]= '\0';
  137. return pow(calcStr(t), (calcStr(s+len_first)));
  138. default:
  139. return calcStr(t_first) + (calcStr(s+len_first+1)); //Rekursives Aufrufen der Strings links und rechts des Operationszeichens
  140. }
  141. }
  142. }
  143.  
  144. strcpy(t,s);
  145. t_first= strtok(t,"*");
  146. len_first=strlen(t_first);
  147. if (len_first != len_s) {
  148. return calcStr(t_first) * (calcStr(s+len_first+1));
  149. }
  150.  
  151. strcpy(t,s); //analog
  152. t_first= strtok(t,"/");
  153. len_first=strlen(t_first);
  154. if (len_first != len_s) {
  155. return calcStr(t_first) * (1 / calcStr(s+len_first+1));
  156. }
  157.  
  158. strcpy(t,s);
  159. t_first= strtok(t,"^");
  160. len_first=strlen(t_first);
  161. if (len_first != len_s) {
  162. if (t_first[len_first-1]=='e') {
  163. if (t_first[0]=='-') {
  164. return (-1)*exp(calcStr(s+len_first+1));
  165. } else if (t_first[0]=='+') {
  166. return exp(calcStr(s+len_first+1));
  167. } else {
  168. return pow(calcStr(t_first), (calcStr(s+len_first+1)));
  169. }
  170. }
  171. }
  172.  
  173. return atof(s); //String ist bei keinem Operationszeichen zerfallen => String ist Zahl ; atof castet string zu double (aus stdlib.h)
  174.  
  175. }
  176.  
  177. /****************************************************
  178.  * Funktion zur Verschachtelten Berechnung des Terms
  179.  ****************************************************/
  180. double calc (char *s) {
  181. double result_d=0.;
  182. char *t, *result_str;
  183. int check=1, i=hasPar(s), j=0;
  184. if ( i == (-1) ) {
  185. return calcStr(s);
  186. } else {
  187. j= ++i; //j=++i ist Position des Chars nach der ersten öffnenden Klammer
  188. while (check > 0) {
  189. if (s[i] == '(') {
  190. check++;
  191. } else if (s[i] == ')') {
  192. check--;
  193. }
  194. i++;
  195. } //Bestimmen der Länge der "obersten" Klammer, i ist Position des ersten Zeichens nach der Klammer
  196.  
  197. t= calloc(strlen(s), sizeof(char)); //Hilfsstring, Länge: s[0 bis j-1] + Puffer für Nachkommastellen
  198. result_str= calloc(strlen(s), sizeof(char)); //Hilfsstring, Länge s[j bis i-2] + Puffer für Nachkommastellen
  199. result_d= calc( subStr(result_str, s, j, i-j-1)); //Trennung auf zwei Zeilen zur besseren Lesbarkeit der verschachtelten Funktionsaufrufe
  200. sprintf(result_str, "%-.16f", result_d); //casten des errechneten Double-Ergebnisses zurück in *char !!!ACHTUNG!!! Präzision nicht auf 16 stellen, da sonst undefiniertes Verhalten erzeugt wird
  201. return calcStr( strcat( subStr(t, s, 0, j-1), strcat( result_str, s+i))); //rekursiver Aufruf: calc( s[bis j-2] ## s[j bis i-2] ## s[i bis Ende]) //##: Konkatenation
  202. }
  203. }
  204.  
Runtime error #stdin #stdout 0s 2192KB
stdin
(1+2)*3
stdout
Standard output is empty