struct in Datei speichern

musiKk

musiKk

Dr. Strangelove
struct in Datei speichern und inzwischen auch Auslesen...

Hallo,
sicher fuer viele ein Grund zum laecheln, bei mir klappts irgendwie nicht.
Und zwar soll ich structs der folgenden Form abspeichern:
Code:
struct satztyp {
	char name[20];
	char vorname[20];
	char anschrift[50];
	char telefon[20];
};
Ich habe erst in der cppreference den Eintrag zu fwrite studiert und angewendet. Das lustige ist nur: In der FH auf der SUN laeuft das ganze wunderbar, hier zu Hause unter Linux stimmt nur "name", der Rest besteht nur aus sinnlosen Zeichen.
Das wichtigste aus dem Code sollte dies sein:
Code:
void eingabe(char *dateiname) {
	struct satztyp* neu;
	neu=(struct satztyp*) malloc (sizeof(struct satztyp*));
	printf("\n\n");
	printf("--------------------------------\n");
	printf("--  Neuen Datensatz eingeben  --\n");
	printf("--------------------------------\n\n");

	printf("Name: ");
	scanf("%s",&(neu->name));
	printf("Vorname: ");
	scanf("%s",&(neu->vorname));
	printf("Anschrift: ");
	scanf("%s",&(neu->anschrift));
	printf("Telefon: ");
	scanf("%s",&(neu->telefon));
	Fflush();
	
	FILE *fp=fopen(dateiname, "a");
	fwrite(neu, sizeof(struct satztyp), 1, fp);
	fclose(fp);
}
Fflush() ist eine Funktion, die den Puffer leert, da ich las, dass fflush(stdout) nicht immer funktionieren soll.
Des weiteren habe ich auch mal statt scanf gets benutzt, da ich dies zuerst im Verdacht hatte, aber da kommt der gleiche Mist raus.

Waere dankbar fuer nen Denkanstoss...
 
Zuletzt bearbeitet:
Nun, zum ersten muss du nicht mit einem Pointer arbeiten.
Das ist auch dein Fehler beim Rausschreiben.

Dein Pointer neu zeigt genau auf den Anfang von char[20] name.
fwrite wird auch wohl nur bis zum \0 schreiben.

Also das könnte ich mir zumindest vorstellen.

Vll. nützt dir das ja schon was.
 
Zunächst ändere mal:

neu=(struct satztyp*) malloc (sizeof(struct satztyp*));

in

neu=(struct satztyp*) malloc (sizeof(struct satztyp));

Sonst liefert malloc Dir nur einen Speicherbereich von 4 Byte (je nach Pointergröße) zurück.

Bei Deinem scanf ist das &(...) überflüssig und kann weggelassen werden da es (bei char-Arrays).

fwrite schreibt genau das auf Platte was man der Funktion übergibt, ob ein \0 dabei ist, ist egal.

Der Rest ist ***eigentlich*** ok, abgesehen davon, das sich mir die Nackenhaare sträuben, wenn man mit scanf in ein char-Array liest - wo schreib der hin, wenn der Benutzer mal ein en Namen mit 100 Zeichen eingibt :oldman :D

Heiko
 
Zunächst ändere mal:

neu=(struct satztyp*) malloc (sizeof(struct satztyp*));

in

neu=(struct satztyp*) malloc (sizeof(struct satztyp));
Ach herrjeh... warum habe ich das gemacht? Das habe ich doch sonst immer richtig gehabt?

Bei Deinem scanf ist das &(...) überflüssig und kann weggelassen werden da es (bei char-Arrays).
Ich bin mir nicht ganz sicher, aber ich glaube, das hat unter Solaris Probleme bereitet... vielleicht taeusche ich mich aber auch.

Der Rest ist ***eigentlich*** ok, abgesehen davon, das sich mir die Nackenhaare sträuben, wenn man mit scanf in ein char-Array liest - wo schreib der hin, wenn der Benutzer mal ein en Namen mit 100 Zeichen eingibt :oldman :D

Heiko
Das glaube ich Dir gerne, ich werde das auch lieber mit fgets machen.

Vielen Dank. :)
 
Ok, es geht weiter (wie zu erwarten). So langsam fuehle ich mich von dem IO-System von C gehoerig verarscht; staendig haengen irgendwelche Enterzeichen oder so im Puffer rum, ich flush mir nen Wolf. Aber das nur nebenbei...

Problem ist jetzt: Wenn ich das Programm oeffne, eine neue Datei anlege (wobei der Name ueber ein Argument ODER innerhalt bestimmt wurde, das geht schonmal beides), da neue Datensaetze einfuege und diese dann auslesen will, klappt das wunderbar.
Schliesse ich das Programm allerdings und oeffne es auf exakt die gleiche Weise, dann bekomme ich beim Auslesen einen Segmentation fault.

Das wundert mich halt am meisten: Selbst wenn da noch irgendwelche anderen Fehler sind, wieso klappts bei naechsten Programmaufruf auf einmal nicht mehr? Wenns wenigstens NIE oder IMMER klappen wuerde, aber so...?

Weiss einer Rat? :(

(Funktion aendern() ist hier atm noch irrelevant, aber ich hab sie mal drin gelassen)

Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define Fflush() while(getchar() != '\n')

struct satztyp {
	char name[20];
	char vorname[20];
	char anschrift[50];
	char telefon[20];
};

char hauptmenue();
void eingabe(char*);
void ausgabe(char*);
void aendern(char*);

int main(int argc, char *argv[]) {
	char *dateiname=(char*) malloc (20);
	if(argc==1) {
		printf("Keine Datei angegeben, bitte Dateiname angeben: ");
		fgets(dateiname,20,stdin); dateiname[strlen(dateiname)-1]='\0';
		Fflush();
	} else {
		dateiname=argv[1];
	}
	while(1) {
		char auswahl;
		auswahl=hauptmenue();
		switch(auswahl) {
			case '1': eingabe(dateiname); break;
			case '2': ausgabe(dateiname); break;
			case '3': aendern(dateiname); break;
			default : exit(1);
		}
	}
}

char hauptmenue() {
	char auswahl;
	printf("-----------------------------------\n");
	printf("--  Das hier ist das Hauptmenue  --\n");
	printf("-----------------------------------\n\n");
	printf("1 - Neuen Datensatz eingeben\n");
	printf("2 - alle Datensaetze ausgeben\n");
	printf("3 - Datensatz aendern\n");
	printf("q - Beenden\n");
	printf("Auswahl: ");
	scanf("%s",&auswahl);
	Fflush();
	return auswahl;
}

void eingabe(char *dateiname) {
	struct satztyp* neu;
	neu=(struct satztyp*) malloc (sizeof(struct satztyp));
	printf("\n\n");
	printf("--------------------------------\n");
	printf("--  Neuen Datensatz eingeben  --\n");
	printf("--------------------------------\n\n");

	printf("Name: ");
	fgets(neu->name,20,stdin); neu->name[strlen(neu->name)-1]='\0';
	printf("Vorname: ");
	fgets(neu->vorname,20,stdin); neu->vorname[strlen(neu->vorname)-1]='\0';
	printf("Anschrift: ");
	fgets(neu->anschrift,50,stdin); neu->anschrift[strlen(neu->anschrift)-1]='\0';
	printf("Telefon: ");
	fgets(neu->telefon,20,stdin); neu->telefon[strlen(neu->telefon)-1]='\0';
	Fflush();
	FILE *fp=fopen(dateiname, "a");
	fwrite(neu, sizeof(struct satztyp), 1, fp);
	fclose(fp);
	free(neu);
}

void ausgabe(char *dateiname) {
	printf("\n\n");
	printf("Nr.           Name        Vorname      Anschrift        Telefon\n");
	printf("---------------------------------------------------------------\n");
	FILE *fp=fopen(dateiname, "r");
	struct satztyp* temp;
	temp=(struct satztyp*) malloc (sizeof(struct satztyp));
	int zaehler=1;
	
	while(fread(temp, sizeof(struct satztyp), 1, fp)) {
		printf("%3d%15s%15s%15s%15s\n",zaehler, temp->name,temp->vorname,temp->anschrift,temp->telefon);
		zaehler++;
	}
	free(temp);
	fclose(fp);
	printf("\n\n");
}

void aendern(char *dateiname) {
	int auswahl, i;
	struct satztyp* temp;
	temp=(struct satztyp*) malloc (sizeof(struct satztyp));
	FILE *fp=fopen(dateiname, "r+");
	
	ausgabe(dateiname);
	printf("Welcher Datensatz soll geaendert werden?\n");
	scanf("%d", &auswahl);
	
	for(i=1;i<auswahl;i++) {
		fp++;
	}
	
	struct satztyp* neu;
	neu=(struct satztyp*) malloc (sizeof(struct satztyp));
	printf("\n\n");
	printf("--------------------------------\n");
	printf("--     Datensatz aendern      --\n");
	printf("--------------------------------\n\n");

	printf("Name: ");
	fgets(neu->name,20,stdin); neu->name[strlen(neu->name)-1]='\0';
	printf("Vorname: ");
	fgets(neu->vorname,20,stdin); neu->vorname[strlen(neu->vorname)-1]='\0';
	printf("Anschrift: ");
	fgets(neu->anschrift,50,stdin); neu->anschrift[strlen(neu->anschrift)-1]='\0';
	printf("Telefon: ");
	fgets(neu->telefon,20,stdin); neu->telefon[strlen(neu->telefon)-1]='\0';
	Fflush();
	
	fwrite(neu, sizeof(struct satztyp), 1, fp);
	fclose(fp);
}
 
char auswahl;
...
scanf("%s",&auswahl);

Ooops - das ist nicht gut - mach besser einen int draus und %d, ebenso aus dem Rückgabewert von hauptmenü(). In dem switch mußt Du dann nicht nach '1', ... sondern nach 1 (als Zahl) ... fragen. Hier geht das dann ... alternativ kannst Du allerdings auch im hauptmenü in einen etwas größeren Array scanf'en:

char auswahl[10];
...
scanf("%s",&auswahl);
return auswahl[0];

Heiko
 
Ja, naja... ich wollte doch aber noch nach 'q' fragen, weil ich 'q' zum Beenden nehmen wollte. Egal, ich hab noch ne Menge dran rumgefummelt... am meisten hat mich dann nochmal irritiert, dass jemand anders das unter Windows perfekt zum Laufen bekommen hat.

Die Auswahl geht bei mir jetzt ueber getchar(). Und was soll ich sagen... SEITDEM gehts. Das Schreiben der Datei war ein Problem. Vorher war es Zufall, obs ging. Ich kanns mir einfach nicht erklaeren. Mal gabs Segmetation Faults, mal hiess meine Datei, wie ich sie nannte, mal war es einfach nur ein wilder Zeichenwust. Hier mal ein Beispiel.

Mein naechstes Problem ist: Hier geht jetzt erstmal wirklich alles. Auch das Aendern. Allerdings nutzt mir das nix, weil ich das Programm in der FH auf ner SUN vorfuehren muss und DA geht das Aendern nicht! Ich glaub, ich krieg noch ganz viele graue Haare deswegen... :(
 
Jaja, als ich vor vielen Jahren meine ersten C-Laufschritte gemacht habe, hatte ich ähnliche Probleme. Man muß erst mal "drin" sein, um richtig zu verstehen wie man Probleme angeht und lösen kann ...

Oje, das sehe ich jetzt erst, habe die aendern Funktion noch nicht angesehen - allerdings möchte ich auch ungerne Deine Hausaufgabe machen :D

Aber mal als Tipp: den Rückgabewert von fopen darfst Du auf keinen Fall mit ++ oder so ändern, dieser Wert zeigt auf eine "struct FILE" (oder wie auch immer "FILE" auf dem System implementiert ist). Ein "++" würde in einem Array von FILE-Strukturen auf die nächste Zeigen, bei Dir zeigt sie also anschließend ins Nirwada ...

Also: "man fseek" oder alle Dummy-Sätze überlesen ...

Viel Erfolg :headup:

Heiko
 
Keine Sorge, niemand soll meine "Hausaufgaben" machen. ;)

Das mit dem Filepointer kam mir auch spanisch vor, funktionierte aber glaub ich mal. Egal, ich mach das jetzt per fread(temp, sizeof(struct satztyp), 1, fp); (glaube, das ist auch das, was du mit "ueberlesen" meinst). Das wird halt so oft ausgefuehrt, bis man an der richtigen Stelle ist. Das ist zwar sicher auch nicht die tollste Variante, aber sie klappt zumindest unter Linux. Da Solaris wieder was voellig anderes draus macht, bin ich aber wohl gezwungen, mir fseek anzuschauen.

Klar, bei mir wird kein Bereich ueberprueft, aber das sind fuer mich Feinheiten, die geringere Prioritaet haben.
 

Ähnliche Themen

fußballstatistik auswerten

Aus Datei lesen

incompatible types in assignment

Datei lesen/schreiben

Ausgabe in *.txt Datei & Struct

Zurück
Oben