Verständnisfrage Pointer, Char, LPCSTR



  • Hallo an alle,

    ich habe noch ein paar Probleme mit dem Verständnis der Speicherreservierung.

    char var[20]; //Speicher wir reserviert 
    char* var2; //Keine Speicher reservierung, äußerte Vorsicht mit dem Umgang
    char* var3="Hallo"; //Speicher wird wieder reserviert.
    

    LPCSTR wie sieht es da aus? Ist ja auch nur ein Pointer (LP) auf Char somit auch keine Speicherreservierung! Wie sind diese dann zu erstellen?

    folgende Beispielfunktion

    //Funktionsprototyp in einer .h
    void GetResponce(LPCSTR Request,LPCSTR IP,int* ResponceSize,char* ResponceBuffer);
    
    //In einer .cpp
    void GetResponce(LPCSTR Request,LPCSTR IP,int* ResponceSize,char* ResponceBuffer)
     {
    //... CODE der unwichtig ist ...
    hRequest = WinHttpOpenRequest( hConnect,
    				L"GET",
    				A2W(Request),//Konvertiert einen LPCSTR zum LPCWSTR
    				L"HTTP/1.1",
    				WINHTTP_NO_REFERER,
    			       WINHTTP_DEFAULT_ACCEPT_TYPES,
    				0 );
    //... CODE der unwichtig ist ...
    	ResponceBuffer=new char[dwSize+1+*ResponceSize];
            //belegt Speicher mit 0
    	ZeroMemory(ResponceBuffer,dwSize+1+*ResponceSize);
    	strcat(ResponceBuffer,Temp); //Temp ist auch von der neuen Größe von ResponceBuffer
    //... CODE der unwichtig ist ... 
    }
    

    so nun die Funktion aufrufen

    //Aufruf der Funktion ist so 
    int ResponceSize=0;
    char* ResponceBuffer="";
    GetResponce((LPCSTR)START ,myIP,&ResponceSize ,ResponceBuffer);
    

    ResponceBuffer wird angelegt und initialisiert. In der Funktion wird mit new Speicher reserviert und dem ResponceBuffer zugewiesen. Somit dürfte doch kein Speicher überschreiben möglich sein wenn die Variable nur lesend benutze?!

    2.Frage ich übergebe ein #define -> ((LPCSTR)START) an die Funktion. Nun müsste ja Speicher für START reserviert werden. Und nach dem verlassen der Funktion müsste dieser wieder freigeben werden!?

    Vielen DAnk



  • 1. Bis auf das new präsentierst du hier lupenreines C, kein C++.
    2. Du solltest Pointer verstehen, bevor du dich mit Speicherreservierungen rumschlägst.
    C/C++ kennen 3 Arten von Speicher: automatischen (Stack), dynamischen (Heap) und statischen Speicher.

    { // Anfang des Gültigkeitsbereichs (Scopes)
      char buf[200]; // Ein Array auf dem Stack, es wird automatisch genug Speicher reserviert.
    } // Am Ende des Scopes wird der Speicher für "buf" automatisch freigegeben.
    
    char* p; // Auch hier wird Speicher auf dem Stack angelegt. Allerdings nur für den Zeiger selbst. Der zeigt jetzt halt irgendwo hin.
    p = malloc(200); // Jetzt zeigt p auf einen freien Speicherbereich.
    free(p); // p zeigt immer noch auf den gleichen Speicherbereich, allerdings gehört dieser jetzt nicht mehr dem Programm.
    
    char const* p = "Hallo, Welt"; // Das Stringliteral "Hallo, Welt" liegt im statischen Speicher, und p zeigt darauf.
                                   // Man darf das Stringliteral allerdings nicht verändern, daher besser: "char const*"
                                   // gesprochen "pointer to const char".
    

    Zu Funktionen:

    void foo(char* buf, size_t size) // Hier wird ein Zeiger auf freien Speicher erwartet.
    {
      for (size_t i = 0; i != size; ++i)
        buf[i] = 0; // Hier wird in den Speicher auf den buf zeigt geschrieben.
                    // buf[i] entspricht *(buf + i)
    }
    
    int main(void)
    {
      char buf[200];
      foo(buf, 200); // Korrekter Aufruf
      char* p = malloc(200);
      foo(p, 200); // Korrekter Aufruf
      free(p);
      char* s = "Hallo, Welt"; // Besser: char const*, dann meckert der Compiler.
      foo(s, 12); // Böse! s zeigt auf Speicher der nicht der nicht beschrieben werden darf.
      return 0;
    }
    

    LPSTR ist nur ein Windows typedef für char* und LPCSTR für char const*.

    In C++ verlässt man sich bei der Speicherverwaltung übrigens ganz auf RAII:

    #include <vector>
    
    int main()
    {
      std::vector<char> buf(5000); // 5000 byte auf dem Heap reserviert.
      buf[3245] = 'a';
    } // Destruktor von std::vector gibt Speicher automatisch frei.
    


  • John1920 schrieb:

    ich habe noch ein paar Probleme mit dem Verständnis der Speicherreservierung.

    char var[20]; //Speicher wir reserviert 
    char* var2;   //Keine Speicher reservierung, äußerte Vorsicht mit dem Umgang
    char* var3="Hallo"; //Speicher wird wieder reserviert.
    

    Die letzte Zeile verwendet eine für veraltet erklärte Konvertierung. Das sollte so aussehen:

    const char* var3 = "Hallo";
    

    Denn Du darfst die Zeichen so oder so nicht ändern. Der Zeiger zeigt nämlich auf ein im statischen Speicher liegendes, unveränderliches Array. Nur mit dem const hintert Dich der Compiler auch daran, etwas verbotenes zu tun, was Dir andernfalls zur Laufzeit um die Ohren fliegen könnte.

    John1920 schrieb:

    LPCSTR wie sieht es da aus? Ist ja auch nur ein Pointer (LP) auf Char somit auch keine Speicherreservierung! Wie sind diese dann zu erstellen?

    LPCSTR hat wenig mit C++ zu tun. Das ist ein Windows-spezifischer typedef für die Windows-API. Ich glaube, das ist nur ein typedef für char*.

    John1920 schrieb:

    so nun die Funktion aufrufen

    //Aufruf der Funktion ist so 
    int ResponceSize=0;
    char* ResponceBuffer="";
    GetResponce((LPCSTR)START ,myIP,&ResponceSize ,ResponceBuffer);
    

    Was ist START, wozu der C-style cast ("(LPCSTR)")?!

    John1920 schrieb:

    ResponceBuffer wird angelegt und initialisiert. In der Funktion wird mit new Speicher reserviert und dem ResponceBuffer zugewiesen.

    Es gibt hier zwei ResponceBuffer-Variablen: Im Aufrufer-Code und in der Funktion. Den Zeiger in der Funktion veränderst Du. Die andere ResponceBuffer Variable verändert ihren Wert nicht. Die zeigt immer noch auf deinen "Leer-String".

    John1920 schrieb:

    Somit dürfte doch kein Speicher überschreiben möglich sein wenn die Variable nur lesend benutze?!

    Ich verstehe die Frage nicht.

    John1920 schrieb:

    2.Frage ich übergebe ein #define -> ((LPCSTR)START) an die Funktion.

    Bitte was?!

    John1920 schrieb:

    Nun müsste ja Speicher für START reserviert werden. Und nach dem verlassen der Funktion müsste dieser wieder freigeben werden!?

    Ich habe mich schon vorhin gefragt, was START sein soll. Die Antwort auf diese Frage hängt davon ab.

    Übrigens heißt das englische Wort "response" und nicht "responce".

    Tipp: Vergiss new[] ! Arbeite mit std::vector.



  • Hallo cooky451,

    danke für deine Hilfe.

    Ja nicht einfach wenn man mal in c und dann wieder c++ schreibt (Studium) .. Zudem wenn man c++ nur Bruchstückhaft lernt. Und einfach die Zeit fehlt mal komplett von vorn alles zu machen.

    Die Geschichte mit den Pointern meine ich verstanden zu haben.
    Was mir immer Kopfschmerzen macht ist es wenn ich einen char* var anlegen und einer Funktion übergebe. Und diese die Variable dynamisch beschreibt (mal 100 Zeichen, mal 200 Zeichen usw.). Dann kann ich es ja nur wie unten in der Funktion beschrieben machen?

    LG John



  • John1920 schrieb:

    Ja nicht einfach wenn man mal in c und dann wieder c++ schreibt (Studium) ..

    Dann schreib halt gleich in C und lass das new weg. (Durch malloc/calloc ersetzen.)
    Ist ja nicht schlimm, nicht alles muss C++ sein, nur wenn man C++ schreiben möchte, dann doch bitte auch einen std::vector nehmen. 😉

    Ich verstehe nicht ganz was du da oben erreichen willst, aber das sieht doch komisch aus.

    void foo(char* p)
    {
      p = malloc(50); // Hier änderst du die lokale Variable "p".
      free(p);
    }
    
    int main(void)
    {
      char* p = 0;
      foo(p); // Der Pointer selbst (also p, nicht *p) wird einfach kopiert!
      // p ist jetzt immer noch 0. Egal was du in der Funktion mit seiner Kopie gemacht hast.
      // p ist eine ganz normale Variable, wie int oder float oder char etc.
      return 0;
    }
    

    Wenn du einen Zeiger aus einer Funktion heraus verändern willst, brauchst du einen Zeiger auf ihn:

    void foo(char** p)
    {
      *p = malloc(50);
    }
    
    int main(void)
    {
      char* p = 0;
      foo(&p); // Jetzt übergibst du die Adresse von p
      // p hat jetzt einen anderen Wert. (Wenn malloc() nicht gefailt hat.. ;))
      free(p);
      return 0;
    }
    

    Aber im allgemeinen ist so etwas wenig ratsam. Wenn man kein RAII hat überlässt man die Speicherbeschaffung dem Aufrufer:

    void foo(char* p, size_t size)
    {
      strncpy(p, "Hallo, Welt!", size);
    }
    
    int main(void)
    {
      char* p = malloc(50);
      foo(p); // p kann nicht verändert werden, aber das braucht man ja auch gar nicht.
              // Man will nur das verändern worauf p zeigt.
      puts(p);
      free(p);
      return 0;
    }
    


  • Sehe schon alles wieder in zu großer Hektik geschrieben.

    const char* var3 = "Hallo";
    

    Angenommen und verstanden

    Was ist START, wozu der C-style cast ("(LPCSTR)")?!
    

    Warum c-style? Cast ist noch ein Überbleibsel ... macht natürlich wenig Sinn!

    Es gibt hier zwei ResponceBuffer-Variablen: Im Aufrufer-Code und in der Funktion. Den Zeiger in der Funktion veränderst Du. Die andere ResponceBuffer Variable verändert ihren Wert nicht. Die zeigt immer noch auf deinen "Leer-String".
    

    Warum? Ich verbiege doch den Zeiger auf eine andere Adresse! Call by Ref. Oder Missverstehe ich dich jetzt?

    Ja Responce natürlich :)!

    Ja wie gesagt C und C++ Mischkultur. Wage mich noch nicht so ganz an vector und co.. Da muss ich nochmal mehr drüber lesen.



  • John1920 schrieb:

    Es gibt hier zwei ResponceBuffer-Variablen: Im Aufrufer-Code und in der Funktion. Den Zeiger in der Funktion veränderst Du. Die andere ResponceBuffer Variable verändert ihren Wert nicht. Die zeigt immer noch auf deinen "Leer-String".

    Warum? Ich verbiege doch den Zeiger auf eine andere Adresse! Call by Ref. Oder Missverstehe ich dich jetzt?

    void foo(int x) { x=5; }  // <-- dieses x ist ein eigenes der Funktion
    void bar(int* p) { p=0; } // <-- dieses p ist ein eigenes der Funktion
    int main() {
      int x = 99;
      foo(x);
      // x ist hier immer noch 99!
      int* p = &x;
      bar(p);
      // p zeigt hier immer noch auf x!
    }
    

    Wenn Du einen Zeiger "by ref" übergeben willst, sieht das so aus:

    void bar1(int*&p) { p=0; } // <-- dieses p IST das des Aufrufers
    void bar2(int**pp) { *pp=0; } // <-- dieses pp zeigt auf das p des Aufrufers
    
    int main() {
      …
      int* p = &x;
      bar1(p); // oder bar2(&p);
      // p ist jetzt 0!
    }
    


  • Ha ... Hab einfach ein altes Repository ausgecheckt... Heute läufts...

    Ich gebe natürlich die Adresse züruck und weise sie dem alten ResponceBuffer wieder zu. Sonst hätte es natürlich nie funktionieren können... Deshalb habe ich euch auch Missverstanden. Aber es wäre sicher hier besser den Zeiger per Ref zu übergeben und nicht die Adresse als return zu werfen...

    char* GetResponce(LPCSTR Request,LPCSTR IP,int* ResponceSize,char* ResponceBuffer)



  • John1920 schrieb:

    Ich gebe natürlich die Adresse züruck und weise sie dem alten ResponceBuffer wieder zu. Sonst hätte es natürlich nie funktionieren können...
    […]
    char* GetResponce(LPCSTR Request,LPCSTR IP,int* ResponceSize,char* ResponceBuffer)

    Wozu ist dann jetzt der ResponceBuffer-Parameter?

    response schreibt man immer noch mit einem s vor dem e.



  • Wie ich schon sagte wäre es natürlich sinnvoller den Buffer gleich per Ref zu übergeben ...

    GetResponse(LPCSTR Request,LPCSTR IP,int* ResponseSize,char** ResponseBuffer)


Anmelden zum Antworten