ReRene Geschrieben 1. Februar 2008 Teilen Geschrieben 1. Februar 2008 Hi Leute, bin noch ein ziemlicher Anfänger, was das C programmieren angeht. Mache deshalb z.Zt. einige Übungen und da hänge ich z.Zt. an einem Problem. Also erstmal kompiliert es ohne Fehlermeldung durch, aber nach dem Programmaufruf erhalte ich einen Speicherzugriffsfehler. Der Zweck des kleinen Übungsprogramms ist es, eine Struktur in einer File zu speichern. Man soll aber auch die Möglichkeit haben, die Daten wieder herauszulesen und darzustellen. Später sollen noch Funktionen folgen, die es möglich machen, den gespeicherten Datensatz zu bearbeiten, das kommt aber noch. Habe den Code in drei Dateien "datensatz.c", "datensatz.h" und "main.c" (die ersten beiden Dateien sollen quasi universell einsetzbar sein, sodass ich mehrere Programme auf Basis der ersten beiden Dateien machen könnte). Nun also mein Code sieht folgendermassen aus: "datensatz.h" #ifndef DATENSATZ_H_ #define DATENSATZ_H_ struct datensatz { char *nachname; char *vorname; char *strasse; char *hausnummer; char *plz; char *ort; char *telefonnummer; }; int daten_lesen (struct datensatz*, char*); int daten_schreiben (struct datensatz*, char*); void daten_ausgeben (struct datensatz*); void daten_bearbeiten (struct datensatz*); //Die Funktion wird später noch geschrieben, wenn ich das Problem erstmal in den Griff bekommen habe #endif "datensatz.c" #include"datensatz.h" #include<stdio.h> int daten_lesen (struct datensatz *ds, char *dateiname) { FILE *lesen; int ausg; lesen = fopen(dateiname, "r"); if (lesen == NULL){ printf("\nDatei konnte nicht gelesen werden!\n"); ausg = 0; } else { printf("\nÖffnen erfolgreich\n"); fgetc(lesen); fscanf(lesen, "%s", &ds->nachname); fscanf(lesen, "%s", &ds->vorname); fscanf(lesen, "%s", &ds->strasse); fscanf(lesen, "%s", &ds->hausnummer); fscanf(lesen, "%s", &ds->plz); fscanf(lesen, "%s", &ds->ort); fscanf(lesen, "%s", &ds->telefonnummer); fgetc(lesen); ausg = 1; printf("\nDaten erfolgreich eingelesen\n"); fclose(lesen); }; return ausg; } int daten_schreiben (struct datensatz *ds, char *dateiname) { FILE *schreiben; int ausg; schreiben = fopen(dateiname, "a+"); if (schreiben == NULL){ printf("\nBeim Öffnen oder Erstellen der Datei \"%s\" ist ein Fehler aufgetreten!\n", dateiname); ausg = 0; } else { printf("\nBeginne damit Daten zu schreiben\n"); fprintf(schreiben, "%s\n", ds->nachname); fprintf(schreiben, "%s\n", ds->vorname); fprintf(schreiben, "%s\n", ds->strasse); fprintf(schreiben, "%s\n", ds->hausnummer); fprintf(schreiben, "%s\n", ds->plz); fprintf(schreiben, "%s\n", ds->ort); fprintf(schreiben, "%s\n", ds->telefonnummer); ausg = 1; printf("\nDaten erfolgreich geschrieben\n"); fclose(schreiben); }; return ausg; } void daten_ausgeben(struct datensatz *ds) { printf("\n%s\n", ds->nachname); printf("%s\n", ds->vorname); printf("%s\n", ds->strasse); printf("%s\n", ds->hausnummer); printf("%s\n", ds->plz); printf("%s\n", ds->ort); printf("%s\n", ds->telefonnummer); } #endif "main.c" #include<stdio.h> #include"datensatz.h" void main() { struct datensatz ds1; ds1.nachname = "Testn"; ds1.vorname = "Testv"; ds1.strasse = "Tests"; ds1.hausnummer = "Testh"; ds1.plz = "Testp"; ds1.ort = "Testo"; ds1.telefonnummer = "Testt"; struct datensatz ds2; daten_schreiben(&ds1, "test.txt"); daten_lesen(&ds2, "test.txt"); daten_schreiben(&ds2, "test2.txt"); //daten_ausgeben(&ds1); //printf("\n\nDatensatz 2\n\n"); //printf("%s\n", *ds2.nachname); //daten_ausgeben(&ds2); } Also kompiliert wird mit GCC 4.2.3 unter Linux x86 mit folgenden Kommandos: gcc -c datensatz.c gcc -c main.c gcc -o datensatz datensatz.o main.o Das daraus folgende Programm "datensatz" dient eigentlich nur dazu, die Funktionen zu überprüfen. Genauso mit den vier "printf" Anweisungen in den Funktionen "daten_lesen(..)" und "daten_schreiben(..)" nur zur Funktionskontrolle dienen. Als Ausgabe des Programms erhalte ich folgendes: >./datensatz Beginne damit Daten zu schreiben Daten erfolgreich geschrieben Öffnen erfolgreich Daten erfolgreich eingelesen Beginne damit Daten zu schreiben Daten erfolgreich geschrieben Speicherzugriffsfehler Es steht zwar ein zweites mal da, dass das Schreiben der Datei erfolgreich war, doch befindet sich lediglich in der ersten Datei leserlicher Text in der Form: Testn Testv Tests Testh Testp Testo Testt Die zweite Datei ist leer. Nun vermute ich, dass irgendetwas mit der "daten_lesen(..)" Funtkion nicht stimmt, da ja die "daten_schreiben(..)" Funktion beim ersten mal richtig Funktioniert. Also müsste wohl irgendetwas mit den Daten zwischen dem Auslesen aus der Datei und dem Schreiben in der zweiten Datei passieren. Ich bedanke mich schoneinmal im Voraus. Wäre sehr toll, wenn mit jemand zumindest einen Anhaltspunkt geben könnte. Falls ihr nochwas wissen müsst, dann fragts einfach PS: Stimmt die "daten_ausgeben(..)" Funktion eigentlich so? Also, wenn ich die beiden Fnktionen, in denen die zweite "datensatz" Struktur verwendet wird, auskommentiere und stattdessen "daten_ausgeben(&ds1)" stehen lasse, dann kommt eine Ausgabe. Also sollte das doch funktionieren, oder? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Klotzkopp Geschrieben 1. Februar 2008 Teilen Geschrieben 1. Februar 2008 In deinem Programm fehlt die Speicherverwaltung komplett. Du hantierst hier mit Zeigern, ohne dich auch nur im Geringsten darum zu kümmern, dass die auch auf gültige Speicherbereiche zeigen. In C ist das Bereitstellen des Speichers deine Aufgabe. Solange du nur mit Stringliteralen hantierst, und nur lesend darauf zugreifst (ds1), geht das noch gut. Danach knallts aber. Und bei scanf & Co. musst du bei der Verwendung von %s einen Zeiger auf char angeben, nicht dessen Adresse. Dieser Fehler dürfte der Grund sein, warum es nicht sofort beim fscanf knallt. Falsch ist es trotzdem. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
ReRene Geschrieben 1. Februar 2008 Autor Teilen Geschrieben 1. Februar 2008 Danke erstmal, dass du mir hilfst. Toll, dass um die Uhrzeit Freitag Nachts noch jemand da ist Nun stellen sich mir aber weitere Fragen. Wie mach ich das mit der Speicherverwaltung. Wie gesagt, bin noch totaler Anfänger. Mit "malloc()" und "free()", oder? OK, dann weiss ich schonmal, womit ich mich beschäftigen muss. Nun zu dem Kommentar zu "scanf" und Co. Wenn ich den Adressoperator "&" in der "daten_lesen(..)" Funktion entferne, dann kommt der Speicherzugriffsfehler bereits nach der Meldung, dass die Datei erfolgreich geöffnet wurde. Löst sich das Problem auch, wenn ich mich um eine ordentliche Speicherverwaltung kümmere? Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Klotzkopp Geschrieben 2. Februar 2008 Teilen Geschrieben 2. Februar 2008 Wie mach ich das mit der Speicherverwaltung. Wie gesagt, bin noch totaler Anfänger. Mit "malloc()" und "free()", oder?Richtig. Nun zu dem Kommentar zu "scanf" und Co. Wenn ich den Adressoperator "&" in der "daten_lesen(..)" Funktion entferne, dann kommt der Speicherzugriffsfehler bereits nach der Meldung, dass die Datei erfolgreich geöffnet wurde. Durch diesen zweiten Fehler macht sich das fehlende Speichermanagement später bemerkbar. Statt direkt dorthin einzulesen, wo deine uninitialisierten char-Zeiger hinzeigen, liest du dorthin ein, wo diese Zeiger selbst im Speicher liegen. Du schreibst also Text dorthin, wo eigentlich Adressen stehen sollten. Da deine Struktur auf dem Stack liegt, geht das offenbar noch gut - auch wenn es undefiniertes Verhalten ist. Das Programm stürzt aber dann ab, wenn du versuchst, bei der Ausgabe den eingelesenen Text als char-Zeiger zu interpretieren. Löst sich das Problem auch, wenn ich mich um eine ordentliche Speicherverwaltung kümmere?Ja. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
ReRene Geschrieben 2. Februar 2008 Autor Teilen Geschrieben 2. Februar 2008 Danke für deine Hilfe. Jetzt funktioniert es, so wie ich es wollte. Habe den Code jetzt folgendermassen abgeändert. In "datensatz.c" habe ich folgende Funktionen zum anfordern und freigeben von Speicher hinzugefügt: int daten_anlegen (struct datensatz *ds, char *nname, char *vname, char *str, char *hausnr, char *pl, char *or, char *tel) { int ausg = 1; ds->nachname = (char *) malloc((strlen(nname)+1) * sizeof(char)); strcpy(ds->nachname, nname); ds->vorname = (char *) malloc((strlen(vname)+1) * sizeof(char)); strcpy(ds->vorname, vname); ds->strasse = (char *) malloc((strlen(str)+1) * sizeof(char)); strcpy(ds->strasse, str); ds->hausnummer = (char *) malloc((strlen(hausnr)+1) * sizeof(char)); strcpy(ds->hausnummer, hausnr); ds->plz = (char *) malloc((strlen(pl)+1) * sizeof(char)); strcpy(ds->plz, pl); ds->ort = (char *) malloc((strlen(or)+1) * sizeof(char)); strcpy(ds->ort, or); ds->telefonnummer = (char *) malloc((strlen(tel)+1) * sizeof(char)); strcpy(ds->telefonnummer, tel); return ausg; } void daten_freigeben (struct datensatz *ds) { free(ds->nachname); free(ds->vorname); free(ds->strasse); free(ds->hausnummer); free(ds->plz); free(ds->ort); free(ds->telefonnummer); printf("\nDaten freigegeben\n"); } und die Funktion zum Auslesen aus der Datei hab ich folgendermassen abgeändert (das dick geschriebene ist neu): int daten_lesen (struct datensatz *ds, char *dateiname) { [B]char *buffer_nachname = (char *) malloc(51 * sizeof(char)); char *buffer_vorname = (char *) malloc(51 * sizeof(char)); char *buffer_strasse = (char *) malloc(51 * sizeof(char)); char *buffer_hausnummer = (char *) malloc(51 * sizeof(char)); char *buffer_plz = (char *) malloc(51 * sizeof(char)); char *buffer_ort = (char *) malloc(51 * sizeof(char)); char *buffer_telefonnummer = (char *) malloc(51 * sizeof(char));[/B] FILE *lesen; int ausg; lesen = fopen(dateiname, "r"); if (lesen == NULL){ printf("\nDatei konnte nicht gelesen werden!\n"); ausg = 0; } else { printf("\nÖffnen erfolgreich\n"); fscanf(lesen, "%s", [B]buffer_nachname[/B]); fscanf(lesen, "%s", [B]buffer_vorname[/B]); fscanf(lesen, "%s", [B]buffer_strasse[/B]); fscanf(lesen, "%s", [B]buffer_hausnummer[/B]); fscanf(lesen, "%s", [B]buffer_plz[/B]); fscanf(lesen, "%s", [B]buffer_ort[/B]); fscanf(lesen, "%s", [B]buffer_telefonnummer[/B]); [B]daten_anlegen(ds, buffer_nachname, buffer_vorname, buffer_strasse, buffer_hausnummer, buffer_plz, buffer_ort, buffer_telefonnummer);[/B] ausg = 1; printf("\nDaten erfolgreich eingelesen\n"); [B]free(buffer_nachname); free(buffer_vorname); free(buffer_strasse); free(buffer_hausnummer); free(buffer_plz); free(buffer_ort); free(buffer_telefonnummer);[/B] fclose(lesen); }; return ausg; } Bin jetzt auch wieder um eine Erfahrung reicher^^ Also nochmal vielen Dank. Falls irgendwer noch nachbesserungsbedarf sieht, immer her mit den Tips Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Klotzkopp Geschrieben 2. Februar 2008 Teilen Geschrieben 2. Februar 2008 Ein paar Anmerkungen hätte ich noch: Den Faktor sizeof(char) könntest du weglassen, der ist laut Definition 1. Er schadet natürlich auch nicht, und wenn du dir das so angewöhnst, vergisst du es auch bei anderen Typen nicht so leicht. Zweitens castest du den Rückgabewert von malloc. Das ist in C nicht notwendig, und kann sogar unter bestimmten Umständen Fehler verdecken. Die (char *)-Casts sollten also besser raus. Drittens kannst du auf das Semikolon am Ende eines Else-Blocks verzichten Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
ReRene Geschrieben 2. Februar 2008 Autor Teilen Geschrieben 2. Februar 2008 Danke, habe deine Tips berücksichtigt. Hier fühlt man sich gut aufgehoben Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen Mehr Optionen zum Teilen...
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.