nicht initialisierte lokale Variable



  • Hi,
    wie mir letztens gesagt wurde darf ich Warnmeldungen nicht einfach so beiseite schieben. Deshalb hiernmeine Frage was ich da falsch mache

    //ich erzeuge mir meine variable
    LPSTR readwert; 
    ......
    // und benutze sie ein paar Zeilen weiter darunter
    GetPrivateProfileString(bereich,Key,sollwert,readwert,destSize,szIniName); 
    ......
    

    der Compeiler meint dazu

    warning C4700: Die nicht initialisierte lokale Variable "readwert" wurde verwendet
    

    Ich weiss nich im geringsten was er von mir will, reicht es nicht wenn ich eine leere Variable erzeuge um sie später zu füllen ?
    Beisst und trettet mich ruhig, aber sagt mir auch was ich da falsch mache 😃


  • Mod

    Du hast einen Zeiger deklariert. Dieser Zeiger muss initialisiert werden. Ohne das Du dies tust wird dieses Stück Code einen Absturz Deines Programmes erzeugen.

    Zeiger selbst sind eben kein Speicher sondern zeigen nur auf Spiecher. Und Dein Zeoger zeigt eben nicht auf einen von Dir festgelegten Bereich.



  • wenn ich das jetzt richtig verstehe gehts also darum das es ein LPSTR ist.

    variable = "A";
    LPSTR meinzeiger = variable;
    

    in diesem fall würde ich dem zeiger meinzeiger anweisen auf die variable zu zeigen mir also den zugriff auf "A" ergöglichen. Richtig 😕

    Der Programmcode Funktioniert übrigens auch in meiner Fehlerhalften schreibweise, keine Ahnung warum.
    Man sieht ja das es sich um einen Teil meiner .ini Read handelt und die Funktioniert im gegensatz zu anderen Kleinigkeiten schon 😃



  • Der Code funktioniert
    1. weil du in der Debugversion bist.
    2. weil du erst drauf zugreifst, nachdem du die Variable (mit Hilfe einer Funktion, was der Compile nicht wissen kann) initialisiert hast.
    😉

    Nicht sauber, aber Glück gehabt.

    Mach besser:

    LPSTR meinzeiger = NULL;
    


  • nene nich Debugversion ganz normal release.
    ich denk mal eher Glück gehabt trifft dann wohl zu 😃

    Aber dafür gibts ja dieses Forum hier, damit auch Stoffel wie ich einer bin mal begreiffen wies geht 😃
    Ich denk mal mit dem Wissen an eine Überarbeitung gemacht und mir bleiben die Zugriffsverletzungen wärend der Laufzeit, die ab und zu mal auftauchen erspart. Bzw werden wohl weniger werden 😉


  • Mod

    estartu schrieb:

    Mach besser:

    LPSTR meinzeiger = NULL;
    

    Aber dann fliegt ihm GetPrivateProfileString dennoch um die Ohren... 🤡



  • Martin Richter schrieb:

    estartu schrieb:

    Mach besser:

    LPSTR meinzeiger = NULL;
    

    Aber dann fliegt ihm GetPrivateProfileString dennoch um die Ohren... 🤡

    Oh, wie geht es dann dann richtig?

    Ich hatte nur kurz geguckt, ob die Zeile kompiliert.
    Außerdem dachte ich: Zeiger werden mit NULL initialisiert, der Rest weiß das und reagiert drauf... 😉



  • Nunja, viele Funktionen der WinAPI und Standardbibliotheken sagen ganz einfach "gib mir eine Adresse und ich schreibe die Daten dorthin" - also mußt du vor dem Aufruf sicherstellen, daß du genug Platz hast.

    LPTSTR meinzeiger = new TCHAR[bufsize];
    
    GetPrivateProfileString(...,meinzeiger,bufsize,...);
    

    (die Alternative sind idR Doppelzeiger, aber da würdest du die Adresse an die Funktion übergeben - Zeiger-Referenzen werden in der WinAPI eher selten verwendet (historisch bedingt))



  • jo Zugriffsverletzung bei adresse 0x000000 schmeist er mir da 😃

    Aber der vorschlag von CStoll funktioniert wunderbar, jetzt hab ich nur noch eine Zugriffsverletzung die ich nich finden kann, weil sie nicht regelmässig auftaucht, und immer wennich debuge passiert natürlich nichts 🙄

    Aber es hat mir schon mal sehr weitergeholfen das ich Dank euch die Pointer begiffen habe.



  • CStoll schrieb:

    Nunja, viele Funktionen der WinAPI und Standardbibliotheken sagen ganz einfach "gib mir eine Adresse und ich schreibe die Daten dorthin" - also mußt du vor dem Aufruf sicherstellen, daß du genug Platz hast.

    Arg, ja klar.
    Sorry, das war mein Fehler, da hatte ich nicht dran gedacht. 😞

    PS: Was passiert, wenn du die Releaseversion debugst? 😉



  • Eine Frage hab ich doch noch, eine variable wird doch ausserhalb der funktion in der sie erzeugt wurde Ungültig wenn ich das richtig verstehe.
    Muss ich die Pointer jetzt am schluss Löschen oder gehen die von allein in die ewigen jagtgründe ein 😕
    Ich meine um den Speicher wieder frei zu geben.



  • Den Speicher hinter dem Pointer mußt du selber wieder löschen (rechtzeitig bevor er aus dem Scope rausfällt), da C++ per Default keinen Garbage Collector hat. Eine Alterantive wäre es, anstelle nackter Zeiger Smart-Pointer zu verwenden, die sich von Hand um den richtigen delete[]-Aufruf kümmern (oder ein ausreichend großes lokales Array).


  • Mod

    CStoll schrieb:

    LPTSTR meinzeiger = new TCHAR[bufsize];
    
    GetPrivateProfileString(...,meinzeiger,bufsize,...);
    

    Ist in diesem Fall

    // Edit: Ursprünglich TCHAR meinbuffer = TCHAR[VORGEGEBENEGROESSE];
    // ich meinte natürlich:
    TCHAR meinbuffer[VORGEGEBENEGROESSE];
    
    GetPrivateProfileString(...,meinbuffer,_countof(meinbuffer),...);
    

    nicht die bessere Variante? Just my 2 cents!

    new/delete würde ich für solche Aufgaben vermeiden!



  • Wenn du eine fest vorgegebene Maximalgröße hast, womöglich(1). Aber spätestens wenn du darüber stolperst, daß das Array zu klein wird, müsstest du dynamisch Speicher anfordern (in dem Fall bedeutet das: wenn der geholte Registry-Wert zu lang ist, mußt du mehr Speicher anfordern und GetPrivateProfileString() nochmal neu aufrufen).

    PS: Bist du sicher, daß dein Code so funktioniert? Ich hab noch nie gesehen, daß man einen einzelnen TCHAR-Wert mit einem Array initialisieren kann.

    PPS: Die beste Lösung wäre es imho sowieso, solche WinAPI-Aufrufe in einer eigenen Funktion zu kapseln und nach außen über C++ Container bzw. std::string zu kommunizieren. Aber so weit ist MS bei der MFC ja nicht gegangen.

    (1) deswegen habe ich in meinem letzten Beitrag auch den Hinweis auf ein Array gebracht.


  • Mod

    CStoll schrieb:

    PS: Bist du sicher, daß dein Code so funktioniert? Ich hab noch nie gesehen, daß man einen einzelnen TCHAR-Wert mit einem Array initialisieren kann.

    😮 Das ist ein Typo! Ich editiere den mal... Danke für den Hinweis!

    CStoll schrieb:

    PPS: Die beste Lösung wäre es imho sowieso, solche WinAPI-Aufrufe in einer eigenen Funktion zu kapseln und nach außen über C++ Container bzw. std::string zu kommunizieren. Aber so weit ist MS bei der MFC ja nicht gegangen.

    (1) deswegen habe ich in meinem letzten Beitrag auch den Hinweis auf ein Array gebracht.

    Sowas meinst Du? 🕶

    CString CMyApp::GetLocalSettingsString(PCTSTR pszSection, PCTSTR pszEntry, PCTSTR pszDefault)
    {
    	if (pszDefault == NULL)
    		pszDefault = _T("");	// don't pass in NULL
    
    	// Up to a maximum of 4kb!
    	TCHAR szBuff[4096];
    	DWORD dw = ::GetPrivateProfileString(pszSection, pszEntry, pszDefault, szBuff, MfxCountOf(szBuff), m_strLocalSettingsIniFile);
    	ASSERT(dw < 4095);
    	UNUSED_ALWAYS(dw);
    	return szBuff;
    }
    
    BOOL CMyApp::WriteLocalSettingsString(PCTSTR pszSection, PCTSTR pszEntry, PCTSTR pszValue)
    {
    	return ::WritePrivateProfileString(pszSection, pszEntry, pszValue, m_strLocalSettingsIniFile);
    }
    


  • Ja jetzt verwirt mich doch mal 😮
    Ich habe nur eine kleine .ini in der ich zum grössten Teil zahlenwerte ablege, also alles vorhersehbar in der benötigten Grösse.

    Hey noch mal Danke, seit dem ich das einigermasen begriffen habe fällt mir das "Konvertieren" doch sofort viel leichter 🙂



  • fmotto schrieb:

    Ja jetzt verwirt mich doch mal 😮

    Immer wieder gerne 😃
    (aber für dein Problem sind die letzten Zeilen auch nicht mehr relevant - da haben wir das Problem nur etwas weitergesponnen)

    @Martin: Ja, an sowas habe ich gedacht, wobei ich diese Wrapper-Funktionen vermutlich nicht in meine App-Klasse integriert hätte (und mit std::string arbeiten würde, aber das ist letztendlich Geschmackssache).

    Ich habe nur eine kleine .ini in der ich zum grössten Teil zahlenwerte ablege, also alles vorhersehbar in der benötigten Grösse.

    Wenn du abschätzen kannst, wie groß deine Werte werden können, reicht es auch aus, ein entsprechend großes Array bereitzustellen (siehe Martins oberer Eintrag) - und für Zahlenwerte gibt es afaik auch GetPrivateProfileInt(), das die Werte gleich in ein int umrechnet.


  • Mod

    CStoll schrieb:

    @Martin: Ja, an sowas habe ich gedacht, wobei ich diese Wrapper-Funktionen vermutlich nicht in meine App-Klasse integriert hätte (und mit std::string arbeiten würde, aber das ist letztendlich Geschmackssache).

    Die Anwednung hier, aus der ich es kopiert habe nutzt eine INI Datei in einem bestimmten Verzeichnis. Insofern ist das natürlich kein gutes Beispiel für einen allgemeinen Wrapper. Aber dadurch kann ich sowohl die Registry mit HKCU verwenden, als auch eine INI Datei um Konfigurationen über eine Datei tauschen zu können!

    Zum std::string Versus CString. Warum soll ich std::string nehmen wenn ich sowieso eine MFC Applikaiton habe. Zudem ist CString flexibler :-)!

    Edit. Quote gefixt!



  • CStoll schrieb:

    PPS: Die beste Lösung wäre es imho sowieso, solche WinAPI-Aufrufe in einer eigenen Funktion zu kapseln und nach außen über C++ Container bzw. std::string zu kommunizieren. Aber so weit ist MS bei der MFC ja nicht gegangen.

    Martin Richter schrieb:

    Zum std::string Versus CString. Warum soll ich std::string nehmen wenn ich sowieso eine MFC Applikaiton habe.

    So, jetzt bin ich vollauf Eurer Meinung! 👍
    Die anderen Datentypen sind jedes Mal mein persönlicher Kampf, wenns an die Api-Sachen geht. 😞


Anmelden zum Antworten