Frage: Gültigkeitsbereiche von Variablen



  • Hallo zusammen, ich probier mich grade an C aus.
    Ich habe folgende Frage:

    typedef struct MeinStruct
    {
    char *name;
    int alter;
    }meins;

    meins *erstelleStruktur()
    {
    meins m;
    m.name = "xyz";
    m.alter = 17;

    return &m; //main.c:76: warning: function returns address of local variable
    }

    void gibStrukturAus(meins *ptr)
    {
    printf("Name: %s, Alter: %d\n", ptr->name, ptr->alter);
    }

    Ich möchte also in der Funktion "meins *erstelleStruktur()", eine Struktur erzeugen und einen Pointer darauf zurück liefern.
    Was mich wundert ist, dass das so funktioniert ohne das ich mit malloc(sizeof(meins)) Speicher für das Objekt reservieren brauche.
    Meine Erwartung war, das "meins *erstelleStruktur()" irgendeinen Zeiger ins Nichts liefert. Sattdessen kommen immer die korrekten Werte bei "void gibStrukturAus(meins *ptr)" an. Ich weiß das ich irgendwas diesbezüglich falsch / noch nicht verstanden habe. Aber was?
    Ich dachte das "meins m" auch nur Gültigkeit (existiert) innerhalb "meins *erstelleStruktur()" besitzt?

    Vielen Dank im vorraus für die Hilfe



  • Dass das funktioniert, ist Glück, Zufall oder sonstwas. m wird zerstört, sobald erstelleStruktur verlassen wird. Das heißt nun nicht, dass der von m belegte Speicher sofort überschrieben wird, aber er gehört Dir nicht mehr, und was da nun in Zukunft steht, ist undefiniert.



  • Dirty schrieb:

    Meine Erwartung war, das "meins *erstelleStruktur()" irgendeinen Zeiger ins Nichts liefert.

    Dein erstelleStruktur() liefert dir die Adresse auf die lokale struct.
    Der Bereich wo die struct steht, wird beim verlassen der Funktion nicht gelöscht oder überschrieben.
    In den Bereich können nur jederzeit wieder irgendwelche Daten geschrieben werden, was i.A. bei jedem Funktionsaufruf passiert.

    Schreib doch mal das printf("Name: %s, Alter: %d, Adresse: %p\n", ptr->name, ptr->alter, ptr); in deine main() (nicht in gibStrukturAus()) direkt hinter erstelleStruktur() und schau mal was dann passiert.



  • Gut. verstanden... noch eine Frage:

    Funktion:
    int *addiereRef(int a, int b)
    {
    int *ptr = (int *)malloc(sizeof(int));

    int c;
    c = a+b;

    *ptr = c;
    printf("Adresse von erzeugtem ptr: %p --- ", &ptr);
    return ptr;
    }

    Aufruf:
    printf("Adresse von zurueckgegeben ptr = %p\n", &(*addiereRef(3,7))); // Mit (*add...) von Zeiger dereferenzieren und davon durch & Adresse anfordern -> Ist das so korrekt?

    Ausgabe:
    lokale Adresse ptr: 0x28cd04 --- Adresse von zurueckgegeben ptr = 0xad01c0

    Meine Frage:
    Meine Erwartung war, das die beiden in der Ausgabe gezeigten Adressen identisch sein müssten. Sind sie aber nicht. Wieso?



  • Dirty schrieb:

    Meine Erwartung war, das die beiden in der Ausgabe gezeigten Adressen identisch sein müssten. Sind sie aber nicht. Wieso?

    Weil du hier die Adresse des Pointers ermittelst, du aber 2 verschiedene Pointer hast, die auf den selben Bereich zeigen.
    Auch Pointer müssen ihre Adressen irgendwo speichern. Und diese Speicherstellen haben auch Adressen, die man mit & ermitteln kann.
    Lass mal bei deinen prinfs das & weg.

    #include <stdio.h>
    
    int main()
    {
      int i = 5;
      int *p1 = &i;
      int *p2 = &i;
    
      printf("Inhalt von   i: %d, Adresse von  i: %p\n", i, &i);
      printf("Inhalt von *p1: %d, Inhalt  von p1: %p, Adresse von p1: %p\n", *p1, p1, &p1);
      printf("Inhalt von *p2: %d, Inhalt  von p2: %p, Adresse von p2: %p\n", *p2, p2, &p2);
    
      return 0;
    }
    

    p1 und p2 zeigen beide auf den selben Bereich (der Inhalt von p1 und p2 ist der Gleiche), haben aber selber unterschiedliche Adressen, da es auch verschiedene Zeiger sind

    PS. Auch du solltest die C/C++ Tags verwenden. Text markieren und auf den Button unter den 🙂 😃 klicken.



  • Wieso habe ich hier 2 Pointer? Ich belege in der Methode mit malloc einen Speicherbereich, indessen Wert ich den Wert von der Variablen c schreibe.

    Genau diesen Pointer gebe ich dann durch return zurück und lasse mir in printf(..) in der main(...) diese Adresse ausgeben?

    Wo ist der 2te Pointer, was habsch übersehn? 🙂



  • int *ptr = (int *)malloc(sizeof(int));
       ...
      printf("Adresse von erzeugtem ptr: %p --- ", &ptr); //
      return ptr; // Hier gibst du den Inhalt von ptr zurück (nicht *ptr und nicht &ptr).
    }
    
    //Aufruf:
    printf("Adresse von zurueckgegeben ptr = %p\n", &(*addiereRef(3,7))); 
    //                                              ^ Hier bekommst du impliziet einen neuen Pointer, von dem du die Adresse anzeigst.
    

    Wenn du das printf aufdröselst kommt doch sowas raus:

    int *i_ptr;
      i_ptr = addiereRef(3,7);
      printf("Adresse von zurueckgegeben i_ptr = %p\n", &i_ptr); 
    // Da siehst du deine 2 Pointer.
    
    // Aber ich denke, du willst das hier haben:
      printf("Adresse von malloc Bereich       = %p\n",  i_ptr); 
      printf("Inhalt vom malloc Bereich        = %d\n", *i_ptr);
    


  • DirkB schrieb:

    //Aufruf:
    printf("Adresse von zurueckgegeben ptr = %p\n", &(*addiereRef(3,7))); 
    //                                              ^ Hier bekommst du impliziet einen neuen Pointer, von dem du die Adresse anzeigst.
    

    Nicht ganz, DirkB. &(*addiereRef(3,7)) gibt einfach nur die Adresse des allokierten Speicherbereichs zurück. Also direkt den Rückgabewert der Funktion, und keine Adresse irgeneines zweiten Zeigers.
    Der Rückgabewert bleibt nämlich vermutlich nur in einem Register und hat damit keine Speicheradresse. Dein zweites Beispiel ist etwas ganz anderes, da du den Rückgabewert in einer lokalen Variable speicherst. Diese hat natürlich eine Adresse.



  • Der Rückgabewert steht wohl in einem Register. Nur wenn der Wert dann an printf übergeben wird, steht er auf dem Stack. Und dann hat er eine Adresse.

    @Dirty:
    Schau doch mal bei http://www.c-plusplus.net/forum/293802 den Link zu Deep C an.



  • F schrieb:

    Nicht ganz, DirkB. &(*addiereRef(3,7)) gibt einfach nur die Adresse des allokierten Speicherbereichs zurück. Also direkt den Rückgabewert der Funktion, und keine Adresse irgeneines zweiten Zeigers.

    Noch mal überlegt und auch die Ergebnisse angesehen: Du hast recht.

    Der Unterschied in der Ausgabe kommt von dem Adressoperator in addiereRef().


Anmelden zum Antworten