Zuweisung eines const wchar_t*



  • Hallo zusammen,

    ich weiß nicht, ob ich mich einfach zu blöd anstelle, aber ich bekomme folgende ganz einfache Zuweisung nicht auf die Reihe:

    const wchar_t *lpWindowTitle  = NULL;   // Deklaration dreier Pointer
    const wchar_t *lpNewWinTitle  = NULL;        // auf einen const wchar_t, 
    const wchar_t *ControlElement = NULL;        // der auf NULL zeigt
    
    lpWindowTitle  = new const wchar_t[];     // Dynamische Speicherallokierung
    lpNewWinTitle  = new const wchar_t[];     // für mein (offenes) Array -
    ControlElement = new const wchar_t[];     // Hier liegt wohl der Fehler
    
    *lpWindowTitle  = L"Form";         // Zuweisung der entsprechenden
    *lpNewWinTitle  = L"myForm";       // Chars
    *ControlElement = L"button1";
    
    delete[] lpWindowTitle;          // Freigabe des reservierten Speichers
    delete[] lpNewWinTitle;          // für das Gesamte Array
    delete[] ControlElement;
    

    lpWindowTitle = NULL; // Auch die Pointer werden auf
    lpNewWinTitle = NULL; // NULL gesetzt
    ControlElement = NULL

    Zum Code sei folgendes gesagt:
    Ich habe alles (der Übersichtlichkeit halber) aufgesplittet.
    Man möge mich bitte korrigieren, wenn ich falsch liege:
    Die Variable selber (z.B. lpWindowTitle) enthält den Zeiger (also die Adresse) des Elements.
    *lpWindowTitle dagegen enthält dessen Inhalt. Somit muss ich bei der Zuwesiung lpWindowTitle mit * dereferenzieren.

    Der Compiler melden den Fehler:
    Error 1 error C2440: '=' : cannot convert from 'const wchar_t [5]' to 'const wchar_t'
    Error 2 error C2440: '=' : cannot convert from 'const wchar_t [7]' to 'const wchar_t'
    Error 3 error C2440: '=' : cannot convert from 'const wchar_t [8]' to 'const wchar_t'

    Wenn ich die Zuweisung lpWindowTitle = L"Form1" mache, wird korrekt kompiliert. Das macht jedoch (man möge mich verbessern) keinen Sinn, da ich damit sage, dass ich den allokierten Speicher (auf der Heap) gar nicht will und ich erhalte eine neue Adresse auf dem Stack.

    Ich hoffe, dass mir geholfen werden kann. Zwar bekomme ich mein Programm lauffähig, ich möchte aber keine memory leaks programmieren.



  • Lass doch einfach die dynamische Verwaltung.. Die brauchst du hier gar nicht..

    Der beste Weg Memoryleaks zu umgehen ist es keinen Speicher anzufordern..

    const wchar_t *lpWindowTitle  = L"Form";
    ...
    

    reicht völlig.

    oder gleich

    std::wstring lpWindowTitle = L"Form";
    


  • Vorsicht, drakons Methode funktioniert nur mit WString-Literalen, da diese im statischen Speicherbereich liegen.

    Wenn du andere Werte reinschreiben willst, müsstest du new[] mit einer Grössenangabe benutzen. Da dies umständlich, mühsam und fehleranfällig ist, rate ich zu std::wstring oder allenfalls std::vector<wchar_t> .

    std::wstring WString = L"Hallo";
    WString.append(L" Welt");
    WString += L"!!!";
    

    Die Benutzung ist analog zu std::string .



  • Nexus schrieb:

    Vorsicht, drakons Methode funktioniert nur mit WString-Literalen, da diese im statischen Speicherbereich liegen.

    Darum ist das ganze ja const. 😉
    Und darum habe ich (wenn auch nicht so deutlich) wstring vorgeschlagen.



  • Ja, ich dachte nur wegen diesem Satz, der könnte schnell zu Fehlschlüssen führen:

    drakon schrieb:

    Lass doch einfach die dynamische Verwaltung.. Die brauchst du hier gar nicht..

    Ich wusste schon, dass du es richtig meintest. Aber zur Sicherheit hab ichs halt ein bisschen erläutert... 😉



  • Also Jungs,

    danke für die Hilfe. Ich hätte es vielleicht dabei schreiben sollen:

    Mir sind alle drei, der von euch genannten Möglichkeiten, bekannt. Ich weiß, dass ich den Speicher gar nicht selber verwalten muss.

    Ich möchte es aber! Einfach des Wissens halber. Es würde mich echt freuen, wenn Ihr mir sagen könntet, was an meinem Code falsch ist. Natürlich fehlt oben bei mir im Code die Angabe der Array-Größe, die ich bei new[] hätte angeben müssen.

    lpWindowTitle  = new const wchar_t[5];
    lpNewWinTitle  = new const wchar_t[7];
    ControlElement = new const wchar_t[8];
    

    Total merkwürdigerweise bekomme ich genau den selben Fehler beim Compilieren.

    Kann mir dass einer erklären? Ich weiß echt nicht mehr weiter.



  • Du machst weisst da aber einem wchar_t einen Zeiger zu, was falsch ist.

    Und dann musst du bei dieser Zuweisung darauf achten, dass du den Speicher nachher nicht mehr selbst freigibst, weil das dann einen Crash gibt. (ist undefiniert, aber mit grosser Wahrscheinlichkeit gibt es einen crash..)

    Es ist einfach ein Mist, wenn du da dynamisch Verwalteten Speicher mit automatisch verwaltetem mischt. Das kommt bestimmt nicht gut.



  • Okay ...

    Kannst du mir dann bitte sagen, wie ich rein dynamisch mir den Speicher dafür holen würde?



  • FrEEzE2046 schrieb:

    Okay ...

    Kannst du mir dann bitte sagen, wie ich rein dynamisch mir den Speicher dafür holen würde?

    Das machst du doch bereits? 🙄

    Ansonsten einfach genügend grossen Block Daten holen und dann z.B mit strcpy arbeiten.



  • Okay, sry, aber jetzt bin ich verwirrt^^.

    drakon schrieb:

    Du machst weisst da aber einem wchar_t einen Zeiger zu, was falsch ist.

    Das verstehe ich nicht. Ich gehe davon aus, dass du diesen Teil meinst:

    lpWinTitle = new const char[5];
    

    Soweit ich weiß, ist *lpWinTitle der Zeiger und lpWinTitle der Inhalt ... richtig? Und ich brauche doch speicher für den Inhalt und nicht die vier Byte für den Zeiger?!

    drakon schrieb:

    Und dann musst du bei dieser Zuweisung darauf achten, dass du den Speicher nachher nicht mehr selbst freigibst, weil das dann einen Crash gibt. (ist undefiniert, aber mit grosser Wahrscheinlichkeit gibt es einen crash..)

    Das verstehe ich auch nicht. Wenn ich mit new[] speicher hole, dann muss ich ihn doch auch wieder mit delete[] freigeben?!

    Das meinte ich eben damit, wie ich denn dann dynamisch Speicher hole. Tut mir echt leid, wenn ich mich hier etwas blöd anstellen sollte, aber ich versuche das logisch nachzuvollziehen. Es muss doch eine Möglichkeit geben sich selber speicher zu allokieren, auf diesen einen Zeiger zu erhalten und anschließend den Speicher wieder freizugeben.
    Und ich dachte, dass new[] genau das für ein Array tut ... 😕



  • Ich habe mich auf das hier bezogen:

    *lpWindowTitle  = L"Form";         // Zuweisung der entsprechenden
    *lpNewWinTitle  = L"myForm";       // Chars
    *ControlElement = L"button1";
    

    Da hast du ersten den Compile Fehler drin. (Zuweisung von wchar_t* an wchar_t) und zweitens hast du ein Problem, weil der Zeiger, auf den Speicher, den du vorher angefordert hast verloren geht (mem Leak) und den neuen darfst du nicht freigeben, weil der automatisch verwaltet wird. (das L"Form" wird statisch gespeichert und von der Implementierung verwaltet).



  • Also müsste es so aussehen:

    *lpWindowTitle = L"Form";
    *lpNewWinTitle  = L"myForm";
    *ControlElement = L"button1";
    

    Dann ist alos *lpWindowTitle der Inhalt und lpWindowTitle der Zeiger?
    Das ich keinen Speicher allokieren und mir dann einfach neuen Speicher (durch die Zuweisung) besorgen lassen kann, leuchtet mir ein. Denn dann kann ich den Speicher nicht mehr freigeben.

    Dennoch erhalte ich auch bei oben genannten Code einen Fehler. Wie kann ich eine Zuweisung auf den Inhalt machen?



  • Du hast gleich mehrere Probleme.

    lpWindowTitle  = new const wchar_t[5];
    

    Die const-Elemente des Arrays müssen initialisiert werden.

    lpWindowTitle  = new const wchar_t[5]();
    
    *lpWindowTitle  = L"Form";
    

    lpWindowTitle ist ein Zeiger auf wchar_t, d.h. *lpWindowTitle könntest du natürlich nur ein wchar_t zuweisen.

    *lpWindowTitle  = L'F';
    

    Soll die gesamte Zeichenkette kopiert werden brauchst du ein Funktion die dir die Zeichen an die durch lpWindowTitle bestimmte Stelle kopiert.

    In deinem Fall funktioniert aber selbst

    *lpWindowTitle  = L'F';
    

    nicht, weil du die Elemente des Arrays als const deklariert hast. Somit können sie auch nicht geändert werden.

    FrEEzE2046 schrieb:

    Dennoch erhalte ich auch bei oben genannten Code einen Fehler. Wie kann ich eine Zuweisung auf den Inhalt machen?

    Vielleicht wird dir durch folgende Zeilen klar warum

    *ControlElement = L"button1";
    

    nicht geht. Wären es kein const-Elemente würde nämlich das gehen:

    *ControlElement = L'b'; 
    // oder alternativ
    ControlElement[0] = L'b';
    //und weiter
    ControlElement[1] = L'u';
    // ...
    ControlElement[6] = L'1';
    ControlElement[7] = L'\0';
    

    Oder, wie schon mehrfach bemerkt, mit einer Funktion, die dir die Zeichen kopiert. Einfach zuweisen geht so nicht.



  • Okay,

    ich denke es jetzt verstanden zu haben.
    Mein größtes Problem ist es hier irgendwie Zeiger und Inhalt nicht zu verwechseln.

    lpWindowTitle ist also der Zeiger und *lpWindowTitle der Inhalt.
    Wenn ich mir folgendes Ausgeben lasse erhalte ich auch die entsprechenden Werte:

    lpWindowTitle  = new wchar_t[5]();
    	lpNewWinTitle  = new wchar_t[7]();
    	ControlElement = new wchar_t[8]();
    
    	lpWindowTitle[0] = L'F';
    	lpWindowTitle[1] = L'o';
    	lpWindowTitle[2] = L'r';
    	lpWindowTitle[3] = L'm';
    	lpWindowTitle[4] = L'1';
    	lpWindowTitle[5] = L'\0';
    	lpNewWinTitle  = lpWindowTitle;
    	*ControlElement = L'button1';
    
    	cout << lpWindowTitle << "\t" << *lpWindowTitle << "\t" << lpWindowTitle[0] <<  endl;
    	cout << lpNewWinTitle << "\t" << *lpNewWinTitle << endl;
    

    Ausgabe:
    02445348 70 70
    024453448 70

    Dadurch ergeben sich mir mehrere Fragen:

    1. Warum schreibe ich bei der Zuweisung lpWindowTitle[0] = L'F' kein * davor, wenn der Inhalt doch mit *lpWindowTitle erreicht wird?
    2. Ist lpWindowTitle (wenn ich es mir ausgeben lasse) die Adresse zur Zeiger-Variablen oder die Adresse auf die die Zeiger-Variable zeigt?
    3. Warum kann ich dann immer noch nicht mit delete [] lpWindowTitle den Speicher wieder freigeben?

    Das verstehe ich einfach nicht und daher kommen auch die anderen Fragen von oben zu stande.

    Achso und noch etwas:
    Brauche ich das hier

    wchar_t *lpWindowTitle  = NULL;
    

    überhaupt?

    Das macht auf mich irgendwie auch schon wieder keinen Sinn. Ich sage *lpWindowTitle = NULL (also ein NULL-Pointer), aber ich denke jetzt, dass *lpWindowTitle der Inhalt ist und nicht der Zeiger.

    Kann mir das bitte mal jemand erklären? Ich habe bereits in Büchern nachgeschlagen, aber auch dort ist mir das ganze nicht ersichtlicher geworden.



  • Uff! Sieht so aus als fehlen bei dir noch etwas die Grundlagen. Nachdem das unzählige Male erklärt wurde, werde zumindest ich nicht anfangen hier Zeiger zu erklären. Vielleicht hilft jemand aus, der etwas mehr in Schreiblaune ist. 🙂

    Von mir zumindest ein Link:
    http://www.highscore.de/cpp/einfuehrung/zeiger.html

    Dann noch ein kleiner Ratschlag. Wenn du noch nicht genau verstanden hast wie das Zeug funktioniert, dann versuch doch es recht einfach zu halten. D.h. lass das const weg und verwende char statt wchar_t. Für wchar_t ist z.b. nicht cout vorgesehen sondern wcout, wcin, ...
    Gibst du die wchar_t-Daten mit cout aus entstehen wieder Ungereimtheiten, wo keine sein müssten.

    FrEEzE2046 schrieb:

    1. Warum schreibe ich bei der Zuweisung lpWindowTitle[0] = L'F' kein * davor, wenn der Inhalt doch mit *lpWindowTitle erreicht wird?

    Der Compiler wandelt lpWindowTitle[0] um in *(lpWindowTitle + 0) entsprechend lpWindowTitle[1] in *(lpWindowTitle + 1) usw. ...

    *Nur am Rande:
    Wenn lpWindowTitle[0] in *(lpWindowTitle + 0) umgewandelt wird dann wird 0[lpWindowTitle] in (0 + lpWindowTitle) was ja nach Adam Riese dasselbe ist. Und, oh Wunder, es funktioniert auch mit 0[lpWindowTitle] oder 1[lpWindowTitle] oder 2[lpWindowTitle] ... 🙂

    FrEEzE2046 schrieb:

    2. Ist lpWindowTitle (wenn ich es mir ausgeben lasse) die Adresse zur Zeiger-Variablen oder die Adresse auf die die Zeiger-Variable zeigt?

    lpWindowTitle ist eine Variable die die Adresse eines wchar_t enthält
    &lpWindowTitle wäre die Adresse der Variablen lpWindowTitle selbst

    Dummerweise ist die Ausgabe von Zeigern auf char bzw. wchar_t mit cout bzw. wcout eine Besonderheit, da nicht der Inhalt der Zeigervariablen ausgegeben wird (also eine Speicheradresse) wie es bei Zeigern auf int, double, float, usw. der Fall wäre, sondern ein Interpretation des Inhalts der Speicheradresse als nullterminierte Zeichenkette.

    int i=7;
       int *pi = &i;
    
       char *pc = "Hallo Welt"; //pc enhält danach die Adresse des ersten Zeichens 'H'
    
       cout << *pi << endl; // gibt 7 aus , wie erwartet
       cout << *pc << endl; //gibt 'H' aus, wie erwartet
    
       cout << pi << endl; //gibt den Inhalt von pi aus, also die Adresse der Variablen i, wie erwartet
       cout << pc << endl; //gibt "Hallo Welt" aus und nicht die Adresse des ersten Zeichens !!!
    

    FrEEzE2046 schrieb:

    3. Warum kann ich dann immer noch nicht mit delete [] lpWindowTitle den Speicher wieder freigeben?

    Wenn lpWindowTitle noch immer auf den mit new [] angeforderten Speicher zeigt, also während des Programms NICHT irgendwie umgebogen wurde, z.B. auf ein Literal wie L"Hallo", ist delete[] kein Problem.



  • Naja, jetzt hast du es ja doch erklärt.

    Eigentlich habe ich kein Problem mit Zeigern (in anderen Programmiersprachen), aber nur mit der Syntax hier in C++. Wenn der Compiler lpWindowTitle[0] in *(lpWindowTitle + 0) umwandelt, dann macht das Ganze auch seinen Sinn.

    Es sah für mich nur so aus, als ob ich direkt lpWindowTitle (also die Speicheradresse) verändere und einen wchar_t zuweise, was keinen Sinn macht.


Anmelden zum Antworten