Wann Rückgabe auf lokalen Speicher zulässig?



  • lokaler Speicher schrieb:

    Wieso der Umweg über das IPTOSBUFFERS-Array

    Weil man anscheinend die letzten 20 Ergebnisse verfügbar halten will. Ich sag mal, das Design ist zumindest fragwürdig.

    und nicht einfach so:

    char *iptosting(u_long in)
    {
        char output[3*4+3+1];
        u_char *p = (u_char *)∈
        sprintf(output, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
        return output;
    }
    

    Naja das geht schonmal gar nicht, deine output-Variable ist ja nicht static. Sie wird also zerstört, wenn die Funktion verlassen wird.

    Ich habe mal gehört, dass Funktionen in einigen Fällen keinen (Zeiger auf) lokalen Speicher zurück geben sollen.

    Für Objekte, die am Ende der Funktion nicht mehr existieren.

    Und für welche Sprachen gilt das? Ist das egal, ob C, C++, Java, PHP?

    In Java und PHP kann man meines Wissens keine Zeiger auf lokale Variablen zurückgeben. Ansonsten gilt das in jeder Sprache, wo sowas geht. Pascal zum Beispiel.



  • Bashar schrieb:

    Naja das geht schonmal gar nicht, deine output-Variable ist ja nicht static. Sie wird also zerstört, wenn die Funktion verlassen wird.

    OK, also static dazu und das Problem ist in diesem Fall gelöst, oder?

    Und für welche Sprachen gilt das? Ist das egal, ob C, C++, Java, PHP?

    In Java und PHP kann man meines Wissens keine Zeiger auf lokale Variablen zurückgeben. Ansonsten gilt das in jeder Sprache, wo sowas geht. Pascal zum Beispiel.

    Ja, in Java und PHP meine ich dann entsprechend die (Object-)Referenzen anstatt der Zeiger. Aber wenn ich z.B. in Java innerhalb einer Funktion ein Objekt anlege (also keinen primitiven Datentyp) und zurückgebe und das Objekt ist nicht static, dann gilt das gleiche, wie in C/C++, oder?



  • PS: Danke für die Antworten. 🙂



  • Aber wenn ich z.B. in Java innerhalb einer Funktion ein Objekt anlege (also keinen primitiven Datentyp) und zurückgebe und das Objekt ist nicht static, dann gilt das gleiche, wie in C/C++, oder?

    Nein!

    Du musst unterscheiden, ob du in C++ dein Objekt auf dem Heap (CMyObject *pObj = new CMyObject;) oder auf dem Stack anlegst (CMyObject obj;).

    In C++ wird der Stack automatisch abgeräumt, der Heap muss manuell verwaltet werden. Wenn Du ne Referenz oder einen Pointer auf ein Object auf dem Stack zurückgibst ist das Todsünde.

    Wenn dein Objekt auf dem Heap liegt, dann bleibt es (in C++) erhalten. Du musst es nur irgendwann mit delete wieder löschen, wenn du nicht von anderen Programmieren ausgelacht werden willst.

    Wenn Du dein Objekt im C++ im Datenbereich anlegst (static MyObject obj;) dann wird es vor Programmstart erzeugt und lebst ganz sicher bis zum Ende des Programmes.

    In Java funktioniert die Speicherverwaltung andres. Ich meine primitive Datentypen werden - wenn in einer Funktion deklariert - immer auf dem Stack angelegt. Objekte werden immer auf den Heap (ich weiss nicht genau, ob Java-Programmierer auch Heap dazu sagen). (MyObject obj = new MyObject)

    Das Object lebt solange es noch mindestens eine Referenz darauf gibt. Wenn das nicht der Fall ist, wird das Objekt zum löschen freigegeben.



  • lokaler Speicher schrieb:

    Ja, in Java und PHP meine ich dann entsprechend die (Object-)Referenzen anstatt der Zeiger. Aber wenn ich z.B. in Java innerhalb einer Funktion ein Objekt anlege (also keinen primitiven Datentyp) und zurückgebe und das Objekt ist nicht static, dann gilt das gleiche, wie in C/C++, oder?

    Nein. Java-Objekte liegen nicht auf dem Stack, werden daher auch nicht ueberschrieben. Rueckgabe von Referenzen auf lokal erzeugte Objekte sind daher ungefaehrlich.



  • lokaler Speicher schrieb:

    Bashar schrieb:

    Naja das geht schonmal gar nicht, deine output-Variable ist ja nicht static. Sie wird also zerstört, wenn die Funktion verlassen wird.

    OK, also static dazu und das Problem ist in diesem Fall gelöst, oder?

    Technisch ja. Praktisch hast du dann ein Problem mit der Programmlogik, weil jeder Aufruf der Funktion dir dieses Array überschreibt:

    char* adr1=iptostring(a1);
    cout<<adr1<<endl;
    char* adr2=iptostring(a2);
    cout<<adr1<<" "<<adr2<<endl;
    

    (dieses Problem "löst" der Autor der obigen Funktion mit seinem zweidimensionalen Array - du kannst bis zu 20 IP-Adressen umrechnen lassen, bevor die Funktion beginnt, dir deine Daten zu überschreiben)



  • lokaler Speicher schrieb:

    ...

    In Java und PHP kann man meines Wissens keine Zeiger auf lokale Variablen zurückgeben. Ansonsten gilt das in jeder Sprache, wo sowas geht. Pascal zum Beispiel.

    Ja, in Java und PHP meine ich dann entsprechend die (Object-)Referenzen anstatt der Zeiger. Aber wenn ich z.B. in Java innerhalb einer Funktion ein Objekt anlege (also keinen primitiven Datentyp) und zurückgebe und das Objekt ist nicht static, dann gilt das gleiche, wie in C/C++, oder?

    (Vorab: Eine "Java-Objektreferenz" entspricht in ihrem Verhalten (fast) exakt einem C++-Zeiger [Ausnahme: Aufgrund des andern "Array"-Konzepts gibt es keine "Pointeraritmetik" ... die aber in C++ auch eher überflüssig geworden ist]).

    Also wenn ich das richtig verstanden habe, stimmt das nicht, weil in Java Objekte ja per GC abgeräumt werden. Und der prüft ja, ob es noch Referenzen auf das Objekt gibt ... was zutrifft, wenn Du eine Referenz zurückgibst und die vom Aufrufer übernommen wird.
    Oder kurz gesagt: Bei Java verwendest Du in dem Fall doch auch new, oder ? 😉

    MyObj myFunc() { return new MyObj(); }
    

    <=>

    MyObj* myFunc() { return new MyObj(); }
    

    ... und in beiden Fällen wird das erzeugte MyObj nicht beim Verlassen der Funktion abgeräumt.

    EDIT: habe erst jetzt gesehen, dass Apollon das bereits gesagt hat...

    Gruß,

    Simon2.



  • Also wäre es wohl am Besten so zu schreiben, oder:

    char *iptosting(u_long in)
    {
        char *output = new char[3*4+3+1];
        u_char *p = (u_char *)&in;
        sprintf(output, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
        return output;
    }
    //...
    char *str1 = iptostring(l);
    // str1 benutzen...und am Ende dann
    delete[] str1;
    


  • Finde ich auch fragwuerdig. new und delete sollten IMHO immer symmetrisch auftreten - nicht einmal in einer Funktion und einmal ausserhalb. Dann schon lieber die Variante mit static.



  • Die wahrscheinlich beste Umsetzung wäre:

    void iptosting(char* output, u_long in)
    {
        u_char *p = (u_char *)&in;
        sprintf(output, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
    }
    //...
    char ip_string[3*4+3+1];
    iptostring(ip_string,l); 
    
    cout <<"Die IP: " << ip_string <<endl;
    

    Sicherer und einfach 🙂 .
    Du musst kein ekliges delete [] verwenden und nicht aufpassen dass deine Variable static ist.


Anmelden zum Antworten