# Lösung zu Aufgabe von highscore.de



## Arvenius (17. Juli 2011)

*UPDATE: Lösung zu Aufgabe von highscore.de*

Hallo erstmal.

Also ich lern nun seit ein paar Tagen C++ und schaffs im Normalfall auch, die kleinen Probleme, die bis jetzt autauchen zu lösen. 

Ich lerne mit Hilfe von highscore.de und hänge da nun an einer Aufgabe, die wie folgt lautet:

Entwickeln Sie eine C++-Anwendung, die den Anwender zur Eingabe einer vierstelligen Zahl auffordert. Das Programm soll daraufhin die Quersumme der vierstelligen Zahl errechnen und das Ergebnis auf den Bildschirm ausgeben.

So und nun habe ich folgendes geschrieben:


```
int main ()
    {
         char zahl[3];
         
         std::cout << "Willkommen in Bennis \"Quersummenausrechnen\" Programm\n" << std::endl;
         std::cout << "Sie müssen eine 4-stellige Zahl eingeben damit es funktioniert!\n" << std::endl;
         
         std::cout << "Bitte geben Sie eine 4-stellige Zahl ein: ";
         std::cin  >> zahl;
         std::cout << "Die eingegebene Zahl lautet " << zahl << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << zahl[0] << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << zahl[1] << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << zahl[2] << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << zahl[3] << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << zahl[0] << "\n" << std::endl;
         
         int erg1, erg2, erg3, erg4;
         erg1 = zahl[0];
         erg2 = zahl[1];
         erg3 = zahl[2];
         erg4 = zahl[3];
         
         std::cout << "Die eingegebene Zahl lautet " << erg1 << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << erg2 << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << erg3 << "\n" << std::endl;
         std::cout << "Die eingegebene Zahl lautet " << erg4 << "\n" << std::endl;
         
         int ergebnis;
         ergebnis = (erg1 + erg2 + erg3 + erg4);
         
         std::cout << "Das Ergebnis der Quersumme aus der Zahl lautet: " << ergebnis << std::endl;
         
         system("PAUSE");
         }
```

Ums einfach zu benutzen gebe ich 1234 ein. Im ersten Durchlauf der Abfrage, welche Zahlen ich eingegeben habe (also zahl[0]-zahl[4]) bekomme ich auch noch 1234 angezeigt. Da trat dann das Problem auf, dass ich als Ergebnis der Quersumme allerdings 202 raus bekam, deswegen das umspeichern in ne neue Variable um zu sehen wo der Fehler liegt. Das er daran liegt, dass die Zahlen als ASCII-Code (also 49,50,51,52) abgespeichert werden weiß ich nun, aber ich bekomme es partout nicht auf die Reihe, die Ergebnisse aus der Abfrage weiterhin als die eingegebenen Zahlen abzuspeichern. Könnt ihr mir da helfen?


----------



## ComFreek (17. Juli 2011)

Du könntest dir eine Funktion bauen, die eine Zahl als String in eine Zahl als Integer konvertiert.
Das sollte ziemlich leicht sein, vor allem weil du nur eine Stelle hast.


----------



## Arvenius (17. Juli 2011)

Ich muss dazu sagen, dass Funktionen erst im nächsten Kapitel behandelt werden. Kennen gelernt hab ich bis jetzt nur Operatoren und Variablen. Also muss es auch mit den bislang vorhandenen Kenntnissen (vielleicht komplizierter) möglich sein. 

Und meine Frage ist ja im Grunde auch recht simpel: Die eingegebene Zahl (1234) wird auch in ihren Einzelteilen in der Variable zahl[] gespeichert. Beim ersten Abruf eben dieser Variable wird das auch korrekt angezeigt. Allerdings, was ja bei char normal ist, sehe ich zwar die 1234, in der Variable steht aber eigentlich der Wert des dazugehörigen ASCII-Codes. 
Nun könnte ich ja sicher, und da weiß ich nicht wie, das ganze, ähnlich wie bei Buchstaben so in die Variable eintragen kann, dass ich am Ende auch die Zahl wieder angezeigt bekomme. Also so: zahl[1] = '2' statt zahl[1] = 50.


----------



## ComFreek (17. Juli 2011)

Mir ist gerade noch eine Lösung eingefallen:

Wenn man sich die Zahlenfolge 0-9 anschaut, sieht man, dass die ASCII-Codes direkt hintereinander liegen.
Somit kannst du vom ASCII-Code auf die Zahl schließen.

Den Code überlasse ich mal dir 
Falls du noch einen Tipp brauchst, kannst dich gerne melden.


----------



## Arvenius (17. Juli 2011)

Haltet mich für blöd, aber ich komm nicht drauf... 
Ich dachte jetzt vielleicht, dass du irgendwas mit inkrementieren meinst, das kanns aber ja nich sein, da das Programm ja auch auf Zahlen wie 9234 richtig reagieren soll...


----------



## Endurion (18. Juli 2011)

ComFreek bezieht sich auf die ASCII-Werte, die du ja schon richtig erkannt hast:

Eine 2 wird in ASCII mit dem Byte-Wert 50 dargestellt. D.h. wenn du den ASCII-Byte-Wert einer Ziffer hast, rechnest du einfach auf den eigentlich Wert um. Das ist ja für alle 10 Ziffern der gleiche Vorgang.

50 - wieviel = 2?

Ab da sollte es dann ein leichtes sein.


----------



## Arvenius (18. Juli 2011)

Sollte, ist es aber nicht... Ich müsste ja theorethisch für jede Eingabe eine if Abfrage oder ähnliches erstellen. Kann natürlich sein, dass ich komplett auf dem Holzweg bin, aber auch das, da dies erst in nem späteren Kapitel erwähnt wird, kann nicht teil der Aufgabenstellung sein. Wie gesagt: Die einzugebene Zahl ist Variabel, ich rede hier nicht von den festen Werten 1234...


----------



## Arvenius (18. Juli 2011)

Lasst mich bloß alle in Ruhe, meine Freundin hats mir grad verständlich erklärt... Sone Denkblockade muss man erstmal haben... Danke an euch beide und natürlich an Steffi, die Helferin in der Not ;-)

Ach und für alle, die hier nach ner Lösung suchen sollten:


```
#include <iostream>

int main ()
    {
         char zahl[3];
         
         std::cout << "Willkommen in Bennis \"Quersummenausrechnen\" Programm\n" << std::endl;
         std::cout << "Sie muessen eine 4-stellige Zahl eingeben damit es funktioniert!\n" << std::endl;
         
         std::cout << "Bitte geben Sie eine 4-stellige Zahl ein: ";
         std::cin  >> zahl;
         std::cout << "Die eingegebene Zahl lautet " << zahl << "\n" << std::endl;
         
         int ergebnis1;
         ergebnis1 = (zahl[0] + zahl[1] + zahl[2] + zahl[3]) - (4*48);
         
         std::cout << "Das Quersumme lautet: " << ergebnis1 << std::endl;
                  
         system("PAUSE");
         }
```


----------



## Matthias Reitinger (18. Juli 2011)

Hallo,

ist denn niemandem der Fehler im Programm aufgefallen? 



Arvenius hat gesagt.:


> ```
> char zahl[3];
> ```


Hier wird Platz für drei Zeichen auf dem Stack reserviert.



Arvenius hat gesagt.:


> ```
> std::cin  >> zahl;
> ```


Und hier werden nahezu beliebig viele Zeichen auf den Stack geschrieben. Das ist ein klassischer Pufferüberlauf. Selbst wenn sich der Benutzer brav an die Vorgabe hält und nur vier Zeichen eingibt, werden insgesamt fünf Zeichen (vier eingegebene Zeichen + Nullterminierung) auf den Stack geschrieben und damit zwei zu viel. Daher:

Genügend Platz reservieren:


```
char zahl[5];
```

Überlauf verhindern:


```
std::cin >> std::setw(5) >> zahl;
```
std::setw(5) gibt dem Eingabestream zu verstehen, dass in zahl höchstens fünf Zeichen (inkl. Nullterminierung) Platz haben. Es benötigt #include <iomanip>. Alternativ kann man auch 
	
	
	



```
std::cin.width(5);
```
 vor dem Einlesen schreiben.


Grüße,
Matthias


----------



## Arvenius (18. Juli 2011)

Aber ist es nicht so, dass bei char die [0] auch mitzählt? So hab ich Platz für 4 Zeichen. 
Das mit dem width allerdings werd ich beherzigen, denn daran, dass beim cin mehr als 4 Zeichen eingegeben werden können hab ich nicht beachtet. Aber wie gesagt, ich lerne seit ungefähr 5 Tagen C++, da dürfen solche Fehler noch unterlaufen (zumal ich bislang ja nur Variablen und Operatoren kennen lernen durfte!


----------



## sheel (19. Juli 2011)

Hi

beim Zugriff auf die einzelnen chars (generall auf Arraylemente, egal welcher Typ) beginnt man bei 0.
Beim Anlegen muss aber die tatsächliche Anzahl angegeben werden.

Also wenn man die Variable mit [3] anlegt, hat das Array 3 Elemente: [0], [1] und [2].

Bei char-Arrays gibt es aber noch eine Besonderheit: Da sie ja oft verwendet werden, um Strings (Tastatureingaben etc) abzuspeichern und diese ja nicht immer gleich viel Buchstaben haben, sondern auch kürzer sein können, gibt es so eine Art Ende-Zeichen.
Das wird eben am Schluss, nach dem letzten Buchstaben, noch mit abgespeichert.

cin, cout... kommen damit von selber klar, ohne dass man noch was tun muss.
Hier ist allerdings das Problem, dass dieses Schlusszeichen wie ein normaler Buchstabe auch seinen Platz im Array braucht.

Wenn du jetzt also 4 wirkliche Zeichen speichern willst, kommt noch das Schlusszeichen dazu = 5.
Anlegen musst du das Array dann auch mit [5], macht [0] [1] [2] [3] und [4].
[0] bis [3] für deine 4 Zeichen und [4] für das Schlusszeichen.

Gruß


----------



## Matthias Reitinger (19. Juli 2011)

Arvenius hat gesagt.:


> Aber ist es nicht so, dass bei char die [0] auch mitzählt? So hab ich Platz für 4 Zeichen.


Bei der Deklaration eines Arrays gibt man nicht den höchsten Index, sondern die Anzahl der Elemente an. Somit stehen dir bei char zahl[3]; genau drei Zeichen zur Verfügung. Mit char zahl[4]; hättest du dementsprechend vier Zeichen, was für deine Zahl auch reichen würde. Allerdings kommt bei C-Strings immer noch ein abschließendes Nullzeichen ('\0') dazu, welches das Ende des Strings markiert. Also brauchst du tatsächlich fünf Zeichen, um eine vierstellige Zahl (als C-String) zu speichern.



Arvenius hat gesagt.:


> Das mit dem width allerdings werd ich beherzigen, denn daran, dass beim cin mehr als 4 Zeichen eingegeben werden können hab ich nicht beachtet. Aber wie gesagt, ich lerne seit ungefähr 5 Tagen C++, da dürfen solche Fehler noch unterlaufen (zumal ich bislang ja nur Variablen und Operatoren kennen lernen durfte!


Der „Vorwurf“ war auch überhaupt nicht an dich gerichtet. Ich wünsche dir jedenfalls noch viel Erfolg mit C++ und viel Spaß auf tutorials.de 

Grüße,
Matthias


----------



## chibisuke (19. Juli 2011)

Anmerkung:

Einige ältere versionen des micrsoft visual studio compilers wichen hier vom standart ab (k.a. ob sies immer noch tun) und reservierten für ein char[4] beispielsweise tatsächlich 5 byte.

Verursachte lustige probleme, wenn man versucht von einem windows programm an einen linux server datenstrukturen zu übermitteln die statische strings beinhalten und hat mich damals einige stunden debugging gekostet.


----------



## Arvenius (19. Juli 2011)

So, da bin ich wieder...

Danke erstmal für eure mehr als tollen Ratschläge, das hilft mir wirklich enorm weiter... Sich selbst in Eigenarbeit C++ beizubringen ist gar nicht so simpel wenn einem nur mehr oder weniger gute Tutorials zur Verfügung stehen. 

Also die nächste Aufgabe, die es zu lösen gilt lautet:
Entwickeln Sie eine C++-Anwendung, die den Anwender zur Eingabe einer vierstelligen Zahl auffordert. Das Programm soll daraufhin die Quersumme der Zahl mit Hilfe einer Schleife errechnen und das Ergebnis dann auf den Bildschirm ausgeben.

Also quasi die gleiche Aufgabe wie oben, allerdings soll diesmal das Ergebnis als Schleife ausgerechnet werden.

Ich zeig euch einfach mal, wie weit ich gekommen bin und erklär euch dann meine Denkansätze:


```
#include <iostream> 
#include <iomanip>

int main() 
{ 
  char zahl[5];
  std::cout << "Willkommen!\n\n";
  std::cout << "Bitte geben eine 4-stellige Zahl ein: ";
  std::cin  >> std::setw(5) >> zahl;
  std::cout << "Die eingegebene Zahl lautet " << zahl << "\n" << std::endl;
  
  int i;
  int ergebnis;
  int ergebnis1;
  
   
  for (int i = 0; i < 3; i++)
      {
           std::cout << "i ist " << i << std::endl;
           ergebnis1 = (zahl[i] + zahl[i++]);
           std::cout << "ergebnis ist " << ergebnis << std::endl;
           std::cout << "zahl ist " << zahl[i] << std::endl;
                 
      }
  
  ergebnis = ergebnis1 - (4*48);
  std::cout << "\nDie Zahl ist " << zahl << std::endl;
  
  std::cout << "Das Ergebnis lautet: " << ergebnis << std::endl;
  
  system("PAUSE");
}
```

Also zunächst habe ich eure Ratschläge beherzigt und die Eingabe ein wenig begrenzt und das Array größer gemacht. 

So, dann zur Schleife... Ich möchte ja, dass die Variable zahl hochgezählt wird von zahl[0] bis zahl[3] um das Ergebnis ausrechnen zu können, deshalb die for Schleife. Das hochzählen von i funktioniert auch grundsätzlich, allerdings weiß ich nicht, wie ich die Schleife so aufbaue, dass ergebnis = immer weiter aufgebaut wird (also mit zahl[0] beginnend und mit zahl[3] endend). Vielleicht weiß hier jemand Rat? 

Ich weiß, dass das absolute Anfängerfragen sind, dafür möchte ich mich bei euch auch vielmals entschuldigen. Aber lesen allein hilft nicht immer, um logische Zusammenhänge zu erkennen (zumindest bei mir nicht).


----------



## deepthroat (19. Juli 2011)

Hi.

Versuch doch mal die Eingabe als Zahl einzulesen und nicht als String.

Eine Zahl kannst du mit Hilfe der Modulo Operation (%) und der Ganzzahldivision in Teile zerlegen.

Außerdem solltest du immer auch prüfen ob überhaupt etwas eingelesen wurde:

```
if (cin >> zahl) {
  ...
}
```
Gruß


----------



## Arvenius (19. Juli 2011)

Also das mit dem Prüfen mache ich im Normalfall auch, indem ich die einzelnen Arrays abfrage. Allerdings wird der Code ein wenig zu unübersichtlich wenn ich das hier posten würde, deshalb beschränke ich mich hier aufs eigentliche Problem. 
Das mit der Zahl versteh ich nicht. Ich lese doch bei char einzelne Ziffern ins Arrays ein oder nicht? Da habe ich sie ja quasi schon zerlegt (was im ersten Teil ja auch super funktioniert hat, das Problem liegt ja eher an der Schleife).


----------



## sheel (19. Juli 2011)

cin kann auch Zahlen (mehrziffrig) gleich in eine int-Variable einlesen, die ja speziell für Zahlen gedacht ist.

Als String hast du zwar alles schon ziffernweise, jedoch im Ascii (die Sache mit dem -48) und es können auch andere Sachen dabei sein. Buchstaben, die nicht dazugehören etc...
cin überprüft die Zahl beim int-einlesen auch gleich, ob es wirklich eine Zahl ist.

Falls du doch beim String bleibst (und auch sonst): Was ist an der Schleife das Problem?
Statt zahl[0]+zahl[1]+... schreibst du eine Schleife, in der du zahl[x] immer zu einer Variable dazuaddierst (diese am Anfang auf 0 setzen)


----------



## deepthroat (19. Juli 2011)

Arvenius hat gesagt.:


> Also das mit dem Prüfen mache ich im Normalfall auch, indem ich die einzelnen Arrays abfrage.


Damit kannst du aber nicht erkennen ob wirklich etwas eingelesen wurde. Zumal du das Array nicht initialisiert hast und somit zufällige Werte drin stehen.


Arvenius hat gesagt.:


> Allerdings wird der Code ein wenig zu unübersichtlich wenn ich das hier posten würde, deshalb beschränke ich mich hier aufs eigentliche Problem.
> Das mit der Zahl versteh ich nicht. Ich lese doch bei char einzelne Ziffern ins Arrays ein oder nicht? Da habe ich sie ja quasi schon zerlegt (was im ersten Teil ja auch super funktioniert hat, das Problem liegt ja eher an der Schleife).


Ja, aber wenn du es als Zahl einliest sparst du dir die Überprüfung ob der Benutzer auch wirklich eine Zahl eingeben hat.

Und in der Regel berechnet man die Quersumme einer Zahl mit Hilfe der Ganzzahldivision mit Rest.

Um eine Schleife zu bauen, brauchst du dann nur 2 einfache Regeln:

1. Quersumme von 0 ist 0.
2. anderenfalls, Quersumme = Quersumme von zahl / 10 + zahl % 10.

Gruß


----------



## Arvenius (19. Juli 2011)

Irgendwas stimmt aber doch an deiner Erklärung nicht. Es macht doch keinen Sinn eine Quersumme zu berechnen, indem ich die Quersumme benutze... Das wäre doch doppelt gemoppelt... außerdem les ich deinen Text so:
(Quersumme der Zahl 1234 geteilt durch 10 = 1) + (zahl % 10 =  4) = 5...
5 ist aber nicht die dezimale Quersumme von 1234 sondern 10. 
Vielleicht hab ich dich auch gänzlich falsch verstanden!?


----------



## sheel (20. Juli 2011)

Hi

das Ganze ist ja auch in einer Schleife bzw. rekursiv gedacht.

Vielleicht wirds ja mit Code klarer:

```
int zahl = 1234;
...
int x = 0;
while (zahl != 0)
{
    x += zahl % 10;
    zahl /= 10;
}
```

Gruß


----------



## deepthroat (20. Juli 2011)

Arvenius hat gesagt.:


> Irgendwas stimmt aber doch an deiner Erklärung nicht. Es macht doch keinen Sinn eine Quersumme zu berechnen, indem ich die Quersumme benutze... Das wäre doch doppelt gemoppelt...


Doch, es macht sehr viel Sinn. Diese Art von (rekursiver) Definition ist auch in der Mathematik durchaus üblich (Stichwort Folgen).

Um die Quersumme von 1234 zu berechnen:

Quersumme(1234) = Quersumme(1234 / 10) + 1234 % 10 = Quersumme(123) + 4
Quersumme(123) = Quersumme(12) + 3
Quersumme(12) = Quersumme(1) + 2
Quersumme(1) = Quersumme(0) + 1
Quersumme(0) = 0


Arvenius hat gesagt.:


> außerdem les ich deinen Text so:
> (Quersumme der Zahl 1234 geteilt durch 10 = 1) + (zahl % 10 =  4) = 5...
> 5 ist aber nicht die dezimale Quersumme von 1234 sondern 10.
> Vielleicht hab ich dich auch gänzlich falsch verstanden!?


Allerdings.

Wie man es in C iterativ implementieren kann, hat sheel ja bereits verraten. Man kann noch etwas optimieren, indem man die Bedingung etwas anpasst:

1. Quersumme einer Zahl n ist gleich n, falls 0 <= n < 10
2. anderenfalls (n > 10), wie oben

Gruß


----------

