Problem mit Rückgabewert "string_val"



  • Hallo,

    ich habe ein Problem mit dem Rückgabewert "string_val" in der Funktion "ReadString(....)"
    Wie muss ich den Datentyp der Funktion angeben ?
    Der gezeigte Datentyp "char*" funktioniert nicht, es wird eine lange Zeichenfolge ausgegeben.
    In der Funktion wird die Variable "string_val" richtig angezeigt (Juergen).

    #include "stdafx.h"
    #include "IniReader.h"
    #include "IniWriter.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <string>
    #include <cstring>   
    #include <tchar.h>
    #include <iostream>
    #include <Windows.h>
    
    using namespace std;
    
    // Funktion: Konvertierung TCHAR to CHAR
    void TCharToChar(const wchar_t* , char* , int);
    
    int main()
    {
    	LPWSTR IniPath = TEXT("J://Logger.ini");
            char *szName = iniReader.ReadString(L"Setting", L"Name", L"25", IniPath);
            cout << "Name: " << szName << endl;    // falsche Ausgabe
    
    }
    
    // Funktion: einen String aus einer INI-Datei lesen
    char* CIniReader::ReadString(LPCTSTR szSection, LPCTSTR szKey, LPCTSTR szDefaultValue, LPCTSTR szFileName)
    {
    
    	TCHAR szResult[255];
    	CHAR string_val1[45];
    
    	memset(szResult, 0x00, 255);
    	GetPrivateProfileString(szSection, szKey, szDefaultValue, szResult, 255, szFileName);
    	TCharToChar(szResult, string_val, sizeof(string_val));
    	cout << "ReadString " << string_val << endl;  // Ausgabe Ok
    	return string_val;
    }
    
    void TCharToChar(const wchar_t* Src, char* Dest, int Size)
    {
    	WideCharToMultiByte(CP_ACP, 0, Src, wcslen(Src) + 1, Dest, Size, NULL, NULL);
    }
    

    MfG

    Juergen B.

    😕


  • Mod

    Du gibst einen Zeiger zurück in der Funktion.
    Deine Variable aber, deren Zeiger Du zurückgeben möchtest liegt auf dem Stack.
    In dem Moment in dem die Funktion verlassen wird ist die Variable string_val1 nicht mehr gültig.

    Also entweder Speicher allokieren oder CString oder std::string verwenden, oder einen Puffer für den Rückgabewert bereitstellen.

    Da dies ein typischer Anfängerfehler ist, rate ich Dir dringend mehr C/C++ zu lernen.

    Ansonsten hätte eine einfache Google Suche massenweise Erklärungen gebracht:
    https://stackoverflow.com/questions/5660527/how-do-i-return-a-char-array-from-a-function

    https://stackoverflow.com/questions/3473438/return-array-in-a-function



  • Hallo,

    vielen Dank für die Hinweise (haben geholfen) und ich bin ja dabei mehr C/C++ zu lernen.
    So funktioniert es nun:

    #include "stdafx.h"
    #include "IniReader.h"
    #include "IniWriter.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <string>
    #include <cstring>  
    #include <tchar.h>
    #include <iostream>
    #include <Windows.h>
    
    #define BUFFER_SIZE 100 
    
    using namespace std;
    
    int main()
    {
        LPWSTR IniPath = TEXT("J://Logger.ini");
            char *szName = iniReader.ReadString(L"Setting", L"Name", L"25", IniPath);
            cout << "Name: " << szName << endl;    // Ausgabe Ok
    
    }
    
    // Funktion: einen String aus einer INI-Datei lesen
    char* CIniReader::ReadString(LPCTSTR szSection, LPCTSTR szKey, LPCTSTR szDefaultValue, LPCTSTR szFileName)
    {
    
       size_t   i;
       char *string_val = (char *)malloc(BUFFER_SIZE);
       TCHAR szResult[(size_t)BUFFER_SIZE];
    
       // INI-Datei lesen 
       GetPrivateProfileString(szSection, szKey, szDefaultValue, szResult, (size_t)BUFFER_SIZE, szFileName);
    
        // Konvertierung TCHAR array to char* array
        wcstombs_s(&i, string_val, (size_t)BUFFER_SIZE,	szResult, (size_t)BUFFER_SIZE);
        cout << "ReadString " << string_val << endl;  // Ausgabe Ok
        return string_val;
    }
    

    MfG

    Juergen B.
    🙂


  • Mod

    Ich sag nur: "Memory leak"



  • Martin Richter schrieb:

    Ich sag nur: "Memory leak"

    Und ich schließe mich einfach mal ganz frech an.

    Gelöst ist da gar nix.



  • jbaben schrieb:

    Hallo,
    vielen Dank für die Hinweise (haben geholfen) und ich bin ja dabei mehr C/C++ zu lernen.

    C++ oder C?



  • Hier ein kleines Beispiel mit std::string (hier C++11 vorausgesetzt), auch mit CString wäre es möglich:

    #include <iostream>
    #include <string>
    
    #include <Windows.h>
    
    std::string read_string(const std::string& section, const std::string& key, const std::string& default_value, const std::string& file_name)
    {
        std::string value;
        value.resize(255);
        auto size = GetPrivateProfileString(section.c_str(), key.c_str(), default_value.c_str(), &value[0], value.size(), file_name.c_str());
        value.resize(size);
        return value;
    }
    
    int main()
    {
        std::cout << read_string("Setting", "Name", "25", "Logger.ini") << "\n";
    }
    


  • Hallo EOP,

    und ich verleihe Dir den Titel: "Papagei der Woche".

    MfG

    Juergen B. 👎



  • Hollo,
    nun mal sachlich bleiben.
    Bezieht sich der Hinweis "Memory Leak" auf das fehlende "free() oder wie kann ich das vermeiden?
    Mein Programm hat keinen "Memory Leak" angezeigt.
    Einen besseren Hinweis als nur "Memory Leak" könntet ihr mir schon geben denn dazu ist ja meiner Meinung nach solch ein Forum da.
    Oder sind solche User wie "Martin Richter" und "EOP" nur da um Punkte oder was weiss ich zu sammelen.
    Da lobe ich mir doch den Beitrag von "theta" (vielen Dank dafür).

    MfG

    Juergen B.
    😕



  • Natürlich bezieht es sich auf das fehlende free().

    Wobei ich kompetenztechnisch in keinster Weise an Martin Richter rankomme.
    Wer keine Ahnung hat sollte einfach auch mal die Klappe halten.


  • Mod

    jbaben schrieb:

    Hollo,
    nun mal sachlich bleiben.

    War ich unhöflich!

    Oder sind solche User wie "Martin Richter" und "EOP" nur da um Punkte oder was weiss ich zu sammelen.

    1. Aus dem Alter bin ich raus.
    2. Du willst lernen (hast Du selbst geschrieben), also schreibe ich nicht die direkte Lösung für das Problem.
    Du darfst selbst den Bereich zwischen Deinen Ohren einschalten. 🤡
    Wenn das nicht reicht. Mach den Mund auf und frage...
    3. Wenn ein Programm keine Leaks anzeigt liegt es vielleicht an Dir, weil Du es nicht so programmiert hast, dass es solche anzeigen könnte.
    Siehe auch
    https://msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.90).aspx

    PS: Ich bilde seit ca. 25 Jahren Leute im Bereich des Programmierens aus... wie soll man lernen wenn man gleich alle Fehler auf dem Tablet präsentiert bekommt.
    Würdest Du bei mir ausgebildet werden hätte ich erwartet:
    1. Du machst Dich klug was ein "Memory Leak" ist. Ich habe es netter Weise in Quotes geschrieben.
    2. Bei der gegebenen Programmiersprache kümmerst Du Dich Darum wie solch ein Problem aussieht.
    3. Du entdeckst selbst in Deinem Code, was 2. bedeutet.
    4. Du sagst "Danke, o Meister!"

    4. Ist optional. 😃



  • Das erste Mal, dass ich Martin Richter aufgebracht sehe. 👍


  • Mod

    EOP schrieb:

    Das erste Mal, dass ich Martin Richter aufgebracht sehe. 👍

    Aufgebracht, war ich wirklich nicht!
    Auch aus dem Alter bin ich raus...
    Ich habe nur jbaben nicht verstanden und er mich scheinbar auch nicht, also gilt es Unklarheiten gleich zu beseitigen. 😃



  • Zu dem Thema hätte ich noch eine Frage:
    Wieso funktioniert std::string eigentlich als Rückgabewert?
    Ist doch im Prinzip auch nur eine lokale Variable auf dem stack. 😕


  • Mod

    EOP schrieb:

    Wieso funktioniert std::string eigentlich als Rückgabewert?
    Ist doch im Prinzip auch nur eine lokale Variable auf dem stack. 😕

    Eben es ist ein temporäres Objekt auf dem Stack, und existiert solange, der dazugehörige Ausdruck im Scope liegt.
    Dann wird er dazugehörige Destruktor aufgerufen.

    Und wenn Deine Frage abzielt, wie etwas, dass größer ist als ein Register zurück gegeben werden kann:
    Der Aufrufer stellt den Stack Bereich zur Verfügung, in den der Rückgabewert passen soll, diese Adresse wird übergeben, die Funktion füllt diesen.

    Aber meine Zeiten aus dem Compilerbau sind lange her... das erklärt ein anderer evtl. besser.



  • Danke erstmal für die Antwort. Meine Assembler-Zeiten sind auch schon etwas länger her. Mindestens 25 Jahre. Aber jetzt wo du es sagst fallen mir wieder verschiedene Sachen ein.



  • Hallo,

    1. ich denke ich bin hier im richtigen Forum.
    2. Meine Aussage: "nun mal sachlich bleiben" beziehst sich auf mich.
    3. ich denke das Problem mit "Memory Leak" war das ich mit "delete szName" und "free(szName)" eine "Ausgelöste Ausnahme Lesezugriffsverletzung ('it' war '0x811E') erhalten habe. ohne "delete szName" --> Ok
    4. Das Bispiel von "theta" funktioniert bei mir unter "Visual Studio Express 2015) nicht.
    In der Zeile " auto size = GetPrivateProfileString(section.c_str(), key.c_str(), default_value.c_str(), &value[0], value.size(), file_name.c_str());" erhalte ich
    "error C2664: "DWORD GetPrivateProfileStringW(LPCWSTR,LPCWSTR,LPCWSTR,LPWSTR,DWORD,LPCWSTR)" : Konvertierung von Argument 1 von "const char *" in "LPCWSTR" nicht möglich"

    MfG

    Juergen B.
    😕


  • Mod

    zu 1. Na dann
    zu 2. Aha
    zu 3. Doch!
    zu 4.
    Schau Dir die Meldung an. Dein Projekt hast Du als Unicode Projekt compiliert.
    Folge: Alle Funktionen wie GetPrivateProfileString, werden auf die Unicode Variante gemappt, hier also GetPrivateProfileStringW!

    Folge: Die Funktion nimmt keine char* wie die GetPrivateProfileStringA, sondenr nur wchar_t*.

    Also entweder Unicode abschalten oder die richtigen (passenden) Typen verwenden, oder universell mit TCHAR arbeiten.



  • Hallo,

    vielen Dank für den Hinweis auf UNICODE.
    Wenn ich den UNICODE ausschalte funktioniert das Beispiel von "theta".
    Das mit dem Hinweis auf "wchar_t*" habe ich ja in meinem Ausgangs Programm-Code verwendet.

    Ich meine nun ist erst einmal zu meinem eigentlich Problem alles gesagt.
    Mein nächstes Problem werde ich dann in einem neuen Beitrag senden.

    Ach, eins noch: könntet ihr mir noch ein gutes C++-Buch empfehlen ?

    MfG

    Juergen B.
    :p



  • Martin Richter schrieb:

    oder universell mit TCHAR arbeiten.

    That's the way to go.
    Ich hatte vor ein paar Jahren schon mal eine Frage, wie ich ein Programm auch für Win98 lauffähig mache. Du und Jochen Kalmbach haben mir dabei sehr geholfen.
    Da ich schon alle strings in _T("string") gepackt hatte, musste ich im ganzen Programm lediglich eine einzige Zeile ändern (war glaube ich irgendwas mit strcmp). Danke noch einmal.


Anmelden zum Antworten