Wenn kein Operator vor (



  • Moin Moin,

    war ja abzusehen das ich wieder schreibe ne ? 😉

    bin jetzt bei einem weiteren Problem angekommen wo ich einfach mal wieder Ideen Anstoss brauche 🙂

    Problem:

    Wenn bei einer Funktion die Berechnet wird ein 2(2+2) eingegeben wird muss das Programm ja wissen das 2*(2+2) gemeint ist.

    heißt es muss ein * zwischengefügt werden und dann weiter bearbeitet werden.

    meine ersten Gedanken dazu:

    If "Kein Operator" -J> bis ( strcpy in bla1 -> strcpy ab ( in bla2 -> An bla1 ein * anhängen -> beide str wieder zusammenführen (bla1*bla2).

    wär das ein richtiger Ansatz? Und bei der überprüfung weiß ich noch nicht sogenau weiter. deshalb auch nur ein If "Kein Operator"...

    Danke schonmal 🙂

    gruß

    Viro



  • Verstehe ich das richtig, dass du ein Rechenprogramm entwickeln willst, das auch komplexere Terme mit Klammern u.ä. verstehen soll?

    Ein Ansatz wäre es, den Term in sog. Tokens zu unterteilen. Tokens für Zahlen, Tokens für verschiedene Operatorklassen. Und dann schaust du einfach nach, ob vor oder nach einem Zahltoken direkt ein Klammertoken kommt. Da kann man dann einfach ein Multiplikationstoken einfügen.

    Das ganze sollte direkt im Parser geschehen. Da können dann auch Fehler wie -+ erkannt werden. Das Ergebnis des Terms sollte in einem anderen Modul entwickelt werden, an einer Stelle, wo die syntaktische Richtigkeit des Terms gegeben ist.

    Ein paar Ideen: http://tclab.kaist.ac.kr/~otfried/cs206/notes/calculator.pdf

    Vielleicht hast du aber auch etwas anderes vor, dann war mein Beitrag wohl für die Katz 😉



  • Er hatte schon einmal hier im Forum geschrieben, es ging tatsächlich um die Berechnung von Termen, damals noch immer in der Form ((a+b)+c) usw. Also jede Operation mit seinen Operanden jeweils geklammert.

    Da ich davon ausgehe das der Term immernoch als ein string vorliegt, ist es wirklich das einfachste einfach Zeichen für Zeichen durchzugehen und zu schauen ob auf eine Ziffer eine öffnende Klammer folgt und in dem Fall ein * einzufügen und dann normal den Term aufzulösen.



  • Fellhuhn schrieb:

    Er hatte schon einmal hier im Forum geschrieben, es ging tatsächlich um die Berechnung von Termen, damals noch immer in der Form ((a+b)+c) usw. Also jede Operation mit seinen Operanden jeweils geklammert.

    genau darum gehts 🙂

    also ich mache das Programm weder mit Tokens noch mit einem Baum... ich wurschtel mich sozusagen bisl durchs Programm.

    Die Rechnung funktioniert auch das die Klammern wenn welche vorhanden sind vor dem Term (((2+2))) = 4 geht auch inzwischen ( Das war ja das was ich als letztes hier ins Forum geschrieben hatte)

    jetzt bin ich soweit das ich halt Zeichen für Zeichen durchgehen muss/will um dann zu schauen ob auf eine Zahl eine KLammer folgt. dann ein * einzufügen.

    Mein größter Problem ist die if Abfrage .. ich hab gerade keine idee wie ich sie formulieren muss/soll... hmm

    da wollte ich einfach einpaar ideen von euch 😉

    gruß

    PS: cool Fellhuhn das du dich an mich erinnerst 😉 hoffentlich ein gutes Zeichen 😃



  • Auf die schnelle in etwa so:

    std::string term = "(3(3+4))";
      for(unsigned int i = 0; i < term.size() - 1; i++) 
        if (std::isdigit(term[i]) && // aus <cctype>
            term[i+1] == '(')
        {
          std::string temp = term.substr(0, i+1);
          temp += '*';
          temp += term.substr(i+1);
          term = temp;
        }
    


  • Virokams schrieb:

    also ich mache das Programm weder mit Tokens noch mit einem Baum... ich wurschtel mich sozusagen bisl durchs Programm.

    Aha, na gut. Wenn du unbedingt mit den Strings rumfummeln willst 😃

    Aber als Vorschlag, wenn du mal fertig bist: Probier mal die Variante mit Termbaum aus. Wäre ne nette Erweiterung und man lernt die Grundlagen vom Compilerbau. Falls dich sowas interessiert.



  • Abstrakte Semantik Bäume wären da zB ein Stichwort. Oder die simpleren Abstraken Syntax Bäume.

    Über so einen anstrengenden Frickelkram habe ich damals meine Diplomarbeit geschrieben... in Ada... war die Hölle. 😃



  • Fellhuhn schrieb:

    Abstrakte Semantik Bäume wären da zB ein Stichwort. Oder die simpleren Abstraken Syntax Bäume.

    Über so einen anstrengenden Frickelkram habe ich damals meine Diplomarbeit geschrieben... in Ada... war die Hölle. 😃

    Also ich werde das Programm bestimm nochmal "anders" lösen sobald es fertig ist.
    Ist halt jetzt so angefangen, abgesprochen und genehmigt es erstmal so zu machen um so strcpy und so andere Problematiken mal kennen zu lernen und die Abläufe mal im Kopf zu verstehen.

    so zurück zum Code... bisl umgebaut sehen meine ersten schritte jetzt so aus:

    for(int i = 0; i <= term[strlen(term)-1]; i++)
      {
        if (int isdigit(term[i]) && term[i+1] == '(')
        {
    	strncpy (copyleft, term[0], term[i]);
    	strncpy (copyright, term[i+1], term[strlen(term)-1);
    	copyleft = // weiß ich noch nicht genau XD   soll aber dann halt das + an copyleft angefügt werden und dann wieder zusammenführung mit copyright im nächsten Schritt
    	strncat();
    
          return berechne(temp);
        } 
      } //hmmmmmmmmmmmm
    


  • Also da du mit char-Arrays arbeitest hast du natürlich etwas mehr Arbeit als wenn du std::string nehmen würdest. Aber das ist deine eigene geschaffene Hölle, da sind wir alle wohl mal durch. 😃

    In etwa so:

    for(int i = 0; i < strlen(term)-1; i++) // du willst bis zum vorletzten Element
      {
        if (std::isdigit(term[i]) && term[i+1] == '(')
        {
            // jetzt hast du das Problem das du term theoretisch um 1 byte vergrößern musst.
            // ich gehe mal davon aus das term vom Typ char* ist.
            char *temp = new char[strlen(term)+2]; // neuer platz
    	strncpy (temp, term, i+1); // alle zeichen bis zum neuen * kopieren
            temp[i+1] = '*'; // * einfügen
    	strncpy (temp+i+2, term + i + 1, strlen(term)-i+1);
            delete[] term; // term wieder freigeben
            term = temp; // term zeigt jetzt auf den neu angeforderten speicher
        } 
      }
    


  • Fellhuhn schrieb:

    Also da du mit char-Arrays arbeitest hast du natürlich etwas mehr Arbeit als wenn du std::string nehmen würdest. Aber das ist deine eigene geschaffene Hölle, da sind wir alle wohl mal durch. 😃

    In etwa so:

    for(int i = 0; i < strlen(term)-1; i++) // du willst bis zum vorletzten Element
      {
        if (std::isdigit(term[i]) && term[i+1] == '(')
        {
            // jetzt hast du das Problem das du term theoretisch um 1 byte vergrößern musst.
            // ich gehe mal davon aus das term vom Typ char* ist.
            char *temp = new char[strlen(term)+2]; // neuer platz
    	strncpy (temp, term, i+1); // alle zeichen bis zum neuen * kopieren
            temp[i+1] = '*'; // * einfügen
    	strncpy (temp+i+2, term + i + 1, strlen(term)-i+1);
            delete[] term; // term wieder freigeben
            term = temp; // term zeigt jetzt auf den neu angeforderten speicher
        } 
      }
    

    hehe ja richtig 🙂 aber Hölle ist immer gut 😉 wie gesagt ich soll es erstmal so machen.

    term ist const char * term ...

    ansonsten Danke erstmal ich gucke gleich mal durch mache jetzt erstmal mittagspause 😉

    gruß



  • hab das jetzt mal so eingefügt... ausser das ich std:: vor dem isdigit wegmachen musste liefs dann... ABER ZACK sobald ich 2(2+2) zum Testen eingebe kommt error.

    und zwar das angeblich irgendiwe der Hipe probleme kriegt oder so.
    kann jetzt keinen Screen machen.

    aber es ist keine Fehlermeldung in der Fehlerliste sondern so ein Windoof Kritikal Error oder so... total wirsch...

    ne ahnung?



  • Virokams schrieb:

    hab das jetzt mal so eingefügt... ausser das ich std:: vor dem isdigit wegmachen musste liefs dann... ABER ZACK sobald ich 2(2+2) zum Testen eingebe kommt error.

    und zwar das angeblich irgendiwe der Hipe probleme kriegt oder so.
    kann jetzt keinen Screen machen.

    aber es ist keine Fehlermeldung in der Fehlerliste sondern so ein Windoof Kritikal Error oder so... total wirsch...

    ne ahnung?

    Alles was hier wirsch ist, ist deine Fehlerbeschreibung.
    Was soll der Hipe sein? Was ist Windoof? Und was soll ein Kritikal Error sein?



  • Ahnung? Ja: char-Arrays. 😉
    Da wird wohl irgendwas mit der Allokierung und/oder Freigabe im Argen liegen.



  • Debug assertion failed!

    Programm:...
    dbgdel.ccp
    Libe:52

    Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

    so ich drücke retry

    Das Programm hat einen Haltepunkt ausgelöst

    ich kann damit garnichts anfangen.

    Hipe ist doch der "kleine" Speicher wo Stacks oder locale Variablen gesp. werden
    Windoof = Windows

    sry...



  • nochwas:

    wenn ich schritt für schritt durchgehe

    sobald ich diese Befehlszeile verlasse:

    delete[] term; // term wieder freigeben

    kommt der Fehler

    also bei:

    term = temp; // term zeigt jetzt auf den neu angeforderten speicher

    SO die Lösung des Problems ist also:

    Auskommentieren von: //delete[] term; // term wieder freigeben

    for(int i = 0; i < strlen(term)-1; i++) // du willst bis zum vorletzten Element
      {
        if (isdigit(term[i]) && term[i+1] == '(')
        {
            // jetzt hast du das Problem das du term theoretisch um 1 byte vergrößern musst.
            // ich gehe mal davon aus das term vom Typ char* ist.
          char * temp = new char[strlen(term)+2]; // neuer platz
        strncpy (temp, term, i+1); // alle zeichen bis zum neuen * kopieren
            temp[i+1] = '*'; // * einfügen
        strncpy (temp+i+2, term + i + 1, strlen(term)-i+1);
            //delete[] term; // term wieder freigeben
            term = temp; // term zeigt jetzt auf den neu angeforderten speicher
        }
      }
    

    Danke 🙂

    Nur eins noch:

    char * temp = new char[strlen(term)+2]; // neuer platz

    was macht das ... versteh ich nicht 😃

    kann mir bestimmt jemand erläutern...

    Danke Danke Danke 🙂



  • char * temp = new char[strlen(term)+2]; // neuer platz

    Dynamische Anforderung von der Länge von term + 2 und temp auf den Anfang des C-Stringes zeigen lassen.



  • Hm, zeig mal die Initialisierung von term.

    Mit new wird neuer Speicher angefordert und mit delete wird er wieder gelöscht. Läßt du das delete weg hast du ein klassisches Speicherleck.



  • Fellhuhn schrieb:

    Hm, zeig mal die Initialisierung von term.

    Mit new wird neuer Speicher angefordert und mit delete wird er wieder gelöscht. Läßt du das delete weg hast du ein klassisches Speicherleck.

    int main()
    {
    char term[1024];

    double berechne (const char * term)
    {}

    ???

    Ich habe dir mal peer Mail den kompletten Code geschickt... vielleicht ist es dann ersichtlicher WIE ich vorgehe... und vielleicht siehste dann besser den Fehler (obwohl es funktioniert 😮 😕 )



  • for(int i = 0; i < strlen(term)-1; i++) // du willst bis zum vorletzten Element
      {
        if (std::isdigit(term[i]) && term[i+1] == '(')
        {
            // jetzt hast du das Problem das du term theoretisch um 1 byte vergrößern musst.
            // ich gehe mal davon aus das term vom Typ char* ist.
            char *temp = new char[strlen(term)+2]; // neuer platz
            strncpy (temp, term, i+1); // alle zeichen bis zum neuen * kopieren
            temp[i+1] = '*'; // * einfügen
            strncpy (temp+i+2, term + i + 1, strlen(term)-i+1);
            delete[] term; // term wieder freigeben
            term = temp; // term zeigt jetzt auf den neu angeforderten speicher
        } 
      }
    

    Entschuldigt bitte das ich mich hier mal mit reinhänge, aber irgendwie verstehe ich die oberen Zeilen nicht so ganz. Sollte dort vor verlassen der for -Schleife nicht auch wieder temp freigegeben werden? Oder habe ich vielleicht gerade ein Brett vorm Kopf? 😞



  • Virokams schrieb:

    Debug assertion failed!

    Programm:...
    dbgdel.ccp
    Libe:52

    Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

    Daran wirst du dich gewöhnen müssen, wenn du es mit char* und deinem Gefrickel durchziehen willst. Du solltest einfach wissen, dass es einfacher geht. 😉

    Mizar schrieb:

    Sollte dort vor verlassen der for -Schleife nicht auch wieder temp freigegeben werden? Oder habe ich vielleicht gerade ein Brett vorm Kopf? 😞

    Nein, der von der alten Variable term referenzierte Speicherbereich wird ja in den neu angelegten Bereich (vom Zeiger temp ) kopiert. Anschliessend wird der alte Speicher von term freigegeben. Zuletzt zeigt term auf den neuen Inhalt (von temp ).


Log in to reply