unerw. Verhalten nach Füllen & Ausgeben eines Arrays



  • Hey Leute!

    Ich bin ein wenig schwach in C und wollte mich desshalb ein wenig auffrischen. Bei meiner simplen rendering library (lediglich zum vereinfachten Füllen von arrays) stoße ich zZt. auf Verhalten, dass ich nicht nachvollziehen kann.

    Folgende Sachlage:

    Ich habe eine "Konstruktor" Funktion welche mir einen typefed Typ "Canvas" erstellt und einen Pointer auf diesen zurück gibt.

    typedef struct{
      ArrayDimension dimension;
      char* array;
    }Canvas;
    

    Hier die Konstruktor Funktion & die Initialisierungsfunktion welche das Array mit bestimmten Werten komplett füllen soll.

    Canvas* createNewCanvas(int height, int width){
      ArrayDimension dimension ;
      Canvas* newCanvas = malloc(sizeof(Canvas));
      char array[height][width];
    
      /* Width: 5, Height: 5 */
    
      dimension.height = height;
      dimension.width = width;
      newCanvas->dimension = dimension;
      newCanvas->array = array[0];
    
      return newCanvas;
    }
    
    void initializeArray(Canvas* newCanvas, char fillSymbol){
      char* arrayToInit = newCanvas->array;
      int iterator_X;
    
      printf("#filling array...\n");
      for(iterator_X = 0; iterator_X < 5; iterator_X++){
        printf("-----------------------\n");
        printf("adress: %p\n", arrayToInit+iterator_X);
        printf("before fill: %c\n", *(arrayToInit+iterator_X));
        *(arrayToInit+iterator_X) = fillSymbol;
        printf("after fill: %c\n", *(arrayToInit+iterator_X));
        printf("-----------------------\n");
      }
    
      printf("#printing array...\n");
      for(iterator_X = 0; iterator_X < 5; iterator_X++){
        printf("pointer: %p\n", arrayToInit+iterator_X);
        printf("current: %c\n", *(arrayToInit+iterator_X));
      }
    }
    

    Die initializeArray Funktion hat natürlich eine andere Logik, jedoch möchte ich den Fokus einfach auf das Füllen der Werte und der Ausgabe der Werte einmal direkt beim Füllen (filling array...), also in der for-Schleife und dann nochmal eine Ausgabe mit dem gleichen Statement wie beim Füllen (#printing array...)

    Und beim ausführen der Main.c, welche ledigliche folgendes tut:

    Main.c

    int main(void){
      Canvas* canvas = createNewCanvas(ARRAY_HEIGHT, ARRAY_WIDTH);
      initializeArray(canvas, 'X');
    
      return 0;
    }
    

    gibt es folgenden Output:

    #filling array...
    -----------------------
    adress: 0x7fff94078dd0
    before fill: -
    after fill: X
    -----------------------
    -----------------------
    adress: 0x7fff94078dd1
    before fill: -
    after fill: X
    -----------------------
    -----------------------
    adress: 0x7fff94078dd2
    before fill: -
    after fill: X
    -----------------------
    -----------------------
    adress: 0x7fff94078dd3
    before fill: -
    after fill: X
    -----------------------
    -----------------------
    adress: 0x7fff94078dd4
    before fill: -
    after fill: X
    -----------------------
    #printing array...
    pointer: 0x7fff94078dd0
    current: a
    pointer: 0x7fff94078dd1
    current: m
    pointer: 0x7fff94078dd2
    current: 
    pointer: 0x7fff94078dd3
    current: 
    pointer: 0x7fff94078dd4
    current: D
    

    Obwohl ich die zweite Ausgabe direkt nach dem Füllen, und sogar dessen direkte Ausgabe in der Schleife, ansetze - unterscheiden sich die Ergebnisse.

    Mir kommt es fast so vor als würden die Werte des Arrays nach dem Abschluss der Schleife einfach wieder vom System überschrieben. Das Array selber ist ja im typdef struct Canvas deklariert und im Konstruktor wird es definiert/initialisert.

    Meine Vermutung:

    Da das Array nicht ge-malloc-ed wurde im Konstruktor, demnach kein "gesperrter" Speicher ist, kann ich zwar gerne auf die Adresse schreiben, die Ausgabe direkt nach dem Schreiben funktioniert auch, da der Thread unmittelbar die Speicherstelle ausliest - jedoch wird beim zweiten Aufruf von printf der Adressraum an jeden weiter gegeben wer möchte?

    Ich würde demnach gleich das char-array mit malloc Speicher zuweisen welchen ich natürlich selber wieder freigeben muss.

    ---

    Liege ich mit der Vermutung soweit richtig? Oder steckt da noch einiges mehr dahinter?

    Gruß Charlie!



  • Du hast einfach nur einen Zeiger auf eine nicht mehr existente variable (vla sind Btw blöd). Da kann alles passieren, wenn du über diesen Zeiger zugreifst.



  • Du hast mit deiner Vermutung recht, Zeile 4 ist ein sogenanntes VLA (was nur Deppen benutzen), dessen Speicher wird ungültig und der Zugriff darauf UB wenn du die Funktion verlässt.
    Ersetze Zeile 4 durch

    =calloc(height,width);
    

    und schreibe einen "Destruktor", in dem du free dafür aufrufst.
    Und ersetze deine albernen

    *(arrayToInit+iterator_X)
    

    Konstruktionen durch

    arrayToInit[iterator_X]
    


  • Okay klingt logisch.

    Danke für die Hilfe
    Und denkt dran, man ist kein Depp oder albern wenn man Anfänger ist 🙂

    PS: DANKE danke ... Der Kram hat mir echt den Arsch gerettet 😃


Log in to reply