stringstream Ärger (oder woran auch immer es liegt)



  • @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.



  • This post is deleted!


  • @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 😉



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

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

    Womit lernst Du?

    oben im edit. Was würdest du empfehlen?



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

    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

    Woher weißt Du daß das ein gutes Anfängertutorial ist?

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

    Was würdest du empfehlen?

    Ein Lehrbuch. Da drüben
    (Buch-) Empfehlung zum Einstieg in die Programmierung mit C++ gesucht
    vielleicht mal reinschauen.



  • @Swordfish Ok super. Danke für alles, ihr seid echt toll^^ seid ihr hier ehrenamtlich unterwegs?



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

    seid ihr hier ehrenamtlich unterwegs?

    Natürlich.



  • @Swordfish Verstehe, dann nochmal tausend Dank!



  • This post is deleted!


  • @Swordfish Sry, die Frage musste umstrukturiert werden. Damit auch größere Zahlen ordentlich ausgegeben werden, muss mit precision manipuliert werden. Vorsichtshalber lässt sich mit setprecision(15) fast jede Zahl ausgeben, auch wenn bei kleineren Fällen immer 15 Stellen angezeigt werden. Um vor jeder Ausgabe die geeignete Anzahl 'n' in setprecision(n) heraus zu finden, könnte man die Anzahl Ziffern während dem String-Input auslesen, aber in diesem Fall wird mit mindestens zwei Nummern gerechnet. Wie könnte man es schaffen, die Anzahl im Ergebnis zu lesen und diese vor der Ausgabe in 'n' von setprecision(n) einfügen?



  • This post is deleted!

Log in to reply