Structur array dynamisch, Pfeiloperator ist äquivalent wie Punktoperator?



  • Hallo,

    ich habe ein C-Programm geschrieben dass mir alle Dateinamen im aktuellen Ordner in ein dynamisches Struktur Array speichert. Da es sich um eine dynamische Struktur handelt (also Zeiger auf die Strukut: *gefundeneDateinamen) muss ich ja den Pfeiloperator verwenden um auf die Variabeln zuzugreifen: gefundeneDateinamen->name

    Was mich aber wundert, bzw. ich nicht verstehe ist dass auch der Punktoperator funktioniert: gefundeneDateinamen[count].name. Ich dachte dass der Punktoperatur dann verwendet wenn es sich um eine Normale Struktur handelt. Also kann ich mit beiden Varianten auf eine Zeiger Strukur zugreifen? Ist das äquivalent? Danke!

    #include <stdio.h>
    #include <dirent.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    typedef struct{
    
        char name[50];
    
    }GefundeneDateinamen;
    
    int main(void)
    {
    
        int anzahlDateienMax = 10;
        int count =0;
    
        DIR *dirp;
        struct dirent *entry;
    
        GefundeneDateinamen *gefundeneDateinamen = (GefundeneDateinamen*)(malloc(anzahlDateienMax * sizeof(GefundeneDateinamen)));
    
        dirp = opendir(".");
    
        while ((entry = readdir(dirp)) != NULL) {
                if ( !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") )
                {
    
                }
                 else {
                   //gefundeneDateinamen->name = (char*)malloc(sizeof(char)*(strlen(entry->d_name)+1)); // Dynamische allokation von aktuellerName
                     strncpy (gefundeneDateinamen[count].name,entry->d_name, strlen(entry->d_name) );
                     gefundeneDateinamen[count].name[strlen(entry->d_name) ] = '\0';
                     // gefundeneDateinamen->name ist gleich wie gefundeneDateinamen[count].name?
                     printf("%s\n",gefundeneDateinamen[count].name );
                     printf("%s\n",gefundeneDateinamen->name ); 
                     count++;
                }
            }
        closedir(dirp);
    
    
        return(0);
    }
    
    
    
    


  • Das liegt daran, daß generell ein Arrayzugriff array[n] äquivalent zu *(array + n) ist, d.h. es findet schon eine Dereferenzierung statt (so daß man dann den Punktoperator zum Zugriff auf die Struktur verwendet kann).
    Und der Pfeiloperator pointer->x ist wiederum äquivalent zu (*pointer).x.
    Sofern du den Zeiger nicht in deiner Schleife veränderst, gibt also printf("%s\n",gefundeneDateinamen->name ) immer den gleichen (d.h. ersten) Dateinamen des Ordners aus.

    PS: Bedenke, daß du bei deinem Code vor dem strncpy die Länge (max. 50) vorher überprüfen solltest, um keinen Speicherüberschreiber zu haben.



  • Achso , du meinst vermutlich so etwas: if(strlen(entry->d_name)<50)

    Wie ist das eigentlich wenn ich in der Struktur selbst einen char Pointer verwende? Also char *name; anstatt char name[50];
    Dann muss ich in meiner while Schleife bei jedem Durchgang für name (mit malloc) Speicher reservieren?
    Und ich muss jeden Zeiger um 1 so erhöhen: (gefundeneDateinamen+count)

    Es funktioniert zwar so aber ist mein Code so auch korrekt? (Also ohne irgendwelchen Buffer overflow?)

    #include <stdio.h>
    #include <dirent.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    typedef struct{
    
        char *name;
    
    }GefundeneDateinamen;
    
    int main(void)
    {
    
        int anzahlDateienMax = 10;
        int count =0;
    
        DIR *dirp;
        struct dirent *entry;
    
        GefundeneDateinamen *gefundeneDateinamen = (GefundeneDateinamen*)(malloc(anzahlDateienMax * sizeof(GefundeneDateinamen)));
    
        dirp = opendir(".");
    
        while ((entry = readdir(dirp)) != NULL) {
                if ( !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") )
                {
    
                }
                 else {
                     if(strlen(entry->d_name)<50)
                        {
                     (gefundeneDateinamen+count)->name = (char*)malloc(sizeof(char)*(strlen(entry->d_name)+1));
                     strncpy ((gefundeneDateinamen+count)->name,(entry->d_name), strlen(entry->d_name)+1 );
                     (gefundeneDateinamen+count)->name[strlen(entry->d_name) ] = '\0';
                     printf("%s\n",(gefundeneDateinamen+count)->name );
                     count++;
                        }
                }
            }
        closedir(dirp);
    
    
        return(0);
    }
    


  • Ja, so ist es jetzt [überwiegend] korrekt (aber dann brauchst du auch die Abfrage auf < 50 nicht, da du ja dynamisch Speicher allozierst).
    Du solltest allerdings nur einmalig strlen(...) berechnen und in einer lokalen Variable speichern und benutzen.
    Außerdem ist die ... = '\0'-Zeile überflüssig, da du in der Zeile vorher ja das Nullterminalzeichen schon mitkopierst (wegen strlen(...) + 1).
    Und ich habe zwar geschrieben, daß die Ausdrücke äquivalent sind, jedoch ist eher unüblich die Schreibweise (pointer+count)->x zu verwenden. Stattdessen wird (auch aus Performancegründen) eine lokale Zeigervariable benutzt und erhöht:

    char *p = gefundeneDateinamen;
    while (...)
    {
        // ...
        size_t len = strlen(strlen(entry->d_name);
        p->name = malloc(len + 1); // in C solltest du keinen Cast (hier: (char*) )verwenden!
        strncpy(p->name, entry->d_name, len + 1);
        // ...
        p++;
    }
    

    Und sizeof(char) ist auch (als Multiplikator) überflüssig, da es immer 1 ist!

    PS: Außerdem solltest du noch die korrekte Speicherfreigabe ausprogrammieren (auch wenn der Speicher automatisch beim Beenden des Prozesses vom OS freigegeben wird), am besten als eigenständige Funktion - genauso wie das Einlesen.
    Ich sehe gerade, daß du bisher auch die Anzahl der Dateien fest einprogrammiert hast - auch das solltest du entweder abfragen (und die Schleife beenden) oder aber realloc verwenden, um dynamisch den Speicher zu vergrößern.



  • Ok, danke für die Hilfe/Tipps.


Anmelden zum Antworten