stringstream Ärger (oder woran auch immer es liegt)



  • @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    also ganz klar keinen Char.

    Doch, du willst ganz klar einen char vergleichen. Was glaubst du denn, was strInput[i] liefert? Die Fehlermeldung des Compilers wird das auch aussagen.



  • @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    // code
    

    Wtf?

    #include <iostream>
    
    int main()
    {
        double lhs;
        double rhs;
        char operation;
    
        std::cin >> lhs >> std::skipws >> operation >> rhs;
    }
    


  • @manni66 Ich verstehe jetzt was du meinst, Danke. Also man kann einen Index in 'if' angeben, und entsprechend mit ' ' vergleichen anstelle der " ", eben weil strInput[i] einen Char liefert und keinen String. Kannst du auch meine zweite Frage beantworten? Wäre super hilfreich! Eine konkrete Antwort auf die erste Frage wird wohl nicht kommen. 😞



  • Du musst schon unterscheiden zwischen dem was effektiv im speicher steht und dem was (und wie) Du es ausgibst. std::fixed, std::precision.



  • @Swordfish Verstehe, Danke. Mir sind noch nicht annähernd alle möglichen Variablen bzw. Manipulationen bekannt. Das wird noch. 🙂



  • @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    Also man kann einen Index in 'if' angeben

    Du kannst als condition alles hinschreiben daß sich irgendwie zu bool konvertieren lässt.



  • @Swordfish Das weiß ich, es hat bloß meinen Kopf ge***** warum sich ein Index nicht vergleichen ließ.

    Ich zeige dir mal den kompletten Code und warum deine simple Lösung, die ich vorher auch ausprobiert habe, in diesem Fall zwar funktioniert, aber bei einem String-Input in die Doubles zu einer Endlosschleife in der Konsole führt:

    #include <iostream>
    #include <sstream>
    #include <iomanip>
    #include <string>
    #include <cmath>
    
    using namespace std;
    
    int calculator()
    {
        int i;
        double num1;
        double num2;
        double result;
        char operation;
        string strInput;
    
    repeat:
    
        cin >> strInput;
        for(i = 0; i <= strInput.length(); i++)
        {
            if(strInput[i] == '+' || strInput[i] == '-' || strInput[i] == '*' || strInput[i] == '/')
            {
                stringstream(strInput.substr(0, i)) >> num1;
                operation = strInput[i];
                stringstream(strInput.substr(i, strInput.length())) >> num2;
            }
        }
    
    Continue:
    
        if(num1 == 0 || num2 == 0)
        {
            goto error;
        }
    
        if(operation == '+')
        {
            result = num1 + num2;
            cout << "=" << endl;
            cout << result;
        }
        else if(operation == '-')
        {
            result = num1 - num2;
            cout << "=" << endl;
            cout << result;
        }
        else if(operation == '*')
        {
            result = num1 * num2;
            cout << "=" << endl;
            cout << result;
        }
        else if(operation == '/')
        {
            result = num1 / num2;
            cout << "=" << endl;
            cout << result;
        }
        else
        {
    
    error:
    
            cout << endl;
            cout << "Invalid input. Enter 'r' or 'e' and press ENTER to repeat or exit: ";
            cin >> strInput;
            if(strInput == "r")
            {
                cout << endl;
                goto repeat;
            }
            else if(strInput == "e")
            {
                return 0;
            }
            else
            {
                goto error;
            }
        }
    
        cin >> strInput;
        if(strInput.length() > 1)
        {
            if(strInput[0] == '+' || strInput[0] == '-' || strInput[0] == '*' || strInput[0] == '/')
            {
                num1 = result;
                operation = strInput[0];
                stringstream(strInput.substr(1, strInput.length())) >> num2;
                goto Continue;
            }
            else
            {
                goto error;
            }
        }
        else if(strInput == "r")
        {
            cout << endl;
            goto repeat;
        }
        else if(strInput == "e")
        {
            return 0;
        }
        else
        {
            goto error;
        }
    }
    
    int main()
    {
        cout << "This is a calculator." << endl << endl;
        cout << "Enter a number followed by an operation (+ - * /) followed by a number." << endl;
        cout << "Decimals (dot .) up to 15 decimal digits are possible." << endl << endl;
        cout << "Press ENTER for result." << endl;
        cout << "Continue with an operation followed by a number or" << endl;
        cout << "enter 'r' or 'e' and press ENTER to repeat or exit." << endl << endl;
    
        cout << fixed;
        cout << setprecision(15);
    
        calculator();
    
        return 0;
    }
    

    Wenn man

    cin >> strInput;
        for(i = 0; i <= strInput.length(); i++)
        {
            if(strInput[i] == '+' || strInput[i] == '-' || strInput[i] == '*' || strInput[i] == '/')
            {
                stringstream(strInput.substr(0, i)) >> num1;
                operation = strInput[i];
                stringstream(strInput.substr(i, strInput.length())) >> num2;
            }
        }
    

    mit

    cin >> num1 >> skipws >> operation >> num2;
    

    austauscht und beim Input keine Ziffer eingibt, nun.. überzeuge dich selbst :>

    Ziel ist hier das ohne Zeilenbruch die Eingabe erfolgen soll und dann ein Resultat erzielt wird, während eine falsche Eingabe entsprechend behandelt wird, ohne das irgendetwas ausartet. Gerne kannst du den Code komplett weg schmeißen, falls es besser geht, worin ich mir sicher bin.



  • Du willst also daß immer mit dem vorigen Ergebnis weitergerechnet wird bis der Benutzer r eingibt?



  • @Swordfish Genau, wie der Rechner in Windows. Die Zeilen würden wunderbar funktionieren, wäre da nicht das Problem am Anfang, wo 'num2' keinen Wert einfängt wenn Operationen außer '+' eingegeben werden. Mit dem Resultat lässt sich mit allen vier Operationen weiter rechnen. Ich kapier das einfach nicht... Weißt du vielleicht woran es liegt? Liegt hier ein namespace Problem vor? Bisher war ich zu faul dazu alles mit std zu deklarieren.



  • @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    Genau, wie der Rechner in Windows.

    Naja, Zwischenergebnisse wie bei einem Taschenrechner anzeigen lassen ist nicht wirklich möglich wenn Du die Eingabe in einer Zeile haben willst.

    Meinst Du sowas? Mit der Eingabe von c wird mit dem vorigen Ergebnis weitergerechnet, mit e das Programm beendet.

    #include <limits>
    #include <cstddef>
    #include <cstdlib>
    #include <cctype>
    #include <cstdio>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    #include <iostream>
    #include <iomanip>
    
    std::istream &skipws_fail_on_newline(std::istream &is)
    {
    	for (int ch{ is.peek() }; ch != EOF && std::isspace(ch); ch = is.peek()) {
    		if (ch == '\n') {			
    			is.setstate(std::ios::failbit);
    			break;
    		}
    		is.get();
    	}
    	return is;
    }
    
    void clear_and_ignore(std::istream &is)
    {
    	is.clear();
    	is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    
    int main()
    {
    	char const operators[] = { '+', '-', '*', '/' };
    
    	for (double result{};;) {
    		std::vector<double>  numbers;
    		std::vector<char>    operations;
    
    		std::cout << "> ";
    
    		if (!(std::cin >> skipws_fail_on_newline)) {
    			clear_and_ignore(std::cin);
    			continue;
    		}
    
    		double first_number{};
    		if (!(std::cin >> first_number)) {
    			std::cin.clear();
    			
    			if (std::cin.peek() == 'e') {
    				return EXIT_SUCCESS;
    			}
    			else if (std::cin.peek() == 'c') {
    				clear_and_ignore(std::cin);
    				numbers.push_back(result);
    				std::cout << "\n> " << result;
    			}
    			else {
    				std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    				std::cerr << "\n! Input error: expected a number.\n\n";
    				continue;
    			}
    		}
    		else numbers.push_back(first_number);
    
    		for (;;) {
    			if (!(std::cin >> skipws_fail_on_newline)) {
    				clear_and_ignore(std::cin);
    				break;
    			}
    
    			char operation;
    			if (!(std::cin >> std::skipws >> operation)) {
    				std::cerr << "\n! Input error.\n\n";
    				break;
    			}
    			if (std::find(std::begin(operators), std::end(operators), operation) == std::end(operators)) {
    				std::cerr << "\n! Input error: operation '" << operation << "' is not supported.\n\n";
    				std::cin.setstate(std::ios::failbit);
    				break;
    			}
    			operations.push_back(operation);
    
    			double number;
    			if (!(std::cin >> skipws_fail_on_newline >> number)) {
    				std::cerr << "\n! Input error: expected a number.\n\n";
    				break;
    			}
    			numbers.push_back(number);
    		}
    
    		if (!std::cin) {
    			clear_and_ignore(std::cin);
    			continue;
    		}
    
    		if (operations.size() + 1 != numbers.size()) {
    			std::cerr << "\n!!! Something went terribly wrong and I have no clue what to do.\n\n";
    			return EXIT_FAILURE;
    		}
    
    		std::cout.put('\n');
    		result = numbers[0];
    
    		for (std::size_t i{}; i < operations.size(); ++i) {
    			char    operation    { operations[i]  };
    			double  next_number  { numbers[i + 1] };
    
    			std::cout << "  " << result << ' ' << operation << ' ' << next_number << " = ";
    			
    			if (operation == '+') {
    				result += next_number;
    			}
    			else if (operation == '-') {
    				result -= next_number;
    			}
    			else if (operation == '*') {
    				result *= next_number;
    			}
    			else if (operation == '/' && next_number != 0.) {
    				result /= next_number;
    			}
    			else {
    				std::cout << "undefined\n";				
    				break;
    			}
    			
    			std::cout << result << '\n';
    		}
    		
    		std::cout << "= " << result << "\n\n";
    	}
    }
    

    Beispieldialog:

    > 12+3-5*3/4
    
      12 + 3 = 15
      15 - 5 = 10
      10 * 3 = 30
      30 / 4 = 7.5
    = 7.5
    
    > c
    
    > 7.5*6/4      ANMERKUNG: Durch wahl von 'c' wurde 7.5 automatisch eingefügt.
    
      7.5 * 6 = 45
      45 / 4 = 11.25
    = 11.25
    
    > *2
    
    ! Input error: expected a number.
    
    > c
    
    > 11.25*2
    
      11.25 * 2 = 22.5
    = 22.5
    
    > 15w3
    
    ! Input error: operation 'w' is not supported.
    
    > c
    
    > 22.5
    
    = 22.5
    
    > 1+2+3+4+5+
    
    ! Input error: expected a number.
    
    > 1+2+3+4+5+6
    
      1 + 2 = 3
      3 + 3 = 6
      6 + 4 = 10
      10 + 5 = 15
      15 + 6 = 21
    = 21
    
    > 25/0
    
      25 / 0 = undefined
    = 25
    
    > e
    
    C:\>
    

    Ähm. und wo hast Du das goto her?



  • @Swordfish Mein Code funktioniert einwandfrei (abgesehen vom genannten Problem), also nicht 'ich will', ich habe bereits^^ Die Eingabe erfolgt ohne Zeilenbruch in einer Zeile, und in der nächsten landet das Zwischenergebnis, womit sich weiter rechnen lässt. Lass es doch mal laufen, dann weißt du vielleicht auch woran es liegen könnte.

    Wenn ich deine Variante ausführe gibt der Compiler mir folgende Error-Meldung bei Zeile 76:

    'begin' is not a member of 'std'

    Wird wohl an meiner Library liegen? Es werden auch mehrere des folgenden Warnings angezeigt:

    extendet initializer lists only available with -std=c++11 or -std=gnu++11

    Ich nutze CodeBlocks. Wie lässt sich heraus finden welche Revision ich derzeit nutze und wie kann ich die auf 2011 oder gar die 2017 Version aktualisieren?

    @Swordfish sagte in stringstream Ärger (oder woran auch immer es liegt):

    Ähm. und wo hast Du das goto her?

    Das habe ich irgendwo im Netz gefunden, funktioniert super.



  • @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    Wenn ich deine Variante ausführe gibt der Compiler mir folgende Error-Meldung bei Zeile 76:
    'begin' is not a member of 'std'
    Wird wohl an meiner Library liegen? Es werden auch mehrere des folgenden Warnings angezeigt:
    extendet initializer lists only available with -std=c++11 or -std=gnu++11
    Ich nutze CodeBlocks. Wie lässt sich heraus finden welche Revision ich derzeit nutze und wie kann ich die auf 2011 oder gar die 2017 Version aktualisieren?

    Code::Blocks ist "nur" das IDE (Integrated Development Environment). Die Fehlermeldung kommt von Deinem Compiler, wahrscheinlich gcc (oder MinGW wenn Windows).

    Schau mal Im Menü "Settings" ~> "Compiler Settings", da kannst Du -std=C++17 auswählen. Dann klapps auch mit std::begin() 😉 (hoffentlich)

    @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    @Swordfish sagte in stringstream Ärger (oder woran auch immer es liegt):

    Ähm. und wo hast Du das goto her?

    Das habe ich irgendwo im Netz gefunden, funktioniert super.

    Ah, ok.

    @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    Mein Code funktioniert einwandfrei (abgesehen vom genannten Problem), also nicht 'ich will', ich habe bereits^^ Die Eingabe erfolgt ohne Zeilenbruch in einer Zeile, und in der nächsten landet das Zwischenergebnis, womit sich weiter rechnen lässt. Lass es doch mal laufen, dann weißt du vielleicht auch woran es liegen könnte.
    Wenn ich deine Variante ausführe gibt der Compiler mir folgende Error-Meldung bei Zeile 76:

    Hm, irgendwas stimmt da nicht:

    This is a calculator.
    
    Enter a number followed by an operation (+ - * /) followed by a number.
    Decimals (dot .) up to 15 decimal digits are possible.
    
    Press ENTER for result.
    Continue with an operation followed by a number or
    enter 'r' or 'e' and press ENTER to repeat or exit.
    
    12+4
    =
    16.000000000000000+4
    =
    20.000000000000000-15+78
    =
    5.000000000000000+5
    =
    10.000000000000000-15+98/71
    =
    -5.000000000000000+5
    =
    0.000000000000000 + 5
    
    Invalid input. Enter 'r' or 'e' and press ENTER to repeat or exit:
    Invalid input. Enter 'r' or 'e' and press ENTER to repeat or exit:
    

    @Cayz sagte in stringstream Ärger (oder woran auch immer es liegt):

    Lass es doch mal laufen, dann weißt du vielleicht auch woran es liegen könnte.

    Ich sehe mehrere unschöne Sachen, aber um ehrlich zu sein weiß ich nicht genau, welches Problem Du meinst. Mich Durch Deinen Code zu quälen habe ich mich noch nicht überwinden können. Zu unstrukturiert und zu viel goto.



  • Dieser Beitrag wurde gelöscht!


  • @Swordfish sagte in stringstream Ärger (oder woran auch immer es liegt):

    Schau mal Im Menü "Settings" ~> "Compiler Settings", da kannst Du -std=C++17 auswählen. Dann klapps auch mit std::begin() 😉 (hoffentlich)

    Geil, ich kann es nun ausführen, Danke!

    @Swordfish sagte in stringstream Ärger (oder woran auch immer es liegt):

    Hm, irgendwas stimmt da nicht:

    xD Pro Zeile lässt sich nur eine Operation ausführen, also bitte nicht 123+123*123 😅 statt dessen 123+123, dann Enter und mit dem Ergebnis weiter machen, also 246 * 123. Die millionen Nachkommastellen entstehen durch

    cout << fixed;
    cout << setprecision(15);
    

    Zu meiner Problematik, führe bitte kurz nur das hier aus, hier entsteht das Problem:

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <cmath>
    
    using namespace std;
    
    int main()
    {
        int i;
        double num1;
        double num2;
        string strInput;
        string operation;
        string subStrInput;
    
        cin >> strInput;
    
        for(i = 0; i <= strInput.length(); i++)
        {
                subStrInput = strInput[i];
                if(subStrInput == "/")
                {
                    stringstream(strInput.substr(0, i)) >> num1;
                    operation = strInput[i];
                    stringstream(strInput.substr(i, strInput.length())) >> num2;
                }    
         }
        
         cout << num1 << endl;
         cout << operation << endl;
         cout << num2 << endl;
        
         return 0;
    }
    

    Teste mal mit allen vier Operationen und schaue dir anschließend die Werte der drei Variablen an, dann wird es offensichtlich. Mit '+' funktioniert es, bei den restlichen Operationen (- * /) gibt 'num2' = 0 zurück, und dass verstehe ich nicht 😭



  • #include <iostream>
    #include <sstream>
    #include <string>
    // #include <cmath>  wofür?
    
    using namespace std;
    
    int main()
    {
    	double num1;
    	double num2;
    	char operation;
    
    	string strInput;
    	cin >> strInput;
    
    	for (int i = 0; i < strInput.length(); i++)
    	{
    		char ch = strInput[i];
    		if (ch == '+' || ch == '-' || ch == '*' || ch == '/')
    		{
    			stringstream(strInput.substr(0, i)) >> num1;
    			operation = ch;
    			stringstream(strInput.substr(i + 1, strInput.length() - i - 1)) >> num2;
    			break;
    		}
    	}
    
    	cout << num1 << '\n' << operation << '\n' << num2 << "\n\n";
    }
    

    Aber das ist extrem hässlich. Womit lernst Du?


    Diese 75 Zeilen tun so ungefähr das, was Dein Code wohl tun soll:

    #include <limits>
    #include <iostream>
    
    int main()
    {
    	std::cout << "Welcome to my very cute calculator :)\nEnter 'r' for reset or 'e' for exit\n\n";
    	bool reset = true;
    	
    	for (double result = 0;;)
    	{
    		double lhs, rhs;
    
    		if (reset) {
    			while (!(std::cin >> lhs)) {
    				std::cin.clear();
    
    				if (std::cin.peek() == 'e') {
    					std::cout << "\n\nBye :)\n\n";
    					return 0;
    				}
    				
    				std::cerr << "\nInput Error. A number, please, or 'e' for exit.\n\n";
    				std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    			}
    			reset = false;
    		}
    		else {
    			std::cout << "=\n" << result;
    			lhs = result;
    		}
    
    		char operation;
    		std::cin >> std::skipws >> operation;
    
    		if (operation == 'e') {
    			std::cout << "\n\nBye :)\n\n";
    			return 0;
    		}
    
    		if (operation == 'r') {
    			reset = true;
    			std::cout.put('\n');
    			continue;
    		}
    
    		if (operation != '+' && operation != '-' && operation != '*' && operation != '/')
    		{
    			std::cerr << "\nOperation '" << operation << "' is not supported :(\n"
    			             "Supported operations are '+', '-', '*', '/' and 'r' for reset.\n\n";
    			std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    			continue;
    		}
    
    		while (!(std::cin >> rhs)) {
    			std::cerr << "\nInput Error. A number, please.\n\n";
    			std::cin.clear();
    			std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    		}
    
    		switch (operation) {
    		case '+':
    			result = lhs + rhs;
    			break;
    		case '-':
    			result = lhs - rhs;
    			break;
    		case '*':
    			result = lhs * rhs;
    			break;
    		case '/':
    			result = lhs / rhs;
    			break;
    		}
    	}
    }
    


  • @Swordfish Es ist nicht schön, aber kannst du erkennen woran es liegt??

    @Swordfish sagte in stringstream Ärger (oder woran auch immer es liegt):

    Diese 75 Zeilen tun so ungefähr das, was Dein Code wohl tun soll:

    Danke, ich versuche die Zeilen mal zu verdauen. Dein anderes Monstrum liegt weit über meinen aktuellen Bildungsstand 😅

    Ich fange gerade mit einen guten Anfänger Tutorial auf YT an, und mittendrin habe ich versucht einen Taschenrechner zu bauen. Möglicherweise überstürze ich mich 😅



  • @Cayz Ich habe Dir eine Korrektur doch oben gepostet?



  • @Swordfish Oh sry, Danke. Es lag also an dem break?



  • @Cayz: Du hast wohl die Änderung in Zeile 24 nicht gesehen?
    Ansonsten lass dir mal den Ausdruck dort ausgeben:

    cout << "num2: " << strInput.substr(i, strInput.length()) << endl;
    

    Btw: Die Änderung des 2. Parameters ist egal (es wird sonst bis Stringende gelesen), wenn schon richtig gerechnet, dann strInput.length() - i - 1.



  • @Th69 sagte in stringstream Ärger (oder woran auch immer es liegt):

    Du hast wohl die Änderung in Zeile 24 nicht gesehen?

    und die bedingung der for-Schleife.

    @Cayz Nein. Das break ist nur dazu da, daß i nicht völlig sinnlos weiterläuft obwohl schon alles erledigt ist. Vergleiche den Code mal etwas genauer mit Deinem.

    Trotzdem nochmal:

    @Swordfish sagte in stringstream Ärger (oder woran auch immer es liegt):

    Womit lernst Du?

    @Th69 sagte in stringstream Ärger (oder woran auch immer es liegt):

    wenn schon richtig gerechnet, dann strInput.length() - i - 1.

    Uuups 😉


Anmelden zum Antworten