Forum: PC-Programmierung Scope- oder Zeigerproblem


von Thorsten (Gast)


Lesenswert?

Ich habe folgende Klasse BigInt in C++ implementiert.
Für den Anfang will ich nur mal einen String einlesen und ihn dann mit 
'.Ausgabe' auf der Konsole ausgeben

Mein Problem ist das ich am Ende des Konstruktors den Inhalt des Strings 
verliere.

#include <iostream.h>
#include <string.h>

class BigInt
{
public:

  BigInt ();
  BigInt (const char *const);
  ~BigInt ();

  BigInt operator+ (const BigInt &);
  BigInt operator- (const BigInt &);
  void operator= (const BigInt &);

  void Ausgabe(void);

private:
  char *pcString;
  int length;
  void StringUp(char);
};

BigInt::BigInt(const char *const pcZahl)
{
  length = strlen(pcZahl);

  pcString  = new char[length+1];    //neuer Stringpointer

  pcString[length+1] = '\0';      // Nullterminierung

  for (int i=0;i<= length;i++)
  {
    pcString[length-i]= pcZahl[i];
  }
}

/********* MAIN ************/
#include "BigInt.h"

int main(void)
{
  BigInt big2("98765432109876543210987654321098765432109876543210");

      big2.Ausgabe();
  return 0;
}



Kann mir jemand helfen und mir sagen an was das liegt?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Mein Problem ist das ich am Ende des Konstruktors den Inhalt
> des Strings verliere.

Das hast Du wie festgestellt?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Arrays starten in C und C++ beim Index 0.

Um 2 Elemente aufzunehmen läuft der Index von [0] zu [1]. Das 
abschliessende Nullbyte kommt nach [2]...

  pcString[length+1] = '\0';      // Nullterminierung

  for (int i=0;i<= length;i++)
  {
    pcString[length-i]= pcZahl[i];
  }

Dieser Code berücksichtigt das nicht. Der Fehler wird durch das reverse 
Kopieren begünstigt. Das abschliessende Nullbyte aus pcZahl wird auf das 
erste Element (Zeichen) von pcString kopiert und schwupp hast du einen 
Leerstring.

von Thorsten (Gast)


Lesenswert?

@rufus: Im Debugger liest er die Zahl korrekt ins Array ein.

@stefb: Also muß es heißen:  pcString[length+2] = '\0';

von Thorsten (Gast)


Lesenswert?

Ach jetzt hab ich es kapiert. Der Befehl

pcString[length-i]= pcZahl[i];

Speichert die '\0' in das erste Element von meinem String und schwubs 
und er ist weg.

Danke für die Hilfe

von Karl H. (kbuchegg)


Lesenswert?

Geh das hier:
1
BigInt::BigInt(const char *const pcZahl)
2
{
3
  length = strlen(pcZahl);
4
5
  pcString  = new char[length+1];    //neuer Stringpointer
6
7
  pcString[length+1] = '\0';      // Nullterminierung
8
9
  for (int i=0;i<= length;i++)
10
  {
11
    pcString[length-i]= pcZahl[i];
12
  }
13
}

bitte mal mit Papier und Bleistift durch.
Nimm an, der Konstuktor wird mit dem Text "123"
aufgerufen.

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+

  length = strlen(pcZahl);

da gibt es also eine Variable length. Die malst
du gleich mal auf dein Papier:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+

   length
   +-------+
   |       |
   +-------+

und wenn wir mal davon ausgehen, dass strlen das richtige
Ergebnis bringt, dann bekommt length den Wert 3. Also
schreibst du eine 3 in deine Variable hinein:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+

   length
   +-------+
   |   3   |
   +-------+


 pcString  = new char[length+1];

hier wird ein Array der Länge length+1 angelegt. length
hat den Wert 3, also wird ein Array der Länge 4 angelegt
und ein Zeiger darauf in der Variable pcString abgelegt:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |   |   |   |
   +-------+       +---+---+---+---+

  pcString[length+1] = '\0';      // Nullterminierung

Aha. Im Array auf das pcString zeigt, wird ein Byte auf
'\0' gesetzt. Welches? das mit dem Index 4. Also zähl
mal im Array ab, welches das ist. Aber achte darauf:
In C++ wird bei 0 zu zählen angefangen:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |   |   |   |
   +-------+       +---+---+---+---+
                     0   1   2   3   4

Hoppla: Das Element 4 ist gar nicht mehr im Array. D.h.
du schreibst die '\0' in rigendwelchen Speicher. Kein
Mensch weis, was du dabei überschreibst, aber was solls.

  for (int i=0;i<= length;i++)

Eine for Schleife. i wird alle Werte von 0 bis
length annehmen (schau auf dein Papier: length hatte
den Wert 3). Also wird i nacheinander die Werte 0, 1, 2, 3
annehmen.

Soweit so gut. Was passiert innerhalb der Schleife:

    pcString[length-i]= pcZahl[i];

OK. pcZahl[i]. i hat den Wert 0, also wird worauf zugegriffen:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+
    0   1   2    3
   ***  <- hier

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |   |   |   |
   +-------+       +---+---+---+---+


Es wird also die '1' aus dem Array geholt und irgendwo ab-
gespeichert. Wo? In pcString[length-i]
Auch das suchen wir mal auf dem Papier. length war 3, i ist
0, also ist 3 - 0 gleich 3 und du suchst im pcString Array
das Element mit dem Index 3

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+
    0   1   2    3
   ***

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |   |   |   |
   +-------+       +---+---+---+---+
                     0   1   2   3
                                ***   <- hier

Dort wird also die '1' abgelegt. Machen wir das mal:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+
    0   1   2    3

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |   |   |'1'|
   +-------+       +---+---+---+---+

nächster Schleifendurchlauf: i hat jetzt den Wert 1
und wieder gilt es auszuführen

    pcString[length-i]= pcZahl[i];

length ist immer noch 3, i ist jetzt 1, also steht
da

   pcString[3-1] = pcZahl[1];

3-1 ist 2, also findet die Operation so statt:

  pcZahl
  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+
    0   1   2    3
       ***

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |   |'2'|'1'|
   +-------+       +---+---+---+---+
                     0   1   2   3
                            ***

Nächster Schleifendurchlauf: i hat jetzt den Wert 2
(Ich spar mir jetzt das genaue Aufschlüsseln)

  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+
    0   1   2    3
           ***

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +---+---+---+---+
   |   o---------->|   |'3'|'2'|'1'|
   +-------+       +---+---+---+---+
                     0   1   2   3
                        ***

und zuguterletzt wird die Schliefe noch mal mit einem
Wert von 3 für i ausgeführt:

  +---+---+---+----+
  |'1'|'2'|'3'|'\0'|
  +---+---+---+----+
    0   1   2    3
                ***

   length
   +-------+
   |   3   |
   +-------+

   pcString
   +-------+       +----+---+---+---+
   |   o---------->|'\0'|'3'|'2'|'1'|
   +-------+       +----+---+---+---+
                     0   1   2   3
                    ***

und jetzt schau dir mal das Ergebnis im pcString Array
genau an. Benenke auch: Ein String ist genau dann zuende
wenn ein Byte mit dem Wert '\0' angetroffen wird.

von Thorsten (Gast)


Lesenswert?

Vielen Dank für die kleine Lehrstunde, ich hab noch einiges zu lernen.
Mach mich gleich dran....

Danke

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.