Pointer und Dateien lesen



  • Leider komme ich mit meinem Addressbuch gerade gar nicht weiter.
    Seitdem ich die globalen Variable eliminiert habe, funktioniert gar kein Eintrag mehr 😞

    Und dann möchte ich mit EintragSuchen die einzelnen Attribute in das STruct hineinschreiben. Gerade a wäre ich für Tipps sehr dankbar. "\0" als Trennzeichenn zu verwenden, sogt scheinbar für große Problem

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdint.h>
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    #define MAX 30
    
    struct adres {
        char vname[MAX];
        char nname[MAX];
        char plz[5];
        char ort[MAX];
        int geburtsjahr;
    } adressen;
    
    void eintragSuchen( FILE *addresbuch) {
        int status;
        char trennzeichen[] = "\0";
        char nachname[30] = {0};
    
        printf("Eingabe von Nachnamen: ");
        scanf("%30[A-Z]", nachname);
        fseek(addresbuch, 0L, SEEK_SET);
    
        do {
            status = fscanf_s(addresbuch, "%s %s %s %s %d", adressen.vname, adressen.nname, adressen.plz,  adressen.ort, adressen.geburtsjahr);
            printf("Vorname %s ---", adressen.vname);
            printf(" Nachname %s ---", adressen.nname);
          	printf("plz %s ---" , adressen.plz);
            printf("ort %s \n" , adressen.ort);
            printf("Jahr: %s \n" , adressen.geburtsjahr);
        } while (status != EOF);
    
    }
    
    /**
    Um einen String in eien Datei zu schreiben, erst zu String konnvertieren dann schreiben
              char buffer[16] = {0}; 
                  sprintf(buffer, "%d", adressen.plz);
      fputs(buffer, addresbuch);
    
     */
    void eintragEingeben( FILE *addresbuch) {
    
        char buffer[30] = {0};
        char trennzeichen[] = "\0";
        char ende[] = ";";
        printf("Vorname      : ");
        scanf("%s30[A-Z]", adressen.vname);
        fflush(stdin);
        printf("Nachname      : ");
        scanf("%30[A-Z]", adressen.nname);
        fflush(stdin);
    
        printf("Postleitzahl : ");
        do {
            scanf("%s", &adressen.plz);
        } while (getchar() != '\n');
    
        printf("Wohnort      : ");
        scanf("%30[A-Z]", adressen.ort);
        printf("Geburtsjahr  : ");
        do {
            scanf("%4d", &adressen.geburtsjahr);
        } while (getchar() != '\n');
    
        fputs(strcat(adressen.vname, trennzeichen), addresbuch);
        fputs(strcat(adressen.nname, trennzeichen), addresbuch);
        sprintf(buffer, "%d", adressen.plz);
        fputs(strcat(buffer, trennzeichen), addresbuch);
    
        fputs(strcat(adressen.ort, trennzeichen), addresbuch);
        sprintf(buffer, "%d", adressen.geburtsjahr);
        fputs(buffer, addresbuch);
    
        fputs(ende, addresbuch);
    
    }
    
    void menue(FILE *addresbuch) {
        int a;
        printf("----- Addresbuch ---- \n");
        printf("----- W?hlen Sie eine Funktion ---- \n");
        printf("1 -  Eintragen \n");
        printf("2 -  Eintrag ausgeben \n");
        printf("3 -  Eintrag modifizieren \n");
        printf("Auswahl:");
        scanf("%d", &a);
        fflush(stdin);
        switch (a) {
    
            case 1:
                eintragEingeben(&addresbuch);
    
                break;
         case 2:
                eintragSuchen(&addresbuch);
                break;
    
        }
    
    }
    
    FILE erstelleDatei() {
    
       FILE *addresbuch = fopen("addresbuch.txt", "a+");
    
    }
    
    int main(int argc, char** argv) {
    
        FILE addressbuch = erstelleDatei();
        menue(&addressbuch);
        return 0;
    }
    

  • Mod

    BoosterBey schrieb:

    Seitdem ich die globalen Variable eliminiert habe,

    adressen ist global. Und auch noch äußerst irreführend bezeichnet, weil es nur eine einzelne Adresse ist.

    fflush(stdin) ist immer noch undefiniertes Verhalten. Ich kann dein Programm überhaupt gar nicht selber ausprobieren, weil es bei mir deswegen nicht funktioniert.

    Die Zeilen 110-118 sind falsch. Man arbeitet niemals direkt mit FILE-Objekten, immer nur mit Zeigern darauf. Deine Funktion gibt nichts zurück.

    Die Grenzen in deinen scanfs passen nicht zu den Größen deiner Datenfelder. Die Grenze in scanf gibt an, wie viel maximal gelesen wird, nicht wie viel maximal gespeichert wird (was normalerweise ein char mehr ist, als gelesen wurde).

    Ich glaube nicht, dass die ganzen do{scanf}while(getchar!='\n') tun, was du denkst.

    Allgemein krankt dein Programm an seiner Struktur und an den von dir verwendeten Bezeichnern. Ich weiß, das ist schwer für Anfänger, aber es ist sehr hilfreich, wenn du es lernst. Denn dann schreiben sich die Programme fast von alleine viel leichter fehlerfrei und sind viel einfacher zu verstehen:

    • Zunächst empfiehlt es sich sehr, auf Englisch zu programmieren, denn die ganzen Schlüsselwörter sind sowieso auf Englisch, dann liest es sich wie aus einem Guss.
    • Variablen sind irgendwelche Objekte unserer Vorstellungskraft und haben eine entsprechende Bezeichnung. Außerdem muss diese Bezeichnung genau zu dem passen, was die Variable ist. Einige, die mir negativ aufgefallen sind:
    • adressen : Der Plural passt nicht, es ist nur eine Adresse.
    • addresbuch : Das ist eine Datei. Die enthält vielleicht ein Adressbuch, aber sie ist kein Adressbuch.
    • ende : Was?
    • a : Was?
    • Funktionen tun etwas. Ihre Bezeichner stehen im Imperativ. Das passt bei dir halbwegs, aber menue fällt vollkommen aus der Reihe. In manchen Fällen kann man einer Funktion auch eine Beschreibung ihres Rückgabewertes als Bezeichner geben, wenn man eher betonen möchte, dass sie etwas zurück gibt, als dass sie etwas tut. Z.B. max() für eine Funktion, die das Maximum von etwas zurück gibt. Das trifft auf dein Menü aber auch nicht zu.
    • Jede Funktion macht genau ein Ding und nur dieses Ding, das aber gut. Deine Funktionen machen viel zu viel. eintragSuchen sucht nicht nur einen Eintrag (tatsächlich suchst sie überhaupt nichts), sondern ist praktisch ein vollständiges Unterprogramm mit eigener Menüführung. Ebenso fast alle deiner anderen Funktionen. Die machen viel zu viel. eintragSuchen sollte wirklich nur einen Eintrag suchen. Keine Eingaben, keine Ausgaben, nur Suchen.

    Die einzige Funktion, die bei dir macht, was sie verspricht, ist erstelleDatei (bis auf den oben angesprochenen Fehler). Wobei sie aber auch schon wieder so wenig macht, dass der Sinn für die Funktion verloren geht, denn worin besteht der Unterschied zwischen dieser Funktion und fopen?

    Dein zweites großen Problem sind Eingaben. Du scheinst nicht genau zu verstehen, was die Eingabefunktionen jeweils machen und wie das Eingabemodell in C funktioniert. Dieser Beitrag wird gerade schon arg lang, daher verweise ich mal auf entsprechende Fachliteratur oder hoffe auf Erklärungen anderer Foristen, während ich erst einmal Kaffee trinken gehe...



  • Danke. Ich werde versuchen das Stück für Stück umsetzen. Würdest du mir denn thereothisch erklären, wie die Daten am besten einlese und wie ich diese dann getrennt auslesen kann?



  • SeppJ schrieb:

    Allgemein krankt dein Programm an seiner Struktur

    Das sehe ich nicht so, die Struktur ist OK.
    - ein Objekt in main() definieren, das dann durch alle Funktionen herumgereicht wird
    - prinzipielle Trennung von Oberflächen/Daten/Fehlerbehandlung/... Aktionen durch Funktionen

    Die Implementierung ist aber grundsätzlich Schrott.
    Was du brauchst ist eine (persistierte) Liste von struct-Elementen, das kann man - so wie du - direkt mit einem FILE-Stream machen, einfacher und somit weniger fehleranfällig ist es, eine dyn. Liste von struct zu verwenden, siehe Beispiel, und die reichst du dann herum.
    Außerdem ist für deinen Fall eine textbasierte Datei unpraktisch, besser wäre eine Binärdatei, siehe Beispiel. Paddingbytes und Byteorder sind dabei zwar impl.abhängig von deinem Compiler/Laufzeitsystem, das kannst du aber erstmal ignorieren, solange du deine Datei ausschließlich in deinem System mit dem gleichen Compiler verwendest.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    enum { MAXILEN = 100 };
    
    typedef struct {
    	char vname[MAXILEN];
    	char nname[MAXILEN];
    	char plz[MAXILEN];
    	char ort[MAXILEN];
    	int geburtsjahr;
    } Adresse;
    
    typedef struct {
    	int anzahl;
    	Adresse *liste;
    } Liste;
    
    void eintragSuchen(const Liste *liste) {
    	Adresse temp = { 0 };
    	printf("Eingabe von Nachnamen: ");
    	scanf("%99[^\n]", temp.nname); while (getchar() != '\n');
    
    	for(int i=0;i<liste->anzahl;++i) /* einfaches Suchen in der Liste im Speicher statt aufwändig mit fseek/fscanf in der Datei zu navigieren */
    	{
    		if (!strcmp(temp.nname, liste->liste[i].nname))
    		{
    			printf("Vorname %s ---", liste->liste[i].vname);
    			printf(" Nachname %s ---", liste->liste[i].nname);
    			printf("plz %s ---", liste->liste[i].plz);
    			printf("ort %s \n", liste->liste[i].ort);
    			printf("Jahr: %d \n", liste->liste[i].geburtsjahr);
    		}
    	} 
    }
    
    /* 
    	eine Adresse eingeben und hinten an die Liste (im Speicher!) anhängen
    */
    void eintragEingeben(Liste *liste) {
    	Adresse temp = { 0 };
    
    	printf("Vorname      : ");
    	scanf("%99[^\n]", temp.vname); while (getchar() != '\n');
    	printf("Nachname      : ");
    	scanf("%99[^\n]", temp.nname); while (getchar() != '\n');
    	printf("Postleitzahl : ");
    	scanf("%99[^\n]", temp.plz); while (getchar() != '\n');
    	printf("Wohnort      : ");
    	scanf("%99[^\n]", temp.ort); while (getchar() != '\n');
    	printf("Geburtsjahr  : ");
    	scanf("%d", &temp.geburtsjahr); while (getchar() != '\n');
    
    	/* hinten an die Liste anhängen */
    	liste->liste = realloc(liste->liste, ++liste->anzahl * sizeof*liste->liste);
    	liste->liste[liste->anzahl - 1] = temp;
    }
    
    void menue(Liste *liste) {
    	while (1)
    	{
    		int a;
    		printf("----- Addresbuch ---- \n");
    		printf("----- W?hlen Sie eine Funktion ---- \n");
    		printf("1 -  Eintragen \n");
    		printf("2 -  Eintrag ausgeben \n");
    		printf("3 -  Eintrag modifizieren \n");
    		printf("Auswahl:");
    		switch (scanf("%d", &a)==1?a:0) {
    		case 1:	 while (getchar() != '\n'); eintragEingeben(liste); break;
    		case 2:	 while (getchar() != '\n'); eintragSuchen(liste);	break;
    		default:  while (getchar() != '\n'); return;
    		}
    	}
    }
    
    void removeListe(Liste *l) { l->anzahl = 0; free(l->liste); }
    void leseListe(Liste *liste, const char *datei)
    {
    	FILE *f = fopen(datei, "rb");
    	if (f)
    	{
    		fread(&liste->anzahl, sizeof(int), 1, f);
    		liste->liste = realloc(liste->liste, liste->anzahl * sizeof*liste->liste);
    		fread(liste->liste, sizeof*liste->liste, liste->anzahl, f);
    		fclose(f);
    	}
    }
    void schreibeListe(const Liste *liste, const char *datei)
    {
    	FILE *f = fopen(datei, "wb");
    	if (f)
    	{
    		fwrite(&liste->anzahl, sizeof(int), 1, f);
    		fwrite(liste->liste, sizeof*liste->liste, liste->anzahl, f);
    		fclose(f);
    	}
    }
    
    int main()
    {
    	Liste liste = { 0 };  /* Arbeitsobjekt definieren und initialisieren */
    	leseListe(&liste, "adressen.dat"); /* befüllen aus Datei */
    
    	menue(&liste); /* Liste bearbeiten, Elemente hinzufügen... */
    
    	schreibeListe(&liste, "adressen.dat"); /* Liste persistieren */
    	removeListe(&liste); /* Listenspeicher freigeben */
    	return 0;
    }
    

Log in to reply