Verstehe nicht wie diese Klasse funktioniert



  • Hi, ich versuche mich in C++ einzuarbeiten. Ich bin kein Profi. Also bitte nicht erschrecken.

    Ich wüsste gerne wieso diese Klasse funtioniert wie sie es soll.

    #include<stdio.h>
    #include<iostream.h>

    class MyString
    {
    private:
    	char*	string;
    
    public:
    	int Len()
    	{
    		int len=0;
    
    		while (string[len])
    		{
    			len++;
    		}
    		return len;
    	}
    
    	MyString operator = (char* text)
    	{
    		string = text;
    		return *this;
    	}
    };
    
    int main()
    {
    	MyString	string;
    	string ="Hallo Welt";
    	printf("%s\n",string);
    	printf("%d\n",string.Len());
    
    	return 0;
    }
    

    Ich habe mir gedacht ich erstelle mir mal eine eigene String Klasse, wie in der STL. Nur um zu lernen wie man das alles anwenden muss.

    Meine Frage jetzt. Warum funktioniert das:

    MyString operator = (char* text)
    	{
    		string = text;
    		return *this;
    	}
    

    Weshalb muss ich keinen Speicher reservieren?

    Und warum funktioniert das.

    printf("%s\n",string);

    Bei mir gibt er den Text "Hallo Welt" korrekt aus. Wie kann das gehen. Woher weiss printf() das in string ein char* steckt.

    Danke für die Antworten. cu



  • Kast schrieb:

    Meine Frage jetzt. Warum funktioniert das:

    MyString operator = (char* text)
    	{
    		string = text;
    		return *this;
    	}
    

    Weshalb muss ich keinen Speicher reservieren?

    Ob du "musst" hängt davon ab, was du da zuweist.
    string = "Hallo"; z.b. ist kein Problem, weil "Hallo" ein String-Literal ist, was solange lebt, wie das Programm läuft. Das hier allerdings geht schief:

    Mystring f() {
      char temp[] = "Hallo";
      Mystring result;
      result = temp;
      return result;
    }
    

    weil die private Membervariable string danach ein nicht mehr existentes Objekt verweist. Eine Allzweck-Stringklasse wie die der STL muss natürlich eine Kopie machen, oder jedenfalls so tun als ob,

    Und warum funktioniert das.

    printf("%s\n",string);

    weil printf nicht typensicher ist. Glücklicherweise(?) ist das Layout der Klasse im Speicher identisch mit dem eines char-Pointers (weil sie nur den einen Member hat), also passiert auf Assemblerebene das gleiche, wie wenn du string.string übergeben hättest. Das muss aber nicht streng so sein, deshalb sollte man sich das nicht angewöhnen.



  • spätestens bei sowas wird es dann gefährlich:

    MyString foo () {
       char buffer[42];
       cin >> buffer;
       return MyString(buffer);
    }
    
    int main () {
      MyString x = foo();
      printf("%s\n",string); //dazu unten
    }
    

    du kopierst nämlich nur einen zeiger. wenn das objekt, auf das der zeiger zeigt gelöscht wird (so wie in dem beispiel, wo buffer[42] nach dem funktionsaufruf zerstört wird), dann klappt nix mehr.
    Ein

    MyString foo () {
      return MyString("Hello World");
    }
    

    Funktionier allerdings auch nur, weil "Hello World" als konstantes Stringliteral einen fixen Ort im Speicher für die gesamte Ausführzeit des Programms hat, d.h. ein Zeiger darauf immer gültig ist.

    Das printf Konstrukt funktioniert auch nur, weil printf keine Typinformationen verwendet. Es nimmt einfach an, du übergibst ihm einen const char * (in wahrheit eine referenz auf deinen MyString) und die Daten liegen eben gleich am Anfang deines Objektes, was aber nicht immer garantiert ist.

    /edit: ach, zu spät 🙄 ein Telefonanruf, tjaja...



  • #include<stdio.h>
    
    class String
    {
    private:
    	char*	_string;
    
    public:
    	String ():_string(0){}
    	String (char* string):_string(string){}
    
    	char* textout()
    	{
    		return _string;
    	}
    
    	int len()
    	{
    		int len=0;
    
    		while (_string[len])
    		{
    			len++;
    		}
    		return len;
    	}
    
    	String operator = (char* string)
    	{
    		_string=string; 
    		return *this;
    	}
    };
    
    int main()
    {
    	String	string="Hallo Welt";
    	printf("%s\n",string.textout());
    	printf("%d\n",string.len());
    
    	return 0;
    }
    

    Was sagt ihr zu dieser Lösung?

    Sowas geht auch

    String f()
    {
    	String temp;
    	temp="Hallo Welt";
    	return temp;
    }
    
    int main()
    {
    	String	string=f();//"Hallo Welt";
    	printf("%s\n",string.textout());
    	printf("%d\n",string.len());
    
    	return 0;
    }
    

    So jetzt wollte ich z.B. 6 Zeichen von links aus ausgeben. Dazu hätte ich eine Funktion in C.

    char* 
    left(char* s, int a)
    {
    	char* t=(char*)malloc(a);
    	int b=0;
    	a--;
    
    	while(b<=a)
    	{
    		t[b]=s[b];
    		b++;
    	}
    
    	t[b]='\0';
    
    	return t;
    }
    

    Ich habe es nicht hinbekommen das in die Klasse einzubauen. Wie würdet ihr das machen.

    cu



  • So, was sagt ihr dazu. Ist das so ok?

    #include<stdio.h>
    #include<iostream.h>
    
    class String
    {
    private:
    	char*	_string;
    
    public:
    	String ():_string(){}
    	String (char* string):_string(string){}
    
    	char* textout()
    	{
    		return _string;
    	}
    
    	int len()
    	{
    		int len=0;
    		while (_string[len])
    		{
    			len++;
    		}
    		return len;
    	}
    
    	String left(int a)
    	{
    		char* t = new char[a];
    		int b=0;
    
    		a--;
    
    		while(b<=a) 
    		{ 
    			t[b]=_string[b]; 
    			b++; 
    		} 
    
    		t[b]='\0';
    
    		String string(t);
    
    		return string;
    	}
    
    	String operator=(char* string){_string=string;return *this;}
    };
    
    int main()
    {
    	String	string="Hallo Welt";
    	cout<<string.textout()<<endl;
    	string="Dies ist der zweite Test";
    	cout<<string.textout()<<endl;
    	string="nochmal";
    	cout<<string.textout()<<endl;
    	cout<<string.len()<<endl;
    
    	String links=string.left(4);
    	cout<<links.textout()<<endl;
    
    	return 0;
    }
    


  • Arghhhh... Funktioniert doch nicht so wie ich dachte.

    Wie müsste ich vorgehen damit sowas funktioniert?

    Mystring f() { 
      char temp[] = "Hallo"; 
      Mystring result; 
      result = temp; 
      return result; 
    }
    

    Ich bekomme das alleine nicht hin 😞



  • Du musst um result den SPeicherzuzuweisen new benutzen, so wie Du es dort benutzt wird der Speicher direkt wieder freigegeben wenn Du die FUnktion verlässt. MIt etwas glück bleibt zwar noch ne weile an der stelle "test\0" im Speicher stehen, aber da kann man sich auch nicht drauf verlassen. Und funktioniert denn Dein Zuweisungsoperator grundsätzlich schon? Kenne mich mit dem Überladen von Operatoren nicht aus kann daß daher icht beurteilen.



  • du musst den inhalt, also das, worauf der zeiger zeigt, kopieren (strcpy/strncpy) und dann auf diesen speicher achten (also mit new[] anlegen, mit delete[] löschen)



  • String operator=(char* string)
    {
         _string = new char[];
         while(stirng[l])
         {
              _string[l]=string[l];
              l++;
         }
         _string[l]='\0';
         return *this;
    }
    

    Müsste das nicht funktionieren? 😞



  • Es geht nicht. Keine Vorschläge? 😕



  • _string = new char[];
    

    Du musst new noch sagen wieviel Speicher er reservieren soll... Und so reserviert er nur den Speichreplatz für einen Pointer auf char. Ich kenne mich mit new leider nicht so aus... Aber ich glaube das müsste so aussehen:

    _string = new char[sizeof(string)];
    

    Wie gesagt ist mal nen Schuss ins Blaue 🙂

    *edit*
    Schau am besten mal in eine Referenz Deiner Wahl wie new genau funktioniert. Hab gerade nix dabei, aber auf den von c-plusplus.net verlinkten tuts gab es etwas was pointer und new so erklärt hat, daß ich es auch (fast) verstanden hab



  • nicht sizeof, sondern strlen(string) + 1 zeichen für '\0'.
    Und keine Unterstriche als Beginn für Variablennamen verwenden!



  • Und wo soll ich den Speicher wieder freigebe? Ich habe schon so vieles ausprobiert. Auch im destruktor habe ich versucht mit delete Speicher freizugeben. Doch dann stürztz das Programm ab.



  • Ah und das funktioniert auch nicht so wie oben mit new.

    string f() {
      char test[]="Hallo";
      string result(test);
      return result; 
    }
    


  • Du musst zwischen Kopierkonstruktor und Zuweisungsoperator unterscheiden.
    Zuerst Speicher von der richtigen Größe anfordern (new char[size]),
    dann den string kopieren (strcpy(m_string, string)) und beim Zuweisungsoperator eben zuerst den alten string mittels delete [] löschen.
    Im Destruktor dann einfach mit delete [] löschen.
    Poste Code, dann sagen wir dir, was genau nicht funktioniert.



  • davie schrieb:

    beim Zuweisungsoperator eben zuerst den alten string mittels delete [] löschen.

    ...zuallererst aber auf selbstzuweisung prüfen.



  • 😃 Jetzt geht es langsam voran.

    string f() {
      char test[]="Hallo";
      string result(test);
      return result; 
    }
    
    string str=f();
    .
    .
    .
    

    Das geht jetzt.

    So sehe die Konstruktoren aus:

    string::string ():_string(0){_string = new char[];}
    		string::string (char* t)
    		{
    			int l;
    
    			l=len(t)+1;
    
    			_string=new char[l];
    
    			l=0;
    
    			while(t[l])
    			{
    				_string[l]=t[l];
    				l++;
    			}
    			_string[l]='\0';
    		}
    

    Das sind die überladenen Operatoren:

    string operator=(char* t)
    		{	
    			if(_string)
    				delete[] _string;
    
    			int l;
    
    			l=len(t)+1; // len() ist eine eigene Funktion!!!
    
    			_string=new char[l];
    
    			l=0;
    
    			while(t[l])
    			{
    				_string[l]=t[l];
    				l++;
    			}
    			_string[l]='\0';
    
    			return *this;
    		}
    
    		string operator=(string& st)
    		{
    			if(_string)
    				delete[] _string;
    
    			char* t=st._char();
    
    			int l;
    
    			l=len(t)+1;
    
    			_string=new char[l];
    
    			l=0;
    
    			while(t[l])
    			{
    				_string[l]=t[l];
    				l++;
    			}
    			_string[l]='\0';
    
    			return *this;
    		}
    

    Jetzt habe ich ein Problem beim Destruktor stürzt das Programm ab. bzw. das OS meldet sich zu Wort. 🙄

    string::~string()
    		{
    			if(_string)
    				delete[] _string;
    		}
    

    Ich weiss man soll keine Variablem mit einem Unterstrich beginnen. Aber alles nur zu Übung 🙂
    Ich bin trotzdem für jeden Verbesserungshinweis dankbar. 👍

    PS:
    Das sind noch Methoden die oben verwendet werde.

    //  Zeiger auf char zurück geben
    		char* 
    		string::_char(void){
    			return _string;}
    
    //  Länge des Strings 
    		int 
    		string::len(){
    			int l=0;
    			while (_string[l]){l++;}
    			return l;}
    
    	//  Länge des Strings
    		int 
    		string::len(char* s){
    			int l=0;
    			while (s[l]){l++;}
    			return l;}
    

    Ich hoffe das war jetzt nicht zu viel



  • 😕



  • Und was kommt für eine Meldung beim Destruktor? Der selbst sieht richtig aus.

    Code-Hacker



  • Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)


Anmelden zum Antworten