Typdef Typ in Typdef Zugriff aber wie?



  • Hallo Leute,

    ich bin neu hier und auch was die C Programmierung betrifft. Ich bin gerade dabei eine Datei zu sortieren, eingelesen ist sie schon. Ich soll nach ZugId anStunden und anMinuten sortieren. Jetzt scheitert es aber schon daran das ich nicht weiß, wie ich auf die typdef Schedule variablen zugreifen kann. Hier der Code:

    typedef struct{
    	int ZugId; // Darauf möchte ich zugreifen
    	int bahnhofId;
    	int anStunde; // Darauf möchte ich zugreifen
    	int anMinute; // Darauf möchte ich zugreifen
    	int abStunde;
    	int abMinute;
    	int anzahlAussteiger;
    	int anzahlEinsteiger;
    } Schedule;
    
    typedef struct{
    	Schedule **schedules; // Über das hier
    	int count;
    	int allocated;
    } ScheduleList;
    
    void sortScheduleList (ScheduleList *sl){
    	qsort (sl->schedules, sl->count, sizeof (Schedule *), 0);
    	printf("ID: %d \n", sl->schedules->ZugId); // Lässt er mich nicht
    }
    

    Ich hoffe man kann mein Problem verstehen.

    LG



  • Das schedules ist ein Doppelzeiger.
    Zeiger kann man mit * oder [] dereferenzieren.

    Deine Datei wird als Array abgelegt sein, daher ist [] angenehmer.

    sl->schedules[0]->ZugId
    

  • Mod

    Mittels des Punktoperators kann man auf die Felder eines Structs zugreifen. Dafür braucht man natürlich ein Objekt des Struct-Typs. Du hast dich in deinen ganzen Zeigern selber verheddert: ScheduleList enthält einen Zeiger auf einen Zeiger auf ein Schedule. Und dann hast du einen Zeiger auf eine ScheduleList. Sind das nicht ein bisschen viele Indirektionen? Was willst du damit erreichen? Du weißt schon, dass in C nicht alles ein Zeiger sein muss (und sollte)? Eine Ebene von Indirektion könnte ich hier nachvollziehen, aber nicht drei.



  • Vielen Dank funktioniert einwandfrei 🙂



  • Sorry den zweiten Kommentar hab ich nicht gesehen. Ich versuche ZugId anStunde anMinute zu sortieren. Die eigentliche Aufgabe:

    programm bahnhof.dat zug.dat fahrplan.dat zugnummer

    Finde alle Züge, die den Zug zugnummer überholen und gib deren Zugnummer aus.

    Implementierungstipp:

    A ist Zug mit zugnummer
    Für alle Züge B
    Finde Bahnhof C, an dem A abfährt und an dem B später abfährt als A
    (und zwar den darunter, an dem A am frühesten abfährt)
    Wenn es einen solchen gibt:
    Für alle Bahnhöfe D, an denen A nach C hält und an denen auch B hält
    Wenn B an D früher hält als A, dann ist B ein Überholer von A

    Eingelesen sind die Dateien alle. Bin mit den Pointern und der Syntax noch nicht ganz vertraut und den Algorithmus weiß ich auch noch nicht um die Aufgabe umzusetzen.

    LG danke für eure Hilfe!



  • SmokeTM schrieb:

    Eingelesen sind die Dateien alle.

    Ich hoffe nicht per Einzel-realloc.

    SmokeTM schrieb:

    Bin mit den Pointern und der Syntax noch nicht ganz vertraut

    Das ist normal für Anfänger, leider gilt das auch für viele sich selbst als Profi bezeichnende.

    SmokeTM schrieb:

    und den Algorithmus weiß ich auch noch nicht um die Aufgabe umzusetzen.

    Das sieht man. Du hast an qsort gar keine compare-Callback-Funktion übergeben.
    Informiere dich darüber, wie qsort funktioniert.

    Prinzipiell ist dein Datendesign schon OK, ein Objekt vom Typ Liste, was auf die Elemente verweist und die Anzahl kennt:

    typedef struct {
    	int ZugId; // Darauf möchte ich zugreifen
    	int bahnhofId;
    	int anStunde; // Darauf möchte ich zugreifen
    	int anMinute; // Darauf möchte ich zugreifen
    	int abStunde;
    	int abMinute;
    	int anzahlAussteiger;
    	int anzahlEinsteiger;
    } Schedule;
    
    typedef struct {
    	Schedule *schedules; // Über das hier
    	int count;
    	int allocated;
    } List;
    
    int cmp(const void*a, const void*b)
    {  /* aufsteigend sortieren nach 2 rangungleichen Kriterien */
    	const Schedule *x = a, *y = b;
    	if (x->anStunde != y->anStunde)
    		return x->anStunde <= y->anStunde ? -1 : 1;
    	return x->anMinute <= y->anMinute ? -1 : 1;
    }
    
    int main()
    {
    	List list = { (Schedule[]) { {3,3,3,3,3,3,3,3},{1,1,1,1,1,1,1,1},{2,2,2,2,2,2,2,2},{0},{9,9,9,9,9,9,9,9} },5 };
    	qsort(list.schedules, list.count, sizeof*list.schedules, cmp);
    	for (int i = 0; i < list.count; ++i)
    		printf("%d\n", list.schedules[i].ZugId);
    	return 0;
    }
    

    http://ideone.com/FLtUgJ



  • Hallo Wutz danke für deinen Code ich hab den Code in mein Programm übernommen. Irgendwie glaub ich aber das die Sortierung nicht stimmt es ist jetzt alles vermischt.

    Ich dachte die anStunde und anMinute sollte nach ZugId sortiert sein, also in etwa so.

    ZugId | anStunde | anMinute
    250 | 1 | 0
    250 | 2 | 10
    250 | 3 | 25
    250 | 5 | 50
    300 | 1 | 0
    300 | 4 | 10
    300 | 5 | 35

    Momentan wird ZugId jedoch vermischt. Daher denke ich passt es dann mit der anStunde und anMinute nicht mehr überein?

    Umgeschriebener Code schedule.c:

    void sortScheduleList (ScheduleList *sl){
     	qsort(sl->schedules, sl->count, sizeof*sl->schedules, cmp); 
        for (int i = 0; i < sl->count; ++i) 
    	printf("ID: %d anStunde: %d anMinute %d \n", sl->schedules[i]->ZugId, sl->schedules[i]->anStunde, sl->schedules[i]->anMinute); 
    }
    
    int cmp(const void*a, const void*b) 
    {  /* aufsteigend sortieren nach 2 rangungleichen Kriterien */ 
        const Schedule *x = a, *y = b; 
        if (x->anStunde != y->anStunde) 
            return x->anStunde <= y->anStunde ? -1 : 1; 
        return x->anMinute <= y->anMinute ? -1 : 1; 
    }
    

    schedule.h

    typedef struct{
    	int ZugId;
    	int bahnhofId;
    	int anStunde;
    	int anMinute;
    	int abStunde;
    	int abMinute;
    	int anzahlAussteiger;
    	int anzahlEinsteiger;
    } Schedule;
    
    typedef struct{
    	Schedule **schedules;
    	int count;
    	int allocated;
    } ScheduleList;
    
    ScheduleList *newScheduleList ();
    Schedule *newSchedule (ScheduleList *sl);
    void readScheduleList (ScheduleList *sl, char *fileName);
    void sortScheduleList (ScheduleList *sl);
    int cmp(const void*a, const void*b);
    

    LG Danke für deine Hilfe Wutz


  • Mod

    Mein vorheriger Beitrag gilt nach wie vor.

    SeppJ schrieb:

    ScheduleList enthält einen Zeiger auf einen Zeiger auf ein Schedule. Und dann hast du einen Zeiger auf eine ScheduleList. Sind das nicht ein bisschen viele Indirektionen?

    Beachte, wie Wutz es besser gemacht hat.



  • Ok wenn ich den einen Zeiger von schedules wegnehme funktioniert das einlesen nicht daher poste ich jetzt den ganzen code.

    schedule.h

    typedef struct{
    	int ZugId;
    	int bahnhofId;
    	int anStunde;
    	int anMinute;
    	int abStunde;
    	int abMinute;
    	int anzahlAussteiger;
    	int anzahlEinsteiger;
    } Schedule;
    
    typedef struct{
    	Schedule **schedules;
    	int count;
    	int allocated;
    } ScheduleList;
    
    ScheduleList *newScheduleList ();
    Schedule *newSchedule (ScheduleList *sl);
    void readScheduleList (ScheduleList *sl, char *fileName);
    void sortScheduleList (ScheduleList *sl);
    int cmp(const void*a, const void*b);
    

    schedule.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "schedule.h"
    
    ScheduleList *newScheduleList () {
    	ScheduleList *sl = (ScheduleList *) malloc (sizeof (ScheduleList));
    	sl->count = 0;
    	sl->allocated = 10;
    	sl->schedules = (Schedule **) calloc (sl->allocated, sizeof (Schedule *));
    	return sl;
    }
    
    Schedule *newSchedule (ScheduleList *sl) {
    	if (sl->count >= sl->allocated){
    		sl->allocated *= 2;
    		sl->schedules = (Schedule **) realloc (sl->schedules, sl->allocated * sizeof (Schedule *));
    	}
    	Schedule *aa = (Schedule *) malloc (sizeof (Schedule));
    	sl->schedules[sl->count++] = aa;
    	return aa;
    }
    
    void readScheduleList (ScheduleList *sl, char *fileName) {
    
    	FILE *file = fopen (fileName, "r");
    	if (file == NULL)  { perror (fileName);  exit (1); }
    	int r, id;
    	do{
    		r = fscanf (file, "%d", &id);
    		//printf("r: %d", r);
    		if (r != EOF){
    			//printf("r: %d", r);
    			Schedule *aa = newSchedule (sl);
    			aa->ZugId = id;
    			r = fscanf (file, "%d %d %d %d %d %d %d", &aa->bahnhofId, &aa->anStunde, &aa->anMinute, &aa->abStunde, &aa->abMinute, &aa->anzahlAussteiger, &aa->anzahlEinsteiger);
    			printf("ID: %d bahnhofId: %d anStunde: %d anMinute: %d abStunde: %d abMinute: %d anzahlAussteiger: %d anzahlEinsteiger: %d \n", id, aa->bahnhofId, aa->anStunde, aa->anMinute, aa->abStunde, aa->abMinute, aa->anzahlAussteiger, aa->anzahlEinsteiger);
    		}
    	}
    	while (r != EOF);
    	fclose (file);
    }
    
    void sortScheduleList (ScheduleList *sl){
     	qsort(sl->schedules, sl->count, sizeof*sl->schedules, cmp); 
        for (int i = 0; i < sl->count; ++i) 
    	printf("ID: %d anStunde: %d anMinute %d \n", sl->schedules[i]->ZugId, sl->schedules[i]->anStunde, sl->schedules[i]->anMinute); 
    }
    
    int cmp(const void*a, const void*b) 
    {  /* aufsteigend sortieren nach 2 rangungleichen Kriterien */ 
        const Schedule *x = a, *y = b; 
        if (x->anStunde != y->anStunde) 
            return x->anStunde <= y->anStunde ? -1 : 1; 
        return x->anMinute <= y->anMinute ? -1 : 1; 
    }
    

    programm.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "train.h"
    #include "trainstation.h"
    #include "schedule.h"
    
    int main(int argc, char *argv[]){
    
    	TrainList *tl = newTrainList ();
    	TrainStationList *tsl = newTrainStationList ();
    	ScheduleList *sl = newScheduleList ();
    
    	readScheduleList (sl, argv[3]);
    	readTrainList (tl, argv[2]);
    	readTrainStationList (tsl, argv[1]);
    
    	sortScheduleList(sl);
    
    	return 0;
    }
    


  • Obwohl Zeiger in C die Grundlage bilden, heißt das nicht, dass man überall wo man nicht mehr weiter weiß auch welche verwenden soll.
    Natürlich musst du deinen bisherigen Code anpassen, wenn du das Datendesign veränderst.

    Die Beispielsortierung habe ich dir nur gezeigt, weil ich es für sinnvoll hielt, für deinen Anwendungsfall die Ankunftszeiten zu sortieren. Und da macht eine gleichzeitige Sortierung nach ZugId keinen Sinn.

    Den fachlichen Algorithmus musst du dir schon selbst überlegen, wir können dir bei technischen Fragen, Daten- und Programmdesignfragen helfen.

    Wie ich dir gezeigt habe, ich es völlig ausreichend, mit der Liste selbst und nicht einem Zeiger darauf zu operieren.
    Ebenso hat newSchedule eine Zeigerebene zuviel, du operierst mit einer Folge von Zeigern auf struct wo eine Folge von struct ausreicht.
    Dein Einlesen ist auch falsch. (um dem häufigen Anfängerargument: "läuft doch" vorzubeugen: nein, ein Code ist nicht korrekt, wenn er mit Spieldaten richtige Ergebnisse liefert).

    Ich empfehle dir dringend:
    Priorisiere die Implementierung des fachlichen Problems (Finde alle Züge, die den Zug zugnummer überholen und gib deren Zugnummer aus.).
    Dazu kannst du den von mir gezeigten Beispielcode verwenden, indem du die dortigen beispielhaften 5 Züge mit sinnvollen Testwerten vorbelegst: wenn das dann läuft, kannst du dein Datenlesen immer noch verbessern.



  • Danke für deine Antwort ich hab jetzt noch ein mal von vorne begonnen. Momentan sieht es so aus.

    programm.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "schedule.h"
    
    int main() 
    { 
        ScheduleList list = newScheduleList();
        ScheduleList list = { (Schedule[]) { {963,8980,21,39,21,41,28,7},{963,6996,21,50,21,51,7,35},{963,8335,23,4,0,0,35,0},{79090,7281,0,0,20,54,0,36},{79090,4286,1,1,20,56,0,9} },5 }; 
        qsort(list.schedules, list.count, sizeof*list.schedules, cmp);
        for (int i = 0; i < list.count; ++i) 
            printf("%d %d %d\n", list.schedules[i].ZugId, list.schedules[i].anStunde, list.schedules[i].anMinute); 
        return 0; 
    }
    

    schedule.h

    typedef struct { 
        int ZugId; 
        int bahnhofId; 
        int anStunde; 
        int anMinute;
        int abStunde; 
        int abMinute; 
        int anzahlAussteiger; 
        int anzahlEinsteiger; 
    } Schedule; 
    
    typedef struct { 
        Schedule *schedules;
        int count; 
        int allocated; 
    } ScheduleList;
    
    int cmp(const void*a, const void*b);
    

    schedule.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "schedule.h"
    
    int cmp(const void*a, const void*b) { 
        const Schedule *x = a, *y = b; 
        if (x->anStunde != y->anStunde) 
            return x->anStunde <= y->anStunde ? -1 : 1; 
        return x->anMinute <= y->anMinute ? -1 : 1; 
    }
    

    Funktioniert auch einwandfrei, jetzt ist nur die Frage was an meinem einlesen falsch war oder eben verbesserungswürdig?

    LG



  • Dein Algorithmus ist noch lange nicht fertig, aber das solltest du selbst wissen.

    Beim Einlesen machst du den klassischen Anfängerfehler:
    du benutzt fscanf und EOF/feof:
    fscanf/scanf/sscanf liefern die Anzahl der erfolgreich gelesenen Werte zurück; dies ignorierst du aber indem du lediglich auf !=EOF (d.h. !=-1) testest.

    Benutze Positivlogik bei fscanf
    also

    while( fscanf(...)==8 )
    {
    }
    

    das funktioniert immer und hat die EOF-Prüfung inklusive.



  • wieso kann ich das nicht so schreiben?

    ScheduleList newScheduleList () {
    	ScheduleList sl = (ScheduleList ) malloc (sizeof (ScheduleList));
    	sl.count = 0;
    	sl.allocated = 10;
    	sl.schedules = (Schedule *) calloc (sl.allocated, sizeof (Schedule *));
    	return sl;
    }
    

    error: conversion to non-scalar type requested

    Ich komm einfach nicht weiter bin am verzweifeln. Das mit der PositivLogik hab ich erst recht nicht verstanden? Das heißt einen counter mitlaufen lassen und dagegen prüfen?

    LG



  • ScheduleList newScheduleList ()
    {
    	ScheduleList sl = (ScheduleList ) malloc (sizeof (ScheduleList));
    }
    

    Lern C, anstatt hier immer nur doof zu fragen, warum X nicht funktioniert.



  • malloc gibt einen Zeiger zurück. Den mag man gerade noch so in einen int-Typ Wandel, aber in eine struct geht halt nicht.

    Es ist immer gut, auch die Zeile, auf die sich der Fehler bezieht, genau zu kennzeichnen.
    Der Compiler macht das mit Zeilen- (und Spalten-)nummer.

    Durch die Definition von ScheduleList sl hast du schon den Speicher, den du brauchst (die komplette struct)
    Oder du machst ScheduleList *sl = malloc .. , aber dann sind die Zugriffe auf die Member mit . falsch.

    SmokeTM schrieb:

    Das mit der PositivLogik hab ich erst recht nicht verstanden? Das heißt einen counter mitlaufen lassen und dagegen prüfen?

    Nein.
    scanf zählt für dich.
    Schau dir mal genau an, was der Rückgabewert von scanf bedeutet:[url] http://www.cplusplus.com/reference/cstdio/scanf/[/url]

    Wenn du keine 8 Werte bekommst, ist was mit der Eingabe falsch.
    Egal ob EOF oder fehlende Werte. Es bringt nichts mehr weiterzulesen.



  • Hab nun das file einlesen geändert.

    ScheduleList newScheduleList () {
    	ScheduleList sl;
    	sl.count = 0;
    	sl.allocated = 10;
    	sl.schedules = (Schedule *) calloc (sl.allocated, sizeof (Schedule *));
    	return sl;
    }
    
    Schedule newSchedule (ScheduleList sl) {
    	if (sl.count >= sl.allocated){
    		sl.allocated *= 2;
    		sl.schedules = (Schedule *) realloc (sl.schedules, sl.allocated * sizeof (Schedule *));
    	}
    	Schedule aa;
    	sl.schedules[sl.count++] = aa;
    	return aa;
    }
    
    void readScheduleList (ScheduleList sl, char *fileName) {
    
    	FILE *file = fopen (fileName, "r");
    	if (file == NULL)  { perror (fileName);  exit (1); }
    	int id;
    	Schedule aa = newSchedule (sl);
    	while(fscanf(file, "%d %d %d %d %d %d %d %d", &aa.ZugId, &aa.bahnhofId, &aa.anStunde, &aa.anMinute, &aa.abStunde, &aa.abMinute, &aa.anzahlAussteiger, &aa.anzahlEinsteiger) == 8) { 
    		printf("ID: %d bahnhofId: %d anStunde: %d anMinute: %d abStunde: %d abMinute: %d anzahlAussteiger: %d anzahlEinsteiger: %d \n", aa.ZugId, aa.bahnhofId, aa.anStunde, aa.anMinute, aa.abStunde, aa.abMinute, aa.anzahlAussteiger, aa.anzahlEinsteiger);
    	}
    	fclose (file);
    }
    

    Jetzt stellt sich mir aber die Frage warum das so funktioniert den ich erstell hier nur eine Instanz von Schedule. Die Ausgabe im Terminal scheint aber richtig zu sein.

    War das einlesen von euch so gemeint, wie ich es jetzt umgesetzt habe?

    LG



  • SmokeTM schrieb:

    Jetzt stellt sich mir aber die Frage warum das so funktioniert

    Tut es nicht.

    SmokeTM schrieb:

    Die Ausgabe im Terminal scheint aber richtig zu sein.

    Überleg mal, wann du welche Daten ausgibst.
    (Woher weißt du, wieviel Zeilen gelesen wurden?)

    Du bringst Zeiger und Objekte gehörig durcheinander.


Anmelden zum Antworten