Funktionen und "Array von Pointern auf Struct" als Parameter



  • Hallo zusammen!

    Folgendes Problem:

    Ich habe ein kleines Programm geschrieben, welches eine Adressdatei einliest, die aus einem Warenwirtschaftssystem als Textdatei exportiert worden ist. Die Datensätze umfassen jeweils 38 Felder, bestehend aus Strings. Die einzelnen Felder sind jeweils durch Semikolon getrennt. Der jeweils nächste Datensatz ist in der Datei nicht näher gekennzeichnet, daher muß also jeder Datensatz abgezählt werden.

    Hier zunächst der Code zum Öffnen der Datei

    adress.h

    #define MAXFIELDS 38
    #define MAXADDR 2000
    
    typedef struct {
      int number;
      char field[MAXFIELDS][42];
    }t_adress;
    

    adress.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "adress.h"
    
    int open_ascii_adress_file(char *filename,t_adress *adresse[])
    {
    
      FILE *fd;
      int count = 0;
      int entry = 0;
      int row = 0;
      int line = 0;
      char c;
      char buffer[42];
    
      if ((fd = fopen(filename,"r")) == NULL) fprintf(stderr,"Error opening %s \n",filename);
    
      while ((c = getc(fd)) != EOF) {
        if (c == ';') {
          if (count == 38) {
        count = 0;
        entry++;
          }
          buffer[row++] = '\0';
          if ((adresse[entry] = malloc(sizeof(t_adress))) == NULL) 
            fprintf(stderr,"Memory allocation failed");
            exit(1);
          }
          strncpy(adresse[entry]->field[count],buffer,strlen(buffer));
    
          /*
          if (strlen(adresse[entry]->field[count]) >= 1) {
            printf("ID %d SLOT %d", entry, count);
            printf(" -> %s\n ",adresse[entry]->field[count]);
          }
          */
    
          row = 0;
          count++;
          continue;
        }  
        if (  isprint(c) || isdigit(c) ) buffer[row++] = c;
      }
    
      fclose(fd);
    
      return entry;
    }
    

    Diese Funktion liefert die Anzahl der Einträge zurück und schreibt die einzelnen Felder in eine Struktur. Zur Struktur referenziere ich über einen Pointer, den ich aus einem Array lese.

    Das Programm:

    #include <stdio.h>
    #include <stdlib.h>
    #include "adress.h"
    
    int main()
    {
      char *filename = "A01.TXT";
    
      t_adress *my_adresses[MAXADDR];
    
      int entries, i;
      int entry = 0;
      char ch;
    
      entries = open_ascii_adress_file(filename,my_adresses);
    
      do {
        for (i = 0;i < MAXFIELDS;i++)
          printf("%d: %s\n",entry,my_adresses[entry]->field[i]);
        entry++;
        ch = getc(stdin);
      } while ( (entry < entries) && (ch != 'q') && (ch != 'Q'));
    
      return 0;
    }
    

    Da ich ja der Funktion open_ascii_adress_file einen Array von Pointern auf Strukturen übergebe, müsste diese Funktion die Strukturen ja direkt über die Zeiger ändern können. Innerhalb der Funktion sind die Daten ja vorhanden, wie ich durch den auskommentierten Teil nachweisen kann. Möchte ich die Daten in main() ausgeben, erhalte ich eine leere Ausgabe. Ich verstehe an dieser Stelle nicht warum, da ich ja alle Daten über Zeiger anspreche. Habe ich hier grundsätzlich etwas nicht verstanden, oder lediglich eine Kleinigkeit übersehen?

    [ Dieser Beitrag wurde am 11.01.2003 um 13:15 Uhr von ReSeT editiert. ]



  • Du machst Dir IMHO zusätzliche Arbeit, wo keine ist. Nebenbei baust Du noch nen schönen Fehler ein: Hier mal ein einfaches Beispielprogramm:

    #include <stdio.h>
    
    typedef struct {
        int d;
    } tData;
    
    void f(tData *Data[])
    {
        Data[0]->d = 0;
        Data[1]->d = 1;
        Data[2]->d = 2;
        Data[3]->d = 3;
    }
    
    int main(void)
    {
        tData *myData[100];  /* myData = 100 Zeiger auf tData */
    
        /* woher Speicher??? */
        f(myData);
    
        return 0;
    }
    

    Das Problem hier ist, dass "myData" ein Zeiger-Array ist. Diese Zeiger sind nicht initialisiert und somit "ungültig". Du müsstest also zuerst mit malloc() ausreichend Speicher besorgen...

    Bessere Version:

    #include <stdio.h>
    
    typedef struct {
        int d;
    } tData;
    
    void f(tData Data[])
    {
        Data[0].d = 0;
        Data[1].d = 1;
        Data[2].d = 2;
        Data[3].d = 3;
    }
    
    int main(void)
    {
        tData myData[100];  /* myData = 100 tData */
    
        f(myData);
    
        return 0;
    }
    

    Hier sind die Definition von "myData" und "f()" anders. Auch Der Datenzugriff innerhalb von f() ist anders. Das Programm funktioniert zwar, kann aber sehr "teuer" werden, wenn die Struktur groß wird und viele Datensätze eingelesen werden sollen. Besser wäre dann eine Version, die dynamisch Speicher anfordert, aber nur soviel, wie eben gebraucht wird. Stichwort: realloc().

    Hoffe, ich konnte Dir helfen.



  • Das ist es gerade, was ich nicht verstehe. Ich deklariere einen Array von Pointern auf einen eigenen Datentypen (typedef struct). Diesen übergebe ich dann einer Funktion, die Speicher für die einzelnen Zeiger in dem Array anfordert,

    if ((adresse[entry] = malloc(sizeof(t_adress))) == NULL)
    .
    .
    .
    

    das müsste doch völlig korrekt sein.

    vgl.hierzu K&R - Programmieren in C S.104 ff.

    [ Dieser Beitrag wurde am 10.01.2003 um 14:32 Uhr von ReSeT editiert. ]

    [ Dieser Beitrag wurde am 10.01.2003 um 14:38 Uhr von ReSeT editiert. ]



  • Wenn Du ein Array an eine Funktion übergibst, wird automatsch ein Zeiger auf das erste Element in diesem Array übergeben. Das hat hauptsächlich Geschweindigkeitsgründe. Das ist auch der Grund dafür, warum viele Leute nicht verstehen, dass ein Array != Zeiger ist, obwohl beim Zugriff auf die einzelnen Elemente und bei der Funktionsübergabe als Parameter die gleiche Syntax verwendet wird.

    if ((adresse[entry] = malloc(sizeof(t_adress))) == NULL) fprintf(stderr,"Memory allocation failed");
    

    Diese Zeile hab' ich doch glatt übersehen....

    ich schau mir Dein progy nochmal an ... 🙂



  • Hat denn niemand eine Idee?



  • warum kann das nicht gehen:

    void alloc(void* p, size_t size)
    {
    p=malloc(size);
    }

    Weil eben nur eine KOPIE von p uebergeben wird. da p aber ein Zeiger ist, zeigt original und kopie auf den selben speicher. wenn du der kopie nun sagst: zeige auf etwas anderes (malloc), dann aenderst du ja nicht das objekt, auf welches gezeigt wird, sondern du sagst nur der kopie, sie soll woanders hinzeigen.

    wenn die kopie woanders hinzeigt, dann zeigen original und kopie nicht mehr auf den selben speicher - folglich kommt kaese raus.

    dein ganzer ansatz ist speicher technisch ein wahnsinn. dein problem kannst du zwar mit zeiger auf zeiger umgehen, aber die speicher loecher bleiben trotzdem bestehen...

    in c hat der caller den speicher bereitzustellen!



  • Weil eben nur eine KOPIE von p uebergeben wird. da p aber ein Zeiger ist, zeigt original und kopie auf den selben speicher. wenn du der kopie nun sagst: zeige auf etwas anderes (malloc), dann aenderst du ja nicht das objekt, auf welches gezeigt wird, sondern du sagst nur der kopie, sie soll woanders hinzeigen.

    Das hat mir geholfen, Danke.

    Ich werd' mich dann mal an den Umbau machen.

    Woher hab ich nur gewusst, das die Lösung von Dir kommen wird. 🙂



  • Hallo!

    Ich habe mich nochmals etwas mit dem Thema Vektoren von Zeigern befasst und bin zu folgendem Ergebnis gekommen:

    Genau wie einen Zeiger kann ich Vektoren von Zeigern an Funktionen übergeben, es wird immer direkt die Speicheradresse auf die der Zeiger zeigt behandelt, sei sie aus einem Vektor oder nicht. Es spielt auch keine Rolle, ob der Zeiger bereits einen sinnvollen Inhalt hat oder nicht, solange ich ungültige Zeiger nicht referenziere.

    vgl K&R Programmieren in C S.93 ff., S.104 ff.

    Das Problem in obigem Programm ist ein ganz anderes:

    Der Speicher für adresse[entry] wird bei jedem Semikolon neu alloziert anstatt bei jedem 38sten.Somit ist der gewünschte Speicher nicht adressierbar. Das kann nicht funktionieren.

    Folgender Ansatz ist ANSI konform und laut meinem Verständnis und meinen schlauen Büchern korrekt.

    int open_ascii_adress_file(char *filename,t_adress *adresse[])
    {
      FILE *fd;
      int count = 0;
      int entry = 0;
      int row   = 0;
      int line  = 0;
      char c;
      char buffer[42];
    
      if ((fd = fopen(filename,"r")) == NULL) {
        fprintf(stderr,"Error opening %s \n",filename);
        exit(1);
      }
    
      if ((adresse[entry] = malloc(sizeof(t_adress))) == NULL) {
        fprintf(stderr,"Memory allocation failed");
        exit(1);
      }
    
      while ((c = getc(fd)) != EOF) {
        if (c == ';') {
          if (count == 38) {
        count = 0;
        entry++;
        if ((adresse[entry] = malloc(sizeof(t_adress))) == NULL) {
          fprintf(stderr,"Memory allocation failed");
          exit(1);
        }
          }
          buffer[row++] = '\0';
          strncpy(adresse[entry]->field[count],buffer,strlen(buffer)+1);
          row = 0;
          count++;
          continue;
        }  
        if ( isprint(c) || isdigit(c) ) buffer[row++] = c;
      }
    
      fclose(fd);
    
      return entry;
    }
    

    GreetZ
    ReSeT

    [ Dieser Beitrag wurde am 13.01.2003 um 20:56 Uhr von ReSeT editiert. ]


Anmelden zum Antworten