Erstes großes Programm, so okay?



  • Hallo Leute, ich hab mir vor kurzem c beigebracht und hab jetzt das erste mal ein relativ großes programm mit Stukturen geschrieben. Die Angabe des Programm hab ich von einem Freund, der das in der Schule machen musste.

    Aufgabe dieses Programm:

    ----Schülerverwaltung----

    Erstelle ein Programm zur Verwaltung von Daten in welchem die Standardfunktionen zur
    Datenverwaltung realisiert sind:

    1. Eingabe
    2. Ausgabe aller Daten
    3. Ändern (Datensatz suchen und überschreiben)
    4. Löschen
    5. Ausgabe eines einzelnen Datensatzes (Suche nach Name)

    -> Die Daten sind in Form von Strukturen zu verwalten.
    -> Eingegebene Daten sind, sofern möglich auf Richtigkeit zu prüfen
    -> Aufruf der einzelnen Funktionen durch ein zentrales Menü.

    Zu erfassen sind die folgenden Daten:
    Name, Vorname, Geburtsdatum (ist auf Richtigkeit zu prüfen in einer eigenen Funktion),
    Klasse

    Bezeichnung und Noten von maximal 20 Unterrichtsgegenständen (in einer Liste)

    Die Anzahl der Gegenstände und Schueler hab ich jetzt nicht genau wie in der Angabe.
    Ich habe das Programm etwas ausführlicher gemacht: Bei mir kann man noch Noten und Gegenstände aendern, hinzufügen und noch ein paar andere kleinigkeiten.

    Das Programm habe ich ausführlich getestet und es scheint alles zu funktionieren.

    Nun zu meiner Bitte: Weil das ja mein erstes großes Programm ist, bin ich mir nicht sicher, ob das so stimmt wie ich das ganze schreibe und ob es C- Profis ganz anders machen würden, oder nur kleine veränderungen!
    Ich war mir nicht ganz sicher bei den verschachtelten cases und ich habe so wenig wie möglich breaks eingebaut (hab irgendwo gelesen, man soll statt breaks eher schleifenbedingungen nehmen). Oder wie würde ihr die Kommentare setzen, oder kann man was mit meinen Kommentaren anfangen, wenn jemand anders den Quelltext lesen soll? Mehr oder weniger?. Bei den globalen Variablen bin ich mir auch nicht ganz sicher, ob das so passt, die soll man ja so wenig wie mögich verwenden...

    Bitte um hilfreiche tipps, und ich vertrag auch Kritik ;).

    Wäre schonmal froh, wenn sich jemand die Mühe macht, den Quelltext zu lesen 🙂 👍

    Dann weiß ich in Zukunft besser wie ich C- Programme schreiben soll

    Hier der Quelltext:

    /**********************************************************/
    /* Beschreibung: Dieses Programm verwaltet Datein,        */
    /* in welchem die Standardfunktionen zur Datenverwaltung  */
    /* realisiert sind										  */
    /**********************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    /**********************************************************/
    /*						Strukturendefinition		      */
    /**********************************************************/
    struct schueler {	// Struktur fuer 200 Schueler
        char vorname[20];
    	char name[20];
    	char gebdatum [5];
    	char klasse[5];
    	struct faecher {	// Struktur fuer je 20 Faecher/Schueler
               char fach[20];
               int note;
        } faecher[20];
    } schueler[200];
    
    /**********************************************************/
    /*						Funktionskoepfe					  */
    /**********************************************************/
    void eingabe(void);	// Schueler eingeben
    void ausgabe(void);	// Schueler ausgeben
    void suche(void);	// Schueler suchen
    void aendernLoeschen(void);	// Wählen zwischen Schueler aendern oder loeschen
    void aendern(void);	// Schueler aendern	
    void loeschen(void);	// Schueler loeschen
    void speichern(void);	// Schueler auf Festplatte speichern
    
    /**********************************************************/
    /*						Globale Variablen				  */
    /**********************************************************/
    int i = 1;	// Eingabe der Schueler
    int l = 1;	// Alle andern Funktionen mit Schuelern
    int n = 1;	// Zaehlen aktueller Faecher
    
    /**********************************************************/
    /*														  */
    /*						Hauptprogramm					  */
    /*														  */
    /**********************************************************/
    int main() {
    	/* Hier werden alle Felder mit nichts befuellt */
    	for(l=1;l<=20;l++) {
    		strcpy(schueler[l].vorname,"");
    		strcpy(schueler[l].name,"");
    		for(n=1;n<=20;n++)
        		strcpy(schueler[l].faecher[n].fach,"");
    	}
    
    	while(1) {			// Hauptmenue bleibt immer (außer wenn exit(EXIT_FAILURE))
    		system("cls");	// Clear Screen
    
    		int menue = 0;	// Dient zum Aufrufen eines Untermenüs des Zentralmenüs
    
    		/********************************/
    		/******** Zentrales Menü ********/
    		/********************************/
    		printf("----SCHUELERVERWALTUNG----\n\n");
    		printf("1: Eingabe\n");
    		printf("2: Ausgabe aller Schueler\n");
    		printf("3: Suchen eines Schuelers\n");
    	 	printf("4: Daten speichern\n");
    		printf("5: Programm beenden\n");
    		scanf("%d", &menue);
    
    		switch(menue) {	// Aufrufen der einzelnen Funktionen
    			case(1): eingabe(); break;		
    			case(2): ausgabe(); break;
    			case(3): suche(); break;
    			case(4): speichern(); break;
    			case(5): return 0;	// Programm beendem
    			default: printf("Falsche Eingabe");			
    		}
    	}
    }
    
    /**********************************************************/
    /* Funktionsname: eingabe								  */
    /*														  */
    /* gibt die Schueler ein								  */
    /*														  */
    /* Parameter: keine										  */
    /**********************************************************/
    void eingabe() {
    	int x = 1;		// fuer die Anzahl der Faecher, die Sie eingeben wollen
    	int j = 1;		// auswählen, ob noch mehr Schueler einzugeben sind
    
    	while(j == 1) {		// Solange j == 1 werden Schueler eingegeben
    		/* Leeren String suchen */
    		while((strcmp(schueler[i].vorname,"")!=0)&&(strcmp(schueler[i].name,"")!=0)&&(l<=200)) l++;	
    
    		system("cls");						// Clear Screen
    
    		/******************************************/
    		/******** Schueler werden eingeben ********/
    		/******************************************/
    		printf("%d. Schueler:", i);			
    		printf("\nVorname: ");
    		scanf("%s", schueler[i].vorname);
    		printf("\nName: ");
    		scanf("%s", schueler[i].name);
    		printf("\nGeburtsdatum [d.m.j]: ");
    		scanf("%s", schueler[i].gebdatum);
    		printf("\nWollen Sie ein Fach+Note eingeben? (1/0): ");
    		scanf("%d", &x);
    		n = 1;				// n wieder auf 1 setzen, falls veraendert wurde
    		while(x == 1) {		// Solange x==1 werden Faecher eingegeben
    	        printf("\nFach: ");
                scanf("%s", schueler[i].faecher[n].fach);
                printf("\nNote: ");
                scanf("%d", &schueler[i].faecher[n].note);
                printf("Noch ein Fach? (1/0): ");
                scanf("%d", &x);
                n++;
            }
    		printf("\nNoch einen Schueler eingeben ? (1/0)");	// 0 --> zurueck ins Hauptmenue 1 --> Naechster Schueler
    		scanf("%d", &j);	
    		i++;				// i++, fuer naechsten Schueler
    	}
    
    }	// Ende der Funktion
    
    /**********************************************************/
    /* Funktionsname: ausgabe								  */
    /*														  */
    /* gibt die eingegebenen Schueler aus					  */
    /*														  */
    /* Parameter: keine										  */
    /**********************************************************/
    void ausgabe() {
    	system("cls");	// Clear Screen
    
    	l = 1;		// Zählvariable zum ausgeben der Schueler vom Anfang bis zum Ende
    	int k = 1;	// Fuer 1. Schueler, 2. Schueler usw...
    
    	while(l < 200) {	// Bis zum letzen Schueler
    		/* Dieses if ueberprueft, ob in dem String etwas steht, oder ob er leer ist */
    		if((strcmp(schueler[l].vorname,"")!=0)&&(strcmp(schueler[l].name,"")!=0)&&(l<=200)) {
    			/* Ausgeben der Strings, in denen ein Schueler existiert */
    			printf("%d. Schueler:", k);
    			printf("\n\tVorname: %s", schueler[l].vorname);
    			printf("\n\tName: %s", schueler[l].name);
    			printf("\n\tGeburtsdatum: %s\n\n", schueler[l].gebdatum);
    			n=1;	// n wieder auf 1 setzen, falls veraendert wurde
    			/* Dieses while ueberprueft, ob in dem String etwas steht, oder ob er leer ist */
    			while(n <= 19) {
    				if(strcmp(schueler[l].faecher[n].fach,"")!=0) {
    					printf("\t%s: ", schueler[l].faecher[n].fach);
    					printf("\t%d\n", schueler[l].faecher[n].note);
    				}
    				n++;                     
    			}
                printf("\n");
    			k++;	// z.B. 1. Schueler auf 2. Schueler erhoehen
    		}	
    		l++;		// Naechster Schueler
    	}
    	system("PAUSE");	// Konsole wird nicht geschlossen
    }
    
    /**********************************************************/
    /* Funktionsname: suche()								  */
    /*														  */
    /* Sucht einen Schueler und wenn gefunden, dann aufrufen  */
    /* von aendernLoeschen Funktion							  */
    /*														  */
    /* Parameter: keine										  */
    /**********************************************************/
    void suche() {
    	system("cls");			// Clear Screen
    
    	char vornameSuche[20];	// String fuer den Vornamen den sie suchen
    	char nameSuche[20];		// String fuer den Namen den sie suchen
    
    	printf("Vorname: ");
    	scanf("%s", vornameSuche);
    	printf("\nName: ");
    	scanf("%s", nameSuche);
    
    	l = 1;			// l wieder auf 1 setzen, falls veraendert wurde
    	while(l < i) {	// Jeden Schueler vergleichen
    		int ret = strcmp(schueler[l].vorname, vornameSuche);	// Vorname vergleichen; ret ist der Rückgabewert der Funtion strcmp (vergleicht 2 Strings)
    
    		if(ret == 0) {		// Wenn Rückgabewert 0 ist, dann ist der Vorname identisch
    			ret = strcmp(schueler[l].name, nameSuche);	// Name vergleichen
    			if(ret == 0) {
    				aendernLoeschen();	// Wenn Vorname und Name übereinstimmen diese Funktion aufrufen
    				break; 	// Aus Schleife hüpfen
    			}
    		}
    		l++;	// Naechsten Schueler ueberpruefen
    	}
    
    	if(l == i) {	// Wenn jeder Schueler kontrolliert wurde und nicht mit Gesuchtem übereinstimmt...
    		system("cls");	// Clear Screen
    		printf("Schueler nicht gefunden!\n");
    		system("PAUSE");	// Konsole wird nicht geschlossen
    	}
    }
    
    /**********************************************************/
    /* Funktionsname: aendernLoeschen()						  */
    /*														  */
    /* Sucht einen Schueler und man wird gefragt, ob man ihn  */
    /* loeschen, oder aendern will							  */
    /*														  */
    /* Parameter: keine										  */
    /**********************************************************/
    void aendernLoeschen() {
    	int aendernloeschenMenue = 0;	// Auswahlvariable fuer das Menue
    	int error = 0;					// Solange Falsche Eingabe, erneuter Versuch
    	system("cls");					// Clear Screen
    
    	/* Gesuchter Schueler wird nochmals ausgegeben */
    	printf("\n\tVorname: %s", schueler[l].vorname);
    	printf("\n\tName: %s", schueler[l].name);
    	printf("\n\tGeburtsdatum: %s\n\n", schueler[l].gebdatum);
    	n=1;			// n wieder auf 1 setzen, falls veraendert wurde
    	while(n <= 19) {
    		if(strcmp(schueler[l].faecher[n].fach,"")!=0) {
    			printf("\t%s: ", schueler[l].faecher[n].fach);
    			printf("\t%d\n", schueler[l].faecher[n].note);
    		}
    		n++;                     
    	}
    
    	/* Menue zum auswaehlen ob Schueler aendern oder loeschen */
    	while(error == 0) {		// Solange falsche Eingabe, Eingabe wiederholen
    		printf("1: Aendern, 2: Loeschen, 3: zurueck\n");
    		scanf("%d", &aendernloeschenMenue);	
    
    		system("cls");	// Clear Screen
    		switch(aendernloeschenMenue) {	// Aufrufen der einzelnen Funktionen
    		    case(1): /* AENDERN */
    					 aendern();
    					 error = 1;	 
    					 break;
    			case(2): /* LOESCHEN --> Nichts in String schreiben */
    					 strcpy(schueler[l].vorname,"");
    					 strcpy(schueler[l].name,"");
    					 strcpy(schueler[l].gebdatum,"");
    				 	 for(n=1;n<20;n++)
                            strcpy(schueler[l].faecher[n].fach,"");
    					 error = 1;
    					 break;
    			case(3): error = 1;	// Zurueck ins Hauptmenue
    					 break;
    			default: printf("Fehlerhafte Eingabe\n\n");
    					 error = 0;	// Wenn falsche Eingabe nochmal abfragen
    		}
    	}
    }
    
    /**********************************************************/
    /* Funktionsname: aendernLoeschen()						  */
    /*														  */
    /* Einzelnen Daten des Schuelers aendern				  */
    /*														  */
    /* Parameter: keine										  */
    /**********************************************************/
    void aendern()
    {
    	int aendernMenue = 0;	// Auswahlvariable; was man ändern will
    	int error = 0;			// Solange Falsche Eingabe, erneuter Versuch
    	int error_2 = 0;		// Solange Falsche Eingabe, erneuter Versuch
    	int error_3 = 0;		// Solange Falsche Eingabe, erneuter Versuch
    	char fach[20];			// String zum suchen des Faches
    	int note;				// Integer zum suchen der Note
    
    	system("cls");	// Clear Screen
    
    	while (error_3 == 0) {	// Solange falsche Eingabe, Eingabe wiederholen
    		system("cls");	// Clear Screen
    
    		/* Gesuchter Schueler wird nochmals ausgegeben */
    		printf("\n\tVorname: %s", schueler[l].vorname);
    		printf("\n\tName: %s", schueler[l].name);
    		printf("\n\tGeburtsdatum: %s\n\n", schueler[l].gebdatum);
    		n=1;
    		while(n <= 19) {
    			if(strcmp(schueler[l].faecher[n].fach,"")!=0) {
    				printf("\t%s: ", schueler[l].faecher[n].fach);
    				printf("\t%d\n", schueler[l].faecher[n].note);
    			}
    			n++;                     
    		}
    
    		printf("\nVornamen aendern: 1\n");
    		printf("Namen aendern: 2\n");
    		printf("Geburtsdatum aendern: 3\n");
    		printf("Noten aendern: 4\n");
    		printf("Zurueck: 5\n");
    		scanf("%d", &aendernMenue);
    
    		/* In diesem switch kann man alle bisher eingegebenen Daten aendern */
    		switch(aendernMenue) {	
    			case(1): /* Neuer Vorname */
    					 printf("\nNeuer Vorname: ");
    					 scanf("%s", schueler[l].vorname);
    					 break;
    			case(2): /* Neuer Name */
    					 printf("\nNeuer Name: ");
    					 scanf("%s", schueler[l].name);
    					 break;
    			case(3): /* Neues Geburtsdatum */
    					 printf("\nNeues Geburtsdatum: ");
    					 scanf("%s", schueler[l].gebdatum);
    					 break;
    			case(4): /* Noten aendern */
    					 printf("\nFach loeschen: 1");
    					 printf("\nNeues Fach: 2");
    					 printf("\nNote aendern: 3\n");
    					 scanf("%d", &aendernMenue);
    
    					 /* In diesem switch kann man alle faecher veraendern */
    					 switch(aendernMenue) {
    					    /* Fach loeschen */
    						case(1): error_2 = 0;
    								 while(error_2 == 0) {
    									 printf("\nFach eingeben: ");
    									 scanf("%s", fach);
    									 for(n=1;n<=20 && error_2 == 0;n++) {			// Jeden Schueler durchlaufen
    										 if(strcmp(fach, schueler[l].faecher[n].fach) == 0) {	// Wenn gesuchtes Fach mit existierendem Fach uebereinstimmt...
    											 strcpy(schueler[l].faecher[n].fach,"");			// Nichts in das Existierende reinschreiben
    											 printf("Erfolgreich geloescht\n");
    											 system("PAUSE");
    											 error_2 = 1;	// for-Schleife beenden
    										 }
    									 }
     									 error_2 = 1;			// while-Schleife beenden
    									 if(n==21) {			// Wenn alle Faecher durgelaufen und Fach nicht gefunden
    										 printf("Fach nicht gefunden\n");
    										 system("PAUSE");
    										 error_2 = 1;
    									 }
    								 }
    								 break;	
    
    						/* Neues Fach */
    						case(2): printf("\nFach eingeben: ");
    								 scanf("%s", fach);
    								 printf("Note eingeben: ");
    								 scanf("%d", &note);
    								 n = 1;							// n wieder auf 1 setzen, falls veraendert wurde
    								 while(strcmp(schueler[l].faecher[n].fach,"")!=0) n++;	// Leeren String suchen
    								 strcpy(schueler[l].faecher[n].fach,fach);				// In leeren String das neue Fach kopieren
    								 schueler[l].faecher[n].note = note;					// Note kopieren
    								 printf("Erfolgreich erstellt\n");
    								 error_3 = 0;
    								 break;
    
    						/* Note aendern */
    						case(3): while(error_2 != 2) {
    									 printf("\nFach eingeben: ");
    									 scanf("%s", fach);
    									 error_2 = 0;
    									 for(n=1;n<=20 && error_2 != 1;n++) {		// Jeden Schueler durchlaufen
    										 if(strcmp(schueler[l].faecher[n].fach, fach) == 0) {	// Wenn gesuchtes Fach mit existierendem Fach uebereinstimmt...
    											 printf("Neue Note eingeben: ");
    											 scanf("%d", &note);
    									 		 schueler[l].faecher[n].note = note;				// Neue Note eintragen
    											 printf("Erfolgreich ueberschrieben\n");
    											 system("PAUSE");
    											 error_2 = 1;       // for-Schleife beenden
    										 }
    									 }
    									 if(n==21) {
    										 printf("Fach nicht gefunden\n");
    										 system("PAUSE");
    										 system("cls");
    									 }
    									 error_2 = 2;	// while-Schleife beenden
    								 }  
    								 break;		// break fuer case(3)
    					 }
    					 break;		// break fuer case(4)
    			case(5): error_3 = 1;	// zurueck ins Hauptmenue
    					 break;
    
    			default: system("cls");
    					 printf("\nFehlerhafte Eingabe\n\n");
    					 error = 1;		// Eingabe wiederholen
    					 break;
    		}
    
    	}	
    }
    

    mfg Sund0se



  • hiiiii!

    du verträgst kritik, das ist gut, wohl bekommts und los gehts:
    1)
    also, mein ansi c compiler mag den code nicht compilieren.
    grund, nicht ansi c konforme deklarationen wie z.b.

    int menue = 0;
    int k = 1;
    

    usw.
    möglicherweise wollen/sollen auch andere deinen code übersetzen und haben/mögen keinen C99/C++ compiler?
    2)
    funktion speichern fehlt. char klasse[5]; scheint ungenutzt.
    char gebdatum [5]; bisken wenig zeichen?
    3)

    struct schueler { // Struktur fuer 200 Schueler
    char vorname[20];
    char name[20];
    char gebdatum [5];
    char klasse[5];
    struct faecher { // Struktur fuer je 20 Faecher/Schueler
    char fach[20];
    int note;
    } faecher[20];
    } schueler[200];

    die struktur faecher lässt sich bestimmt auch in anderen programmteilen benutzen. auch wenn nicht, mach den code leserlicher, hol die struktur da raus und lege lieber satt dessen eine instanz an. verbau dir nicht deinen quellcode.

    /* Hier werden alle Felder mit nichts befuellt */
    int menue = 0;
    for(l=1;l<=20;l++) {
    strcpy(schueler[l].vorname,"");
    strcpy(schueler[l].name,"");
    for(n=1;n<=20;n++)
    strcpy(schueler[l].faecher[n].fach,"");
    }

    mach dir das leben einfacher, benutz die array-initialisierung mit 0. ( siehe code in main(). )

    printf("\nNoch einen Schueler eingeben ? (1/0)");

    benutz eindeutige eingabeaufforderungen wie 'j' / 'n', "ja"/"nein" etc.

    int i = 1; // Eingabe der Schueler
    int l = 1; // Alle andern Funktionen mit Schuelern
    int n = 1; // Zaehlen aktueller Faecher

    nixa gutta. globale variablen lieber static deklarieren, meist hat man es mit
    modulen zu tun.

    1. prüfung der puffergrenzen/arraygrenzen, siehe kommentare

    scanf("%s", schueler[i].name); <--- absturzgefahr, eingabe absichern.

    // Solange x==1 werden Faecher eingegeben
    ...
    n++; <--- absturzgefahr, arraygrenze absichern.
    scanf("%d", &menue); <-- ganz üble kiste das, absichern. (siehe weiter unten.)
    for(l=1;l<=20;l++) <--- 0 bis maximal bis 19! siehe auch andere arrays

    /* Leeren String suchen */
    while((strcmp(schueler[i].vorname,"")!=0)&&(strcmp(schueler[i].name,"")!=0)&&(l<=200)) l++;

    lieber anzahl speichern und ab index anzahl-1 weiter eingeben (aufwendiger).

    8.1)
    bei der eingabe eines buchstabens anstatt einer zahl geht das programm in eine
    endlosschleife über. grund: scanf nicht abgesichert ( siehe weiter oben. )
    8.2)
    will man sich die schüler anzeigen lassen, obwohl noch nix eingegeben wurde, werden unnötiger weise 200 mal strukturen abgefragt. abhilfe: zählvariabe, strukturenarray nacheinander befüllen, verkettete liste etc. damit würden auch die globalen variablen entfallen. die löschfunktion wäre abzuändern.
    danach erscheint die meldung: drücken sie eine beliebige taste...
    man denkt, das programm sei zu ende. es fehlt eine meldung nach dem motto: "keine einträge vorhanden" oder so, mit einer option zur rückkehr zum menü ...
    8.3)
    die option noch ein fach eingeben funzt nicht richtig.
    8.4)
    deine funktion aendern() ist mächtig gewaltig umständlich und fehlt als option im zentralen menü.

    sei nicht so knauserig mit den arraygrößen.
    denk an namen wie Pippilotta Viktualia Rallgordina Pfefferminza Efraimstochter Langstrumpf
    arrayindizes beginnen bei 0 und enden bei der anzahl ihrer elemente -1. alles in allem sind einige funktionen vieeeeeel zuuuuuu laaaaaaang. lieber in möglichst wiederverwendbare teilschritte aufteilen. (keine bange, das kommt mit der zeit.)

    Lass dich nicht allzu dolle entmutigen, ein 'bombensicheres' Programm zu schreiben ist nicht ganz
    so einfach und braucht einiges an Übung/Erfahrung/Aufwand.

    Näherungslösung/ Verbesserungsvorschläge für die Datenstruktur:

    #include <time.h>
    
    ////////////////////////////////////////////////////////////////////////////
    // Diese Daten besser in eine Konfigurationsdatei auslagern, um
    // das Programm flexibler zu machen.
    // Die Variablen in den Strukturen würden dann char* vorname, 
    // char* name, Fach* lauten, etc. Stichwort: malloc und co.
    // ANZAHL_FAECHER_MAX, NAMELEN_MAX, etc. würden gänzlich entfallen.
    // Das würde hier jetzt aber zu weit gehen, ich habe Feierabend. :D
    char* faecher[] = {"Mathematik", "Deutsch", "Sport", "Ansi C", "etc." }; 
    char* klassen[] = {"1A", "1B", "etc."};
    ////////////////////////////////////////////////////////////////////////////
    
    #define ANZAHL_FAECHER_MAX 20
    #define NAMELEN_MAX 64
    
    typedef struct {// Verkürzung des Quellcodes, Einführung eines neuen Datentypen.
        unsigned fach_id; // Speichert den Index (ID) eines Fachs.
        unsigned note; 
    }Fach;
    
    typedef struct {// dito.
        char vorname[NAMELEN_MAX]; 
        char name[NAMELEN_MAX]; 
        time_t geburtstag;  // Bei der Eingabe ins time_t Format umwandeln.
        unsigned klassen_id; // Speichert den Index (ID) einer Klasse.
    	Fach fach[ANZAHL_FAECHER_MAX];
    }Schueler;
    
    /*
    // Alternativ ( flexibler, aufwändiger. ):
    typedef struct 
    {
    	Schueler* schueler;
    	Schueler* next;
    	unsigned n; // Momentane Anzahl in der Liste.
    }SchuelerListe;
    */
    
    #define N 200
    
    int main()
    {
    	int i = 0, j = 0;
    	// Strukturelemente sauber mit 0 initialisieren.
    	// Setzt alle Elemente auf 0.
    	Schueler sc[N] = {0}; // Alternativ als Liste: SchuelerListe list;
    	// Überzeuge dich, das auch die eingebetteten Elemente 0 sind:
    	for ( i = 0; i < N; i++ )
    		for ( j = 0; j < ANZAHL_FAECHER_MAX; j++ )
    			printf("%d", sc[i].fach[j].fach_id ); // Jepp, 0.
    	// ... to be continued ...
    
    	return 0;
    }
    

    So, jetzt hab ich erstmal keinen Bock mehr. Tipps zur Absicherung der Eingaben etc, vllt. ein anderes mal.
    Gruß,
    a.



  • Vielleicht die Funktionen kleiner machen, dafür aber mehr davon.
    Damit meine ich, daß man Sachen wie

    void ausgabe() { 
        system("cls");    // Clear Screen 
    
        l = 1;        // Zählvariable zum ausgeben der Schueler vom Anfang bis zum Ende 
        int k = 1;    // Fuer 1. Schueler, 2. Schueler usw... 
    
        while(l < 200) {    // Bis zum letzen Schueler 
            /* Dieses if ueberprueft, ob in dem String etwas steht, oder ob er leer ist */ 
            if((strcmp(schueler[l].vorname,"")!=0)&&(strcmp(schueler[l].name,"")!=0)&&(l<=200)) { 
                /* Ausgeben der Strings, in denen ein Schueler existiert */ 
                printf("%d. Schueler:", k); 
                printf("\n\tVorname: %s", schueler[l].vorname); 
                printf("\n\tName: %s", schueler[l].name); 
                printf("\n\tGeburtsdatum: %s\n\n", schueler[l].gebdatum); 
                n=1;    // n wieder auf 1 setzen, falls veraendert wurde 
                /* Dieses while ueberprueft, ob in dem String etwas steht, oder ob er leer ist */ 
                while(n <= 19) { 
                    if(strcmp(schueler[l].faecher[n].fach,"")!=0) { 
                        printf("\t%s: ", schueler[l].faecher[n].fach); 
                        printf("\t%d\n", schueler[l].faecher[n].note); 
                    } 
                    n++;                     
                } 
                printf("\n"); 
                k++;    // z.B. 1. Schueler auf 2. Schueler erhoehen 
            }    
            l++;        // Naechster Schueler 
        } 
        system("PAUSE");    // Konsole wird nicht geschlossen 
    }
    

    zerlegt, zum Beispiel in

    int schueler__istFrei(struct schueler* this) {
    	return (strcmp(this->vorname,"")==0)||(strcmp(this->name,"")==0);
    }
    
    void schueler__ausgabe(struct schueler* this,int k) {
    	/* Ausgeben der Strings, in denen ein Schueler existiert */
    	int n;
    	printf("%d. Schueler:", k);
    	printf("\n\tVorname: %s", this->vorname);
    	printf("\n\tName: %s", this->name);
    	printf("\n\tGeburtsdatum: %s\n\n", this->gebdatum);
    	/* Dieses while ueberprueft, ob in dem String etwas steht, oder ob er leer ist */
    	for (n=0 ; n <= 19; n++) {
    		if (strcmp(this->faecher[n].fach,"")!=0) {
    			printf("\t%s: ", this->faecher[n].fach);
    			printf("\t%d\n", this->faecher[n].note);
    		}
    	}
    	printf("\n");
    }
    
    void ausgabe() {
    	system("cls");    // Clear Screen
    
    	int k = 1;    // Fuer 1. Schueler, 2. Schueler usw...
    
    	for (l=1 ; l < 200 ; l++) {   // Bis zum letzen Schueler
    		/* Dieses if ueberprueft, ob in dem String etwas steht, oder ob er leer ist */
    		if (!schueler__istFrei(&schueler[l])) {
    			schueler__ausgabe(&schueler[l],k);
    			k++;    // z.B. 1. Schueler auf 2. Schueler erhoehen
    		}
    	}
    	system("PAUSE");    // Konsole wird nicht geschlossen
    }
    

    So Sachen wie schueler__istFrei kannste mit ein wenig Glück dann uch in anderen Funktionen verwenden. Aber darum gehts gar nicht. Es geht nur drum, die Funktionen übersichtlicher zu machen. Aufräumen führt dann automatisch zur objektorientierten Programmierung, die entgegen anderslautender Gerüchte natürlich auch in C angemessen ist.



  • volkard schrieb:

    Aufräumen führt dann automatisch zur objektorientierten Programmierung, die entgegen anderslautender Gerüchte natürlich auch in C angemessen ist.

    das stimmt, aber es geht auch ohne zwei _ hintereinander.
    🙂



  • ;fricky schrieb:

    aber es geht auch ohne zwei _ hintereinander.

    Ja, ich hätte CamelCase_CamelCase schreiben sollen, wie Henkman&the_Underscores jetzt auch verabschiedet haben.
    Aber das blaue this ist ganz allein Dir gewidmet.



  • ;fricky schrieb:

    aber es geht auch ohne zwei _ hintereinander.

    Das ist so wie ++. Da muß halt auch __ rein. Wechen däm Obscheckt.

    Das geht in C genauso kompakt und wiederverwertbar. Aber, Hauptsache wir
    haben C-Code in C++-Syntax.



  • Scheppertreiber schrieb:

    Das geht in C genauso kompakt und wiederverwertbar. Aber, Hauptsache wir haben C-Code in C++-Syntax.

    Wenn ich recht informiert bin, geht

    int schueler__istFrei(struct schueler* this) { 
        return (strcmp(this->vorname,"")==0)||(strcmp(this->name,"")==0); 
    }
    

    gar nicht auf einem C++-Compiler, sondern nur auf einem C-Compiler.
    Ich würde mal behaupten, das ist C++-Code in C-Syntax und nicht wie Du geraten hast C-Code in C++-Syntax.



  • Funktioniert auch unter C++, wenn man vorher

    #define this that
    

    schreibt -)

    volkard und ;fricky, die Protagonisten der neuen Doku-Soap...



  • volkard schrieb:

    Aber das blaue this ist ganz allein Dir gewidmet.

    passt schon, es gibt 'nen codegenerator, der c-code ausspuckt und der auch 'this' nimmt. allerdings 'malloc'd' der sich noch 'ne struct, auf die sich das this bezieht. das fehlt noch bei dir.

    ich hätte CamelCase_CamelCase schreiben sollen, wie Henkman&the_Underscores jetzt auch verabschiedet haben.

    double__underscores hab u.a. ich ihm gestern (im IRC) wieder ausgeredet.
    🙂



  • volkard schrieb:

    Aufräumen führt dann automatisch zur objektorientierten Programmierung, die entgegen anderslautender Gerüchte natürlich auch in C angemessen ist.

    Huh? Wer behauptet denn so einen Blödsinn? Natürlich kann das angemessen sein, wo kommen wir denn sonst hin?

    volkard schrieb:

    Ja, ich hätte CamelCase_CamelCase schreiben sollen, wie Henkman&the_Underscores jetzt auch verabschiedet haben.

    Das hast du mit deinem absurden __Vorschlag ja auch schlau hinbekommen.
    🙂

    C++ forever schrieb:

    volkard und ;fricky, die Protagonisten der neuen Doku-Soap...

    denn zusammen rockt ihr die bude

    Immerhin verstehe ich diesmal, worum es geht.



  • Danke Leute, habt mir echt geholfen und hab das Programm jetzt soweit ausgebessert, doch ein paar Sachen von abcok verstehe ich noch nicht so ganz:

    1.) array-initialisierung mit 0, weil ich hab mir verkettet Listen noch nicht angesehen und für sowas braucht man verk. Listen, oder?

    2.) Etwas absichern (z.B. Eingabe mit scanf) versteh ich auch nicht. Meinst du mit fflush(stdin)den Tastaturpuffer leeren?

    3.) Wo geht bei dir die Funktion Fach eingeben nicht? Bei mir geht die pefekt...?!

    4.) Wie würdet ihr die Funktion aendern() verkürzen? Ich habe Noten ändern (das case im case) als eigene Funktion gemacht.

    5.) Wenn ich z.B bei "Wollen Sie noch ein Fach eingeben? (ja: 1 nein: 0)" 1231 eingebe, geht er gleich zum zweiten Schueler und überspringt alles unter der Eingabe in der Schleife. Hat das was mit dem Absichern zu tun?

    Bitte um Hilfe

    lG und danke nochmals 👍

    Sund0se



  • hi,
    zu 1)
    das initialisiert alle elemente des Arrays Schueler mit 0:

    Schueler schueler[200] = {0};
    

    zu 2)
    ein programm sollte nicht abstürzen, wenn anstatt einer angeforderten
    zahl ein buchstabe eingegeben wird. das war mit absichern gemeint.
    dafür gibt es u.a. die möglichkeit: einen puffer wählen, der groß genug ist

    char buf[BUFSIZ] = {0};
    

    und für die eingaben fgets benutzen ( die legendären funktionen wie clear_buffer, fflush(stdin), etc. entfallen dann gänzlich ) und aus diesem puffer alle weiteren infos wie zahlen, namen, datum etc. mittels sscanf etc. extrahieren.
    BUFSIZ ist die größe des eingabepuffers in bytes und in stdio.h definiert.

    zu 3)
    aber nur wenn der benutzer keinen fehler macht(buchstaben statt zahl eingibt). siehe 2)

    zu 4)
    funktion aendern() in teilaufgaben zerlegen und kleine funktionen draus machen.
    z.b. kannst du für namen eingeben und namen ändern eine funktion gemeinsam nutzen.
    zu 5)
    ja, das hat damit zu tun.

    hier noch die eine oder andere funktion als anregung, um zu zeigen was ich mit teilaufgaben und kleinen funktionen meine:

    #define ARRSIZ 64
    
    // Entfernt einen Zeilenumbruch, der von fgets eingefügt wird.
    void remove_newline ( char* buf )
    {
    	char* p = strrchr ( buf, '\n' );
    	if (p)
    		*p = 0;
    }
    
    typedef struct 
    {
    	char name[ARRSIZ];
    	char vorname[ARRSIZ];
    }Schueler;
    
    // Allgemeine Eingabefunktion.
     // allow_void_input bestimmt, ob eine Leereingabe erlaubt/nicht erlaubt ist. 
    int input ( char* buf, int bufsize, int allow_void_input )
    {
    	do
    	{
    		fgets ( buf, bufsize, stdin );
    		remove_newline (buf);
    		if ( ferror (stdin) )
    		{
    			perror ("input");
    			exit(1);
    		}
    		if ( allow_void_input == 0 && *buf == 0 )
    			puts ("Eine Leereingabe ist nicht erlaubt!");
    	}while ( *buf == 0 && allow_void_input == 0 );
    
    }
    
    void vorname_nachname_eingabe ( char* msg, char* buf, int bufsize, int allow_void )
    {
    	printf("%s ", msg );
    	input ( buf, bufsize, allow_void );
    }
    
    void vornamen_eingeben ( Schueler* ps )
    {
    	char buf[BUFSIZ] = {0}; 
    	if ( ps == NULL )
    		return;
    	do
    	{
    		vorname_nachname_eingabe ( "Vornamen eingeben:", buf, sizeof(buf), 0 );
    		if ( strlen(buf) >= sizeof(ps->vorname))
    			puts("Der eingegebene Vornamen ist zu lang.");
    		else if ( strlen ( buf ) > 0 )
    			strcpy(ps->vorname, buf);
    	}while ( strlen(buf) >= sizeof(ps->vorname) );
    }
    
    Schueler* schueler_suchen_vorname ( Schueler* ps, int n )
    {
    	int i;
    	char buf[BUFSIZ] = {0};
    	printf ("Vorname: ");
    	input ( buf, sizeof ( buf ), 0 );
    
    	for ( i = 0; i < n; i++ )
    		if ( strcmp ( buf, ps[i].vorname ) == 0 )
    			return &ps[i];
    	return NULL;
    }
    
    void schueler_anzeigen ( Schueler* ps )
    {
    	printf ( "Vorname: %s\n", ps->vorname );
    //	printf ( "Nachname: %s\n", ps->name );
    }
    
    void alle_schueler_anzeigen ( Schueler* ps, int n )
    {
    	int i;
    	for ( i = 0; i < n; i++ )
    		if ( *ps[i].vorname != 0 )
    			schueler_anzeigen ( &ps[i] );
    }
    
    #define N 300
    
    int main()
    {
    	Schueler* ps = NULL;
    	Schueler schueler[N] = {0};
    	int allow_void = 0; // Bestimmt, ob eine Leereingabe erlaubt/nicht erlaubt ist 
    
    	vornamen_eingeben ( &schueler[0] );
    
    	printf ("Alle Schueler anzeigen. ");
    	alle_schueler_anzeigen ( &schueler[0], N  ); 
    
    	printf ("Schueler suchen. ");
    	ps = schueler_suchen_vorname ( &schueler[0], N );
    
    	if ( ps != NULL )
    		puts ("Schueler gefunden");
    	else
    		puts ("Schueler nicht gefunden");
    
    	if ( !ps )
    		return 0;
    	// Gleiche Funktion wie für die Eingabe zum Ändern benutzen:
    	allow_void = 1; // Leere Eingabe genehm.
    	puts("Vornamen aendern, Abbruch mit Entertaste.");
    	vornamen_eingeben ( ps, allow_void );
    
    	printf ("Alle Schueler anzeigen. ");
    	alle_schueler_anzeigen ( &schueler[0], N  ); 
    
    	return 0;
    }
    

    einen schueler hinzuzufuegen würde ca. so aussehen:

    void neuen_schueler_eingeben ( Schueler* ps )
    {
    	vornamen_eingeben ( ps );
    	nachnamen_eingeben ( ps ); 
    	geburtsdatum_eingeben ( ps );
    	klasse_eingeben ( ps );
    	// USW
    }
    

    du siehst, das programm ist in teilaufgaben zerlegt, die von kleinen
    funktionen erledigt werden, wobei die funktionen nicht mehr als ca. 15 zeilen lang sind.



  • okay, super, vielen dank

    hab jetzt das ganze mit zeiger gemacht und es geht super.

    hätt da noch ne frage bzg. der funktion loeschen

    wenn der zeiger ps vom typ Schueler auf den schueler zeigt, den man löschen will, muss man doch einfach

    *ps[x].vorname = 0;
    

    da er bei der abfrage bei alle_schueler_anzeigen sowieso abfragt, ob der vorname nicht 0 ist, oder wie würdet ihr es machen?

    wenn so, wie kommt ihr dann auf das x?

    scheint ne blöde frage zu sein, steh aber echt auf der leitung!


Anmelden zum Antworten