Dynamische Datenstrukturen



  • Also ich glaube langsam wirklich das es irgendwo ein Speicherproblem ist, weil ich habe jetzt die VM Heruntergefahren und gestartet und jetzt geht die Funktion IPKQKDynListStringAnhaengen wieder.

    Aber dafür IPKQKDynListStringAusgabe nicht. Da bekomme ich jetzt wieder die Fehlermeldung 'IPKQKDynListStringAusgabe': unresolved external function

    Kann jemand mal bitte das am Anfang beschriebene Programm testen? So langsam verzweifel ich. Vielen Dank



  • Also ich habe nun mal folgendes gemacht:

    Ich habe das beispiel von Galileo Computing genommen und den Dev-C++ Compiler

    Das beispiel funktioniert.

    Nun habe ich es etwas abgespeckt und den Header in eine eigene Datei gelegt. (um langsam an mein Beispiel herran zu kommen.)

    Header (Dateiname: angestellt.h)

    struct angestellt{
       char name[MAX];
       struct angestellt *next;
    };
    
    struct angestellt *next   = NULL;
    struct angestellt *anfang = NULL;
    

    Main: (Dateiname: main.c)

    /* linear_list2.c */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <angestellt.h>
    #define MAX 20
    
    void anhaengen(char *n) {
       struct angestellt *zeiger;
    
       if(anfang == NULL) {
    
          if((anfang =
           malloc(sizeof(struct angestellt))) == NULL) {
             fprintf(stderr, "Kein Speicherplatz vorhanden "
                             "für anfang\n");
             return;
          }
          strcpy(anfang->name, n);
    
          anfang->next=NULL;
       }
    
       else {
          zeiger=anfang; 
          while(zeiger->next != NULL)
             zeiger=zeiger->next;
    
          if((zeiger->next =
           malloc(sizeof(struct angestellt))) == NULL) {
              fprintf(stderr,"Kein Speicherplatz für das "
                             "letzte Element\n");
              return;
          }
          zeiger=zeiger->next; 
          strcpy(zeiger->name,n);
          zeiger->next=NULL;
       }
    }
    
    /* Funktion zum Ausgeben der Dateien */
    void ausgabe(void) {
       struct angestellt *zeiger = anfang;
    
       while(zeiger != NULL) {
          printf("%12s\n",
             zeiger->name);
             zeiger=zeiger->next;
       }
    }
    
    int main(void) {
       int wahl;
       char dname[MAX];
    
       do {
          printf("\n1 : Eingabe\n");
          printf("2 : Ausgabe\n");
          printf("9 : Ende\n");
          printf("Ihre Wahl : ");
          scanf("%d",&wahl);
          getchar();
          switch(wahl) {
             case 1 : anhaengen("TestX");
                      break;
             case 2 : ausgabe();
                      break;
             case 9 : break;
             default: printf("Falsche Eingabe!!!\n");
          }
       } while(wahl != 9);
       return EXIT_SUCCESS;
    }
    

    Soweit so gut alles Funktioniert:

    nun wollte ich die Funktion anhaengen in eine eigene Datei legen:

    Also:

    Main Datei (Dateiname main.c)

    /* linear_list2.c */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <angestellt.h>
    #define MAX 20
    
    /* Funktion zum Ausgeben der Dateien */
    void ausgabe(void) {
       struct angestellt *zeiger = anfang;
    
       while(zeiger != NULL) {
          printf("%12s\n",
             zeiger->name);
             zeiger=zeiger->next;
       }
    }
    
    int main(void) {
       int wahl;
       char dname[MAX];
    
       do {
          printf("\n1 : Eingabe\n");
          printf("2 : Ausgabe\n");
          printf("9 : Ende\n");
          printf("Ihre Wahl : ");
          scanf("%d",&wahl);
          getchar();
          switch(wahl) {
             case 1 : anhaengen("TestX");
                      break;
             case 2 : ausgabe();
                      break;
             case 9 : break;
             default: printf("Falsche Eingabe!!!\n");
          }
       } while(wahl != 9);
       return EXIT_SUCCESS;
    }
    

    und Funktion Anhängen (Dateiname: anhaengen.c)

    /* linear_list2.c */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <angestellt.h>
    #define MAX 20
    
    void anhaengen(char *n) {
       struct angestellt *zeiger;
    
       if(anfang == NULL) {
    
          if((anfang =
           malloc(sizeof(struct angestellt))) == NULL) {
             fprintf(stderr, "Kein Speicherplatz vorhanden "
                             "für anfang\n");
             return;
          }
          strcpy(anfang->name, n);
    
          anfang->next=NULL;
       }
    
       else {
          zeiger=anfang; 
          while(zeiger->next != NULL)
             zeiger=zeiger->next;
    
          if((zeiger->next =
           malloc(sizeof(struct angestellt))) == NULL) {
              fprintf(stderr,"Kein Speicherplatz für das "
                             "letzte Element\n");
              return;
          }
          zeiger=zeiger->next; 
          strcpy(zeiger->name,n);
          zeiger->next=NULL;
       }
    }
    

    nun wollte ich es compilieren aber bekomme folgende Fehlermeldung:

    multiple definition of next' first defined here multiple definition ofanfang'
    first defined here
    ld returned 1 exit status
    C:\Dev-Cpp\Projekt Denis\Makefile.win [Build Error] [Projekt1.exe] Error 1

    Was muss ich machen damit ich diese Meldung nicht mehr bekomme bzw. wie würde der Lösungsweg aussehen?

    vielleicht ist dies mein Problem was ich auch beim SIEMENS Compiler habe aber er es nicht richtig anzeigt...

    Vielen lieben Dank an euch schon mal
    MfG



  • Der Compiler (in diesem Fall sogar der Linker) hat wie immer Recht.
    Du inkludierst die Definition von next+anfang 2 mal durch 2 maliges Inkludieren von <angestellt.h>, was üblicherweise "angestellt.h" heissen sollte.
    Ich kann immer noch keinen Compilerfehler entdecken.



  • Mit

    struct angestellt *next   = NULL;
    struct angestellt *anfang = NULL;
    

    legst du die Variablen (Zeiger) next und anfang an.

    Das passiert jedesmal wenn die Datei includiert wird.

    Schreib das einfach an den Anfang der Datei mit main. Nach den #include und #define.



  • Also Danke schon mal an DirkB das werde ich gleich einmal außprobieren, aber erst noch einmal zu Wutz:

    Was ist der Unterschied zwischen <> und ""

    und wie soll ich das jetzt nach deiner Meinung machen, damit ich das nicht doppelt Includiere?

    Weil ich hätte das schon gerne im Header, außer das ist nicht möglich dann mach ich es halt wie DirkB es beschreibt.



  • <> sucht die includes im Compilerpfad.
    "" sucht auch im aktuellen Verzeichnis (da wo die C-Datei steht).

    Variablendeklarationen haben in Headerdateien nichts zu suchen.



  • Falsch.
    Deklarationen gehören genau in Headerdateien.
    Definitionen gehören da nicht hin.



  • Ich habe das beispiel von Galileo Computing genommen und den Dev-C++ Compiler

    2 Fehler auf einmal, Gratulation 👍
    Sind die Initialen des Autors zufälligerweise J.W.? 🤡


  • Mod

    314159265358979 schrieb:

    Sind die Initialen des Autors zufälligerweise J.W.? 🤡

    Ja, sind sie, wie man am Link im ersten Beitrag sieht.



  • Ah, stimmt, danke. 😃



  • Also entweder stelle ich mich zu blöde an oder ich versteh das nicht richtig.

    ich habe jetzt

    struct angestellt *next = NULL; UND
    struct angestellt *anfang = NULL;

    aus den Header genommen und in der main Funktion eingefügt

    main.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "angestellt.h"
    #define MAX 20
    
    struct angestellt *next   = NULL;
    struct angestellt *anfang = NULL;
    
    /* Funktion zum Ausgeben der Dateien */
    void ausgabe(void) {
       struct angestellt *zeiger = anfang;
    
       while(zeiger != NULL) {
          printf("%12s\n",
             zeiger->name);
             zeiger=zeiger->next;
       }
    }
    
    int main(void) {
       int wahl;
       char dname[MAX];
    
       do {
          printf("\n1 : Eingabe\n");
          printf("2 : Ausgabe\n");
          printf("9 : Ende\n");
          printf("Ihre Wahl : ");
          scanf("%d",&wahl);
          getchar();
          switch(wahl) {
             case 1 : anhaengen("TestX");
                      break;
             case 2 : ausgabe();
                      break;
             case 9 : break;
             default: printf("Falsche Eingabe!!!\n");
          }
       } while(wahl != 9);
       return EXIT_SUCCESS;
    }
    

    jetzt würde ich davon ausgehen das alles richtig ist oder?

    Warum bekomme ich immernoch den Fehler?

    multiple definition of next' first defined here multiple definition ofanfang'
    first defined here
    ld returned 1 exit status



  • So jetzt hab ich glaube ich verstanden was Ihr meint.

    Moment Post kommt gleich.



  • Also ich würde sagen ich fasse das mal alles zusammen.

    Zunächst der Quellcode:

    Header: angestellt.h

    struct angestellt{
       char name[20];
       struct angestellt *next;
    };
    
    struct angestellt *next;
    struct angestellt *anfang;
    

    Main: main.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "angestellt.h"
    #define MAX 20
    
    struct angestellt *next   = NULL;
    struct angestellt *anfang = NULL;
    
    /* Funktion zum Ausgeben der Dateien */
    void ausgabe(void) {
       struct angestellt *zeiger = anfang;
    
       while(zeiger != NULL) {
          printf("%12s\n",
             zeiger->name);
             zeiger=zeiger->next;
       }
    }
    
    int main(void) {
       int wahl;
       char dname[MAX];
    
       do {
          printf("\n1 : Eingabe\n");
          printf("2 : Ausgabe\n");
          printf("9 : Ende\n");
          printf("Ihre Wahl : ");
          scanf("%d",&wahl);
          getchar();
          switch(wahl) {
             case 1 : anhaengen("TestX");
                      break;
             case 2 : ausgabe();
                      break;
             case 9 : break;
             default: printf("Falsche Eingabe!!!\n");
          }
       } while(wahl != 9);
       return EXIT_SUCCESS;
    }
    

    und Anhängen: anhaengen.c

    /* linear_list2.c */
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "angestellt.h"
    #define MAX 20
    
    void anhaengen(char *n) {
       struct angestellt *zeiger;
    
       if(anfang == NULL) {
    
          if((anfang =
           malloc(sizeof(struct angestellt))) == NULL) {
             fprintf(stderr, "Kein Speicherplatz vorhanden "
                             "für anfang\n");
             return;
          }
          strcpy(anfang->name, n);
    
          anfang->next=NULL;
       }
    
       else {
          zeiger=anfang; 
          while(zeiger->next != NULL)
             zeiger=zeiger->next;
    
          if((zeiger->next =
           malloc(sizeof(struct angestellt))) == NULL) {
              fprintf(stderr,"Kein Speicherplatz für das "
                             "letzte Element\n");
              return;
          }
          zeiger=zeiger->next; 
          strcpy(zeiger->name,n);
          zeiger->next=NULL;
       }
    }
    

    Also in der Header datei dürfen nur die Deklarationen stehen aber keine Zuweisung von Werten auch nich NULL da sonnst dieser Variable bei jeden Funktion angelegt wird indem das Include vorhanden ist. (Was beim Übersetzen auch ein guter (etwas besserer) Compiler auch nicht zulässt.

    Somit darf also der Header nur so aussehen wie oben beschrieben und nicht so wie in den anderen Beispielen dieses Beitrages.

    Damit aber next und Anfang zu beginn auf NULL stehen muss dies bei Aufruf Definiert werden. (also wie in der Main.)

    So und nun geht auch alles 😃

    Danke für die Hilfe Leute, auch wenn Ihr mir das schon etwas schwer gemacht habt. Aber ich glaube das werde ich nicht so schnell vergessen 😃



  • PS: ich finde das Buch C von A bis Z garnicht so schlecht, leider habe ich nicht die Zeit es von Anfang bis Ende zu lesen.

    Aber so ist es gut gut und übersichtlich geschrieben. An stelle zu maulen wie schlecht der Gute Mann ist, solltet Ihr lieber auch dazu schreiben welches Buch Ihr empfehlen würdet.

    Dann kann ich als 0815 ANSI-C Programmierer das auch mal kaufen und werde vielleicht dann auch ein 4711 ANSI-C Programmierer.

    Gruß an euch alle und noch einmal vielen lieben Dank.



  • Aus dem Header muss das raus:

    struct angestellt *next;
    struct angestellt *anfang;
    

    denn auch damit legst du die Variablen an. Das hat mit dem zuweisen von Werten nichts zu tun.

    Dafür muss in anhaengen.c folgendes rein:

    extern struct angestellt *next;
    extern struct angestellt *anfang;
    

    Damit sagst du dem Compiler, dass die Variablen schon woanders angelegt wurden.
    (bei dir in main.c).



  • Es hat glaub ich noch keiner darauf Aufmerksam gemacht (und vielleicht weißt du es sogar und hast es nur wegen dem simplen Beispiel ignoriert), aber das programm ist anfällig für einen Buffer Overflow.

    struct angestellt{
       char name[20];
       struct angestellt *next;
    }
    ...
    void anhaengen(char *n){
    ...
    /* keine Längenprüfung von n */
    strcpy(anfang->name,n);
    ...
    }
    

    Wenn n hier länger als 20 Zeichen ist (NUL inklusive) wird dein Programm im besten Fall abstürzen, im schlimmsten Fall gekapert werden können



  • LHBL2003 schrieb:

    PS: ich finde das Buch C von A bis Z garnicht so schlecht, leider habe ich nicht die Zeit es von Anfang bis Ende zu lesen.

    Aber so ist es gut gut und übersichtlich geschrieben. An stelle zu maulen wie schlecht der Gute Mann ist, solltet Ihr lieber auch dazu schreiben welches Buch Ihr empfehlen würdet.

    Also subjektiv didaktisch gut aufbereitete Fachbücher, die inhaltlich überwiegend nachweisbar falsche Aussagen präsentieren, sind gute Bücher?
    Nein, das stimmt nicht.
    Der Autor JW verbreitet überwiegend Pfusch, und wenn DU dir mal die Mühe gemacht haben würdest, hier im Forum zu suchen, wäre dir u. vielen anderen Beiträgen auch der aktuelle Parallelbeitrag "Hoffungslos" aufgefallen, in dem der Autor entsprechend abgehandelt wird.
    Wie schwer es ist, aus euch Anfängerköpfen diesen JW Pfusch herauszubekommen, merkt man an vielen Beiträgen hier im Forum.
    Ich habe dort z.B. auch Alternativliteratur benannt, also: eine Suche in diesem Forum lohnt sich, und nehme nicht immer gleich die Top-Googletreffer als gottgegeben hin.



  • Hallo linux_c89 danke für den Hinweiß, aber ich muss den Code A: erst einmal noch etwas aufräumen und B: dieses mal hab ich eh eine Längenbegrenzung von 4 Zeichen, daher ist es sogar noch zu groß.

    Aber ich werde mich mal die Tage hinsetzten und dass ohne Längenbegrenung bauen. 🙂

    Hallo Wutz, naja ich hab in dem Fall sogar das Buch zu hause. Ich bin irgendwie darmals (Nicht auf Google Seite 1) drüber gestolpert, weil ich etwas gesucht habe und es da "gut" beschrieben war.
    Aber danke für den Tipp ich werde mich dann doch mal schlau machen und nicht irgendwann das Buch von JW durchlesen.

    MFG & Vielen Dank erst einmal.



  • DirkB schrieb:

    Aus dem Header muss das raus:

    struct angestellt *next;
    struct angestellt *anfang;
    

    denn auch damit legst du die Variablen an. Das hat mit dem zuweisen von Werten nichts zu tun.

    Dafür muss in anhaengen.c folgendes rein:

    extern struct angestellt *next;
    extern struct angestellt *anfang;
    

    Damit sagst du dem Compiler, dass die Variablen schon woanders angelegt wurden.
    (bei dir in main.c).

    Hallo DirkB,

    kannst du mir noch den Grund sagen warum ich die beiden Variablen außerhalb des Headers halten muss? Gibt es spezielle Gründe dafür?

    Ich kann sonnst nicht gleichzeitig mehrere Strukturen verwenden oder?

    Danke für deine Antwort



  • Durch

    struct angestellt *next;
    

    wird Speicherplatz für einen Zeiger reserviert, den du über den Namen next ansprechen kannst.

    #include <name.h> bindet den Inhalt der Datei name.h mit in die C-Datei ein. Für den Compiler ist das so, als ob der Inhalt aus name.h in der C-Datei steht.

    Du hast jetzt zwei C-Dateien. Beide machen das #include. Dann haben beide auch einen Zeiger namens next. Das sind aber unterschiedliche Zeiger.


Anmelden zum Antworten