Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Probleme mit String-klasse

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
29.02.2004, 17:21 Uhr
Vriza



Hallo!

Ich hab folgendes Problem mit dieser (selbstgemachten) String Klasse:


C++:
class string{
    char *str;
public:
    string(){str=NULL; } //C'tor
    string (char *s) {str=strdup(s);  }// C'tor
    ~string () { if(str) free (str);printf("X\n");  }//D'tor

    string (const string &s) {if(s.str)str=strdup(s.str); } //Copy c'tor

    string operator += (const string& s)
    {
        
        if(this->str == NULL && s.str== NULL)
//wenn beide strings null sind wird *this zurückgegeben (also null)

            return *this;
        else if (s.str == NULL)
//wenn s.str null ist dann wird ebefalls this zurückgegeben (der bisherige string also; es wird ja nicht hinzugefügt in diesem Fall)
            return *this;
        else if (this->str == NULL ){
// wenn this->str null ist wird einfach der string angehängt und this zurückgegeben
    
            strcat (this->str,s.str);
            return *this;
        }
        else
//wenn beide nicht null sind wird angehängt
        {
            strcat (this->str,s.str);
            return *this;
        }
    }    
                            
};



Meine Main Funktion sieht folgendermaßen aus:


C++:

main()
{
    string s1("Hal");    
    string s2("lo");
    string s3;
    string s4;



    s1+=s3;//hier treten keine fehler auf
    printf("%s\n", s1);
    printf("%s\n", s3);

    s4+=s2;//hier bekomme ich einen speicherfehler
    printf("%s\n", s4);
    printf("%s\n", s2);

    s3+=s4;//hier bekomme ich einen debug error
    printf("%s\n", s4);
    printf("%s\n", s3);

    s1+=s2; //das funktioniert, obwohl nach der aktion ein error kommt (siehe unten)
    printf("%s\n", s2);
    printf("%s\n", s1);

// Wenn das Programm die letzte Aktion durchgeführt hat (s1+=s2) bekomme ich ebenfalls einen Speicherfehler
}



danke schonmal für die Hilfe

mfG

vriza

//edit:
wenn ich schon nen Thread starte, noch eine Frage:
Wie kann ich dieses "string operator" ausserhalb meiner Klasse schreiben?

Dieser Post wurde am 29.02.2004 um 17:23 Uhr von Vriza editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
29.02.2004, 18:56 Uhr
virtual
Sexiest Bit alive
(Operator)


Ich denke Du hast gleich mehrere Probleme:

1. Generell ist nun mal so, daß wenn du mit strdup einen C-String duplizierst, der Speicher eben nur genau für diesen String ausreicht. Du machst aber auf diesen String munter ein strcat, was aber eben dazu führt daß Du über die Speichergrenzen hinausschreibst.

2. Du mchst zwar fein irgendwelche if-Abfragen im op+=, aber du ignorierst diese dann geflissentlich. zB:

C++:
       else if (this->str == NULL ){
// wenn this->str null ist wird einfach der string angehängt und this zurückgegeben
    
            strcat (this->str,s.str);
            return *this;
        }


Ist nahezu eine unablehnbare Einladung zum Programmabsturz, weil du im strcat zu einem NULL Pointer hin kopierst.

3. Das printf funktioniert nicht mit Deiner string klasse. Wenn Doch, dann ists es purer Zufall und ein Implementationsspezifikum. Schreib einfach einen op<< zur Ausgabe nach cout.

Die letzte Frage versthe ich nicht.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
29.02.2004, 22:34 Uhr
Vriza



Ok.


C++:

else if (this->str == NULL ){    
            this->str=(char*) malloc (1);
            this->str='\0';
            strcat (this->str,s.str);
            return *this;
        }



Jetzt allokier ich Speicherbereich für den String und gib dann ein \0 rein. Dann sollte es funktionieren. Allerdings bekomm ich dann trotzdem nen Absturz.

Wegen der Ausgabe habe ich noch eine Funktion für das Ausgeben des Strings geschrieben:

C++:

void output()
    {
        printf("%s \n", str);
    }




So gebe ich zB string s4 aus:

C++:
s4.output();



zum strdup:
Wie kann ich das Problem lösen?

Und zur Frage:
Ich wollt nur wissen ob es geht diesen Code für den Operator auch ausserhalb der Klasse zu schreiben. So wie bei Funktionen.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
01.03.2004, 01:08 Uhr
~(un)wissender
Gast


Ungetested, aus dem Kopf...


C++:
string& operator += (const string& s)
{
  if(this == &s || s.str == NULL)
    return *this;

  if(str == NULL) {
    str = new char[strlen(s.str) + 1];
    strcpy(str, s.str);
  }
  else {
    int size = strlen(s.str);
    char *temp = new char[size + strlen(str) + 1];
    strcpy(temp, str);
    strncat(temp, s.str, size);
    delete [] str;
    str = temp;
  }
  return *this
}

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
01.03.2004, 01:12 Uhr
~(un)wissender
Gast


Semikolon hinter das letzte *this...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
01.03.2004, 08:25 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat:
Vriza postete
Ok.


C++:

else if (this->str == NULL ){    
            this->str=(char*) malloc (1);
            this->str='\0';
            strcat (this->str,s.str);
            return *this;
        }





Ja, Dann hast Du eben nur Speicher für ein Byte belegt.
Das vergörßern/verkleinern des Speicherbereichs ist bei einer Stringklasse eine Häufige Tätigkeit. Ich würde dafür eine Private Methode spendieren, etwa so:

C++:
class string
{
...
private:
     void resize(size_t new_length)
     {
         if (new_length>0)
         {
              char* tmp = realloc(str, new_length+1);
              if (NULL == tmp) throw std::bad_alloc();
              if (NULL == str) *tmp = 0;
              str = tmp;
         }else
         {
              if (str != NULL) free(str);
              str = NULL;
         }
     }


Dann eben noch eine length Routine:

C++:
    ....
public:
    size_t length() const { return str? strlen(str):0; }


So daß Du dann Deinen op+= schreiben kannst als:

C++:
    ...
public:
    string& operator += ( const string& str)
    {
         resize(length()+str.length());
         if (str.str != NULL) strcat(this.str, str.str);
         return *this;
    }


Die resize methode ist allerdings mit Vorsicht zu geniessen: wenn die neue Länge kleiner ist als die alte, geht die Terminierende 0 verloren!
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 01.03.2004 um 08:28 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
01.03.2004, 11:55 Uhr
~(un)wissender
Gast


Die hatte ich bei mir noch rumfliegen, vielleicht hilft die.
Ist nicht zwangsläufig korrekt, hatte die, glaube ich, nicht ausgiebig getestet, sonder nur zu Übungszwecken geschrieben.
Wenn du beim operator>> was Tolleres willst (also nicht std::string), dann musst du, um die gleiche Funktionalität zu bekommen, etwas Betriebssystemabhängiges machen.


C++:
#ifndef STRING_INC
#define STRING_INC

#include <string>
#include <cString>

class String {
private:
    int capacity;
    int length;
    char *cString;

public:
    String(const String &other);
    String(const char *otherCString);
    String(int amount = 1);
    
    ~String();
    
    inline bool operator==(const String &other) const;
    String& operator=(const String &other);
    inline friend String operator+(const String &first, const String &second);
    friend std::ostream &operator<<(std::ostream &out, const String &str);
    friend std::istream &operator>>(std::istream &in, String &str);
    String& operator+=(const String &other);
    inline const char& operator[](int index) const;
    inline char& operator[](int index);
    
    inline int getCapacity() const;
    inline int getLength() const;
    void reserve(int amount);
    void trim();
    inline const char* c_str() const;
    
};

#endif

String::String(const String &other)
{
    int size = other.length;
    length = capacity = size;
    cString = new char[size];
    strcpy(cString, other.cString);
}

String::String(const char *otherCString)
{
    int size = static_cast<int>(strlen(otherCString) + 1);
    cString = new char[size];
    strcpy(cString, otherCString);
    length = capacity = size;
}

String::String(int amount)
{
    length = 1;
    capacity = amount;
    cString = new char[amount];
    cString[0] = '\0';
}

String::~String()
{
    delete [] cString;
}

bool String::operator==(const String &other) const
{
    return strcmp(cString, other.cString) == 0;
}

String& String::operator=(const String &other)
{
    if(this == &other)
        return *this;

    if(capacity < other.length) {
        delete [] cString;
        cString = new char[other.length];
        capacity = length = other.length;
    }

    strcpy(cString, other.cString);
    length = other.length;
    return *this;

}

String operator+(const String &first, const String &second)
{
    return String(first) += second;
}

String& String::operator+=(const String &other)
{
    int size = length + other.length - 1;
    if(capacity < size) {
        reserve(size);
    }
    length = size;
    strcat(cString, other.cString);
    return *this;

}

std::ostream& operator<<(std::ostream &out, const String &str)
{
    return out << str.cString;
}

std::istream& operator>>(std::istream &in, String &str)
{
    std::string stream;
    getline(in, stream);
    str = stream.c_str();
    return in;
}

const char& String::operator[](int index) const
{
    return cString[index];
}

char& String::operator[](int index)
{
    return cString[index];
}

int String::getCapacity() const
{
    return capacity;
}

int String::getLength() const
{
    return length;
}

void String::reserve(int amount)
{
    if(amount > capacity) {
        char *temp = new char[amount];
        strcpy(temp, cString);
        delete [] cString;
        cString = temp;
        capacity = amount;
    }
}

void String::trim()
{
    if(capacity > length) {
        char *temp = new char[length];
        strcpy(temp, cString);
        delete [] cString;
        cString = temp;
        capacity = length;
    }
}

const char* String::c_str() const
{
    return cString;
}

int main()
{
    using namespace std;
    String test = "Hallo";
    String test1 = ", du!";
    cout << "\n" << test + test1 << endl;
    return 0;
}    

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
01.03.2004, 13:44 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat:
~(un)wissender postete

C++:
[...]
String::String(const char *otherCString)
{
    int size = static_cast<int>(strlen(otherCString) + 1);
[...]



Eiegntlich nur notwendig, weil Du fälschlicherweise ein int verwendest. strlen und new arbeiten beide mit size_t. Und schups, halbierst ganz schnell auf diese Weise die max. Mögliche Länge von Strings.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
01.03.2004, 13:47 Uhr
virtual
Sexiest Bit alive
(Operator)



C++:
String s1 = "";
for(int i=0; i<=1+INT_MAX/2; ++i) s1 += "x";
s1 = s1 + s1;


sollte schon problematisch werden
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
02.03.2004, 15:42 Uhr
~(un)wissender
Gast


Ok, war aber ja eh nur zu Übungszwecken, für ihn reicht das auf jeden Fall.
Ich kann dein Beispiel auch so modifizieren, das es mit size_t Ärger gibt.
Allerdings ist es natürlich klar, dass ein Programmierer annimmt, dass der String size_t Zeichen haben kann.
Performancetechnisch wäre es wohl auch besser, strcpy durch memcpy zu ersetzten, aber ich denke nicht, dass das hier von entscheidender Bedeutung ist.

Heutzutage würde ich eine Stringklasse eh anderes schreiben, am besten gar nicht.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: