# stringstream Ärger (oder woran auch immer es liegt)

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

• 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?

Ähm. und wo hast Du das `goto` her?

Das habe ich irgendwo im Netz gefunden, funktioniert super.

• 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)

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

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:
``````

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!

• 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!

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??

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`.

• 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:

Womit lernst Du?

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

Uuups

• Womit lernst Du?

oben im edit. Was würdest du empfehlen?

• 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?

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?

• seid ihr hier ehrenamtlich unterwegs?

Natürlich.

• @Swordfish Verstehe, dann nochmal tausend Dank!

• This post is deleted!