Programm bricht bei der Eingabe ab
-
Hi, hab mal wieder ein hoffentlich kleines Problem.
Ich hab zu Übungszwecken ein Programm geschrieben, welches Personalien einlesen soll, diese in einer Datei speichern soll und anschliessend wieder auslesen und auf dem Bildschirm ausgeben soll.
Und das alles mit den umständlichen Mitteln, wie der Prof es meistens fordert
Das Problem ist jetzt, das das Programm nach der Eingabe des Alters abstürzt.
Hier der code der Unterfunktion:// Liest die Personalien ein void einlesen(PERSONALIEN *person) { printf("\nBitte geben Sie jetzt die Personalien der %i. Person ein:\n", person->nummer); printf("\nVorname: "); scanf("%s", person->vorname); printf("\nNachname: "); scanf("%s", person->nachname); printf("\nAlter: "); scanf("%i", person->alter); printf("\nStrasse: "); scanf("%s", person->strasse); printf("\nHausnummer: "); scanf("%i", person->hausnummer); }
Und hier der des ganzen Programmes:
#include <stdio.h> #include <stdlib.h> #include <string.h> /****************************************************/ /*** Programm soll die Personalien mehrerer *********/ /*** Personen einlesen, in einer Datei speichern, ***/ /*** wieder auslesen und am Bildschirm ausgeben *****/ /****************************************************/ // Struktur mit Personalien typedef struct { int nummer; char vorname[30]; char nachname[30]; int alter; char strasse[30]; int hausnummer; }PERSONALIEN; // Tauscht ein Leerzeichen gegen einen Unterstrich und umgekehrt char zeichen_tauschen(char *daten) { int i; for (i=0; i<29; i++) { if(daten[i] == ' ') { daten[i] = '_'; return (*daten); } if(daten[i] == '_') { daten[i] = ' '; return (*daten); } } return 0; } // Liest die Personalien ein void einlesen(PERSONALIEN *person) { printf("\nBitte geben Sie jetzt die Personalien der %i. Person ein:\n", person->nummer); printf("\nVorname: "); scanf("%s", person->vorname); printf("\nNachname: "); scanf("%s", person->nachname); printf("\nAlter: "); scanf("%i", person->alter); printf("\nStrasse: "); scanf("%s", person->strasse); printf("\nHausnummer: "); scanf("%i", person->hausnummer); } // Hauptprogramm int main() { char dateiname[30]; PERSONALIEN person; FILE *file_ptr; int i, n; printf("\nWie viele Personen wollen Sie eingeben: "); scanf("%i", &n); for(i=1; i<=n; i++) { person.nummer = i; einlesen(&person); printf("\n\nWie soll die Datei heissen, in der die Daten gespeichert werden: "); scanf("%s", dateiname); file_ptr = fopen("dateiname","w"); fprintf(file_ptr,"%i %s %s %i %s %i\n", person.nummer, zeichen_tauschen(person.vorname), zeichen_tauschen(person.nachname), person.alter, zeichen_tauschen(person.strasse), person.hausnummer); } fclose(file_ptr); file_ptr = fopen("dateiname","r"); printf("\nDatei wird ausgelesen\n"); for(i=1; i<=n; i++) { fscanf(file_ptr,"%i %s %s %i %s %i\n", &person.nummer, zeichen_tauschen(person.vorname), zeichen_tauschen(person.nachname), &person.alter, zeichen_tauschen(person.strasse), &person.hausnummer); printf("\n%i %s %s %i %s %i", person.nummer, person.vorname, person.nachname, person.alter, person.strasse, person.hausnummer); } fclose(file_ptr); return 0; }
Ob das mit dem Zeichen tauschen funktioniert weiss ich auch noch nicht, das Programm läuft ja nicht lange
-
Ich schätze, dass es am Einlesen des Alters liegt:
Unser Prof. hat uns f. Tipp gegeben:
char help; scanf("%d%c",person.alter,&help);
Weil man nach dem %d noch ENTER drückt, giebt es wahrscheinlich mit den nächsten scanf Komplikationen. Durch das %d wird das Enter auf eine Hilfsvariable help gespeichert!
PS.: alle Zahlen mit einem anschließendem %c einlesen und es müsste funktionieren.
-
noch eine Frage:
Warum verwendest du oben:
person->alterund unten
person.alterDas ist doch das gleiche!?!
-
chille07 schrieb:
noch eine Frage:
Warum verwendest du oben:
person->alterund unten
person.alterDas ist doch das gleiche!?!
Nope, ist es nicht.
Das ist gleich:
var->foo == (*var).foo Die Klammer is nötig, da der Punkt stärker bindet als der Derefernzierungsoperator
-
chille07 schrieb:
noch eine Frage:
Warum verwendest du oben:
person->alterund unten
person.alterDas ist doch das gleiche!?!
person->alter hab ich benutzt, weil in der Teilfunktion
void einlesen()
person ein Zeiger auf die Struktur ist und im main Programm ist es eine normale Variable und da benutzt man nur den Punkt.
person->alter ist nur die Kurzschreibweise für (*person).alter wie interpreter schon richtig bemerkt hat.Es muss doch aber noch ne elegantere Lösung für mein Problem geben, oder?
-
Hallo,
um welches Problem geht es denn jetzt noch, wenn du von einer "eleganteren Lösung" sprichst? Geht es also immer noch um den Absturz? Wenn ja, dann füge nur den &-Operator beim Einlesen des Alters in der einlesen-Funktion hinzu (der Absturz genau an dieser Stelle war schon ein Hinweis, daß genau in dieser Zeile das Problem auch liegt, in main bei der Eingabe der Anzahl der Personen hast du es richtig gemacht, also Leichtsinnsfehler, würde ich sagen):
scanf("%i", &person->alter);
nach weiteren Fehlern habe ich jetzt nicht gesehen, aber zumindest an dieser Stelle sollte es jetzt weitergehen.
MfG
-
Aber ich lese das Alter doch mit Hilfe eines Pointers ein, da benutzt man den Adressoperator doch nicht, oder hab ich da jetzt was falsch verstanden?!
Also eigentlich müsste der Einleseausdruck an sich stimmen, deswegen versteh' ich ja auch nicht warum das Programm an der Stelle abbricht.Und mit eleganterer Lösung meinte ich, dass ich nicht einfach sinnlos einen weiteren Wert einlesen möchte, da ich mir 100%ig sicher bin dass es auch anders geht.
-
ok, ich dachte, du hättest das Problem erkannt, deshalb jetzt doch ausführlich:
vergleiche einmal das Einlesen des integers in main:
scanf("%i", &n);
mit dem Einlesen des selben Datentyps in der einlesen-Funktion:
scanf("%i", person->alter);
hier ist schon der Unterschied zu erkennen, der ganze Ausdruck person->alter ist vom Typ int, und scanf erwartet die Adresse einer int-Variablen. Deshalb ist es so richtig (zur Verdeutlichung habe ich geklammert, ist aber unnötig, da der "->"-Operator eine höhere Priorität als der &-Operator hat):
scanf("%i", &(person->alter) );
es geht also nicht darum, daß person schon ein Zeiger ist, sondern der "resultierende" Ausdruck person->alter stellt eine int-Variable dar, deren Adresse für scanf dementsprechend korrekt übergeben werden muß.
Dabei habe ich übersehen, daß du auch person->hausnummer falsch behandelst (wird jetzt klar, da du nicht wußtest, was hier passiert), also muß es auch heißen:
scanf("%i", &person->hausnummer);
ich weiß immer noch nicht, welchen Wert du beim Einlesen als sinnlos erachtest (das Einlesen des Dateinamens jedesmal für jede neue Person?), man kann noch einiges verbessern..
vielleicht meintest du ja das:
du fragst hier:
printf("\n\nWie soll die Datei heissen, in der die Daten gespeichert werden: "); scanf("%s", dateiname);
für jede Person nach einem eigenen Dateinamen, aber dann öffnest du hier:
file_ptr = fopen("dateiname","w");
jedes Mal dieselbe Datei mit dem Namen "dateiname", statt den eingelesenen Namen zu verwenden, das erscheint zumindest auch mir sinnlos, aber dann laß doch einfach das Einlesen des Dateinamens weg. Soll er auch vom Benutzer festgelegt werden können, dann verlege die Eingabe des Dateinamens doch einfach nach außerhalb der for-Schleife.
Wenn erst einmal klar ist, was denn nun passieren soll (was sind die genauen Anforderungen, in einer Datei speichern oder in mehreren?) bzw. was für dich (noch) sinnlos ist, kann man am Programm noch einiges verbessern oder ändern.
MfG
-
ah, jetzt versteh ichs, danke.
Ich hab ganz vergessen, dass der -> schon den Dereferenzierungsoperator enthält. Und bei person->vorname geht es weil da der Zeiger auf eine Zeichenkette zeigt, richtig?Und mit sinnlos einlesen meinte ich eigentlich den Kommentar von chille07
char help; scanf("%d%c",person.alter,&help);
Das Einlesen des Dateinamens hab ich jetzt auch aus der for-Schleife rausgenommen, das sollte da eigentlich auch gar nicht rein. Es sollten natürlich alle Personen in einer Datei gespeichert werden.
Aber was mir noch völlig unklar ist, wie das mit dem Zeichen tauschen funktioniert. An der Stelle bricht das Programm nämlich jetzt ab.
Der Grund für die Funktion ist, falls z.B. ein Strassenname eine Lücke enthält, dass dieser später bei fscanf nicht als zwei Wörter gesehen wird.Wenn mir da noch einer helfen könnte wäre ich überglücklich