-
Hallo,
Ich bin ein Anfänger im Programmieren und muss für das Studium ein paar Programme verfassen.
Ich hab jetzt bei einer Aufgabe ein kleines Problem. Man soll quasi ein kleines Mitgliedsverzeichens anlegen und auch ausgeben. Mir geht es jedoch im Moment eher um das einlesen der Daten.
Ich schätze mal, dass es ein anfänger Fehler oder sowas in der Art ist, da der compiler das Programm zwar akzeptiert, aber ich beim ausführen (in dem Moment ,wenn ich etwas eingeben könnte) Segmentation Fault anzeigt.
Kann auch daran liegen, dass ich die Pointer noch nicht so richtig durchblicke. Vllt. sieht ja einer von euch was diesen Fehler verursacht.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
#include <stdio.h> #include <strings.h> struct mitglied { char vorname[100]; char nachname[100]; char mitgliedsnr[100]; char telefonnr[100]; }; void eingabe(){ struct mitglied *person; struct mitglied *ptr; ptr = person; /*Hier liegt wohl das Problem */ printf("Geben Sie den Nachnamen des neuen Mitglieds ein\n"); fgets(ptr->nachname, 100, stdin); printf("Geben Sie den Vornamen des neuen Mitglieds ein\n"); fgets(ptr->vorname, 100, stdin); printf("Geben Sie die Mitgliedsnr des neuen Mitglieds ein\n"); fgets(ptr->mitgliedsnr, 100, stdin); printf("Geben Sie die Telefonnr des neuen Mitglieds ein\n"); fgets(ptr->telefonnr, 100, stdin); int i; for (i=0; i>100; i++) { printf("%s",ptr->nachname); } }; int main(){ int menu; printf("Willkommen im Mitgliedsverzeichnis\n"); printf("------------------------------------\n"); printf("Aus Gruenden des Datenschutzes werden\nkeine Eintraege dauerhaft gespeichert.\n"); printf("------------------------------------\n"); printf("(1)Ausgabe eines vorhandenen Eintrags\n"); printf("(2)Eingabe eines neuen Eintrages\n"); printf("(0)Ende des programms\n"); printf("Eingabe: "); scanf("%d",&menu); switch(menu){ case 1: break; case 2: eingabe(); break; case 0: break; default: printf("Geben Sie bitte eine der angegeben Nummer ein!\n"); break; } return 0; }
-
Willkommen bei tutorials.de

Beim main, case 0, solltest du statt break ein return schreiben, damit das Programm auch wirklich beendet wird, statt einfach wieder eine Zahl zu fordern.
Und das Einlesen...die Aufgabe ist wahrscheinlich, ein Array aus Mitgliedern zu machen?
-
Ja das mit dem return bei case 0 stimmt. Aber ich wollte ich wollte erst die funktionen schreiben bevor ich die main funktion fertigstelle.
Die Aufgabe ist es am Anfang ein Programm Diaglog zu haben wie er in der Main dargestellt ist.
In der letzten Vorlesung ging es um Struct und Pointer. In der Aufgabe steht auch, dass diese mit Pointer gelöst werden soll.
Segmentation Fault scheint ja irgendein Speicherfehler zu sein, oder?
Ist denn die Übergabe der Eingabe in das Array richtig? Bzw. funktioniert das auch so mit fgets ?
-
Zu deiner Funktion:
Die fgets sind richtig, ja. Die printf sind auch nicht das Problem, aber die Pointer...
Einmal angenommen, du willst nur ein Mitglied haben und nicht mehr dazufügen können (wie aus dem printf im main hervorgeht).
Dann müsstest du statt
struct mitglied *person;
das schreiben:
struct mitglied person;
OHNE Stern. Um ein int zu machen, schreibst du ja auch nicht int*, oder?
Mit dem Stern sagst du grundsätzlich: Es gibt eine mitglied-Variable, irgendow im Arbeitsspeicher. Fertig.
Solange du dem Zeiger nichts zuweist, weiß er auch nicht wo. Und bevor du ihm was zuweisen kannst, muss es die Variable eben schon geben. Ein Pointer hat eben nur den "Ort" einer Variablen, nicht aber die Variable selber.
Die Variable ptr vergisst du derweil am besten einmal und entfernst sie (die Zuweisung eine Zeile danach auch)
Noch was: Die for-Schleife, soll die den Nachnamen des neuen Mitglieds ausgeben?
1) würde da ein einzelnes printf mit %s reichen, das macht von selber alle Buchstaben
2) Wenn du schon fgets verwendest, warum dann nicht einfach
puts(person->nachname);
puts kann zwar zusammengesetzte Sachen mit (mehreren) %s, %d etc nicht verarbeiten, für einen einzelnen String reichts aber.
3) Eine for-Schleife, die von 0 bis 99 zählen soll, ist nicht
for(i=0;i>100;i++)
sondern
for(i=0;i<100;i++)
Angefangen mit 0, SOLANGE bis es Hundert erreicht...
Deine Variante würde heißen:
Anfangen mit 0 und so oft machen, wie es schon von Anfang an größer als Hundert ist...also garnicht.
Nochwas: "struct" musst du nur bei der Deklaration der Struktur schreiben, also welche Variablen drin sind etc.
Für
struct mitglied person;
reicht auch
mitglied person;
so wie "int i;" etc...
Es ist kein Fehler, aber unnötig.
-
Erstmal Danke für die ausführlich Antwort zu später Stunde.
Wie müsste denn das mit den Pointer aussehen. Aus dem Vorlesungscript werde ich nicht wirklich schlau. In der Aufgabe wird gefordert, dass man mehere Mitglieder eingeben kann.
Ein kleines Beispiel in dem auch Struct vorkommt, würde meinem Kopf vllt. ein wenig auf die Sprünge helfen.
Der Pointer zeigt doch auf einen gewissen Speichereintrag:
Mitglied 1
Mitglied 2
.
.
Mitglied n
wobei der pointer=n ist , oder verstehe ich das falsch?
Hier mal die Aufgabe:
Erstellen Sie ein Programm, welches die Mitglieder eines Vereins verwaltet. Definieren Sie für die Mitgliedseinträge eine geeignete Struktur (bestehend aus Vorname, Nachname, Mit- gliedsnummer und Telefonnummer). Schreiben Sie dann eine Funktion mit der Aufgabe, per Dialog einen Mitgliedseintrag auszufüllen und eine andere Funktion, die für die Ausgabe eines einzelnen Eintrags zuständig ist. Hier sollen selbstverständlich immer nur Pointer auf den jeweiligen Eintrag übergeben werden. Im Hauptprogramm gibt es ein Menü, in dem man die jeweiligen Funktionalitäten und Einträge auswählen kann.
-
Es gibt verschiedene Arten, zur Laufzeit Speicher Speicher für mehr Mitglieder bekommen
Eine davon sind die Funktionen malloc/realloc/free und sizeof.
Kleine Erklärung:
sizeof: Ermittelt, wieviel Byte eine bestimmte Variable/eine Variable vom Typ ... im Arbeitsspeicher braucht.
Beispiel:
Code cpp:1 2 3 4 5 6
int i; //... printf("Ein int braucht %d Bytes\n", sizeof(i) ); //Byteanzahl von i, also einem int: 4 printf("Ein char braucht %d Bytes\n", sizeof(char) ); //Geht auch mit dem Typ selber: 1 //... printf("Ein Mitglied braucht %d Bytes\n", sizeof(mitglied) ); //Sollte selbsterklärend sein...
malloc: Kann während der Programmausführung eine bestimmte Byteanzahl im Speicher für dein Programm reservieren. Angenommen, man will "sizeof(mitglied)" Byte haben...dann hat man damit praktisch eine weitere Mitglied-Variable.
Allerdings kann man dafür beim Quelltextschreiben nicht einfach einen Variablennamen vergeben, die Variable wird ja erst zur Laufzeit "gemacht".
Und genau dafür braucht man jetzt die Pointer: malloc gibt passend dazu gleich die Adresse im Speicher zurück, wo die reservierten Bytes zu finden sind; also den "Ort"; und genau das was man einem Pointer zuweisen sollte.
free: Bevor es dazu aber ein Codebeispiel gibt, kommt besagtes free noch dran.
Wenn du im Quelltext eine normale Variable machst, kannst du die einfach verwenden und wenn du ihr nichts mehr zuweisen willst und den Wert nicht mehr brauchst, lässt du sie eben bis zum Programmende links liegen.
Beim Speicher, der mit malloc reserviert ("allokiert") wurde, musst du aber (wenn du die Variablen nicht mehr brauchst) dafür sorgen, dass das Betriebssystem weiß "Du brauchst den Speicher nicht mehr, kann ein anderes Programm haben".
Spätestens in der letzten Programmzeile musst du daher die Funktion free aufrufen und den Pointer übergeben, der zu dem malloc-Speicher zeigt.
Sonst würden besagte Bytes weiter als "noch gebraucht" markiert bleiben...beim nächsten malloc wird irgendwo anders ein freier Platz gesucht...und irgendwann ist der gesamte Speicher im Computer verstopft und das Betriebssystem findet kein einziges freies Byte mehr.
Obwohl die Programme, die den Speicher haben wollten, ja schon längst wieder beendet sind; aber alles "noch gebraucht" wird...
Also nie aufs free vergessen!
Und jetzt aber das Beispiel:
Code cpp:1 2 3 4 5 6 7 8 9 10 11 12 13
//Zum Vergleich eine normale Variable: mitglied person1; person1.nachname... ... //Jetzt Pointerart mitglied *person2; person2= (mitglied*) malloc( sizeof(mitglied) ); //Ich möchte soviel Byte, wie ein Mitglied braucht... person2->nachname... //Wenn du die person2 nicht mehr brauchst: free(person2);
Und jetzt wirst du dich fragen: Was bringt mir das? Mehr Schreibarbeit?
Hier: Ja, sonst nichts (
)
Der Vorteil liegt darin, dass man nicht bei einer Person bleiben muss...
Code cpp:1 2 3 4 5 6 7 8 9 10 11
mitglied *mehrmitglieder; mehrmitglieder= (mitglied*) malloc( 100 * sizeof(mitglied) ); //100 Mitglieder... mehrmitglieder[0].nachname...//Erstes Mitglied ("->" von oben ist nur eine Abkürzung für "[0].") mehrmitglieder[1].nachname...//Zweites Mitglied mehrmitglieder[2].nachname...//Drittes Mitglied //...und so weiter free(mehrmitglieder);
Und mit realloc kannst du die malloc-Größe auch nachträglich verändern, mehr oder weniger Platz für Mitglieder schaffen.
So, Schluss für heute.
Ich denke, du hast fürs Erste genüg Lesestoff.
Wenn was unklar ist, einfach fragen.
GrußGeändert von sheel (02.12.10 um 00:48 Uhr)
-
02.12.10 20:03 #7
- Registriert seit
- Oct 2010
- Beiträge
- 35
gefordert war:
Definieren Sie für die Mitgliedseinträge eine geeignete Struktur (bestehend aus Vorname, Nachname, Mit- gliedsnummer und Telefonnummer).
Du machst:
Warum nimmst du die Aufgabenstellung nicht wörtlich und DEFinierst einen TYP von einer Struktur:
Code c:1 2 3 4 5 6
typedef struct { char vorname[100]; char nachname[100]; char mitgliedsnr[100]; char telefonnr[100]; } Mitglied;
Wo ist denn bei dir der geforderte Parameter?Schreiben Sie dann eine Funktion mit der Aufgabe, per Dialog einen Mitgliedseintrag auszufüllen und eine andere Funktion, die für die Ausgabe eines einzelnen Eintrags zuständig ist. Hier sollen selbstverständlich immer nur Pointer auf den jeweiligen Eintrag übergeben werden.
So sieht sowas z.B. aus:
Code c:1 2 3 4 5 6 7 8 9 10
void eingabe(Mitglied *mitglied){ printf("Geben Sie den Nachnamen des neuen Mitglieds ein\n"); fgets(mitglied->nachname, 100, stdin); printf("Geben Sie den Vornamen des neuen Mitglieds ein\n"); fgets(mitglied->vorname, 100, stdin); printf("Geben Sie die Mitgliedsnr des neuen Mitglieds ein\n"); fgets(mitglied->mitgliedsnr, 100, stdin); printf("Geben Sie die Telefonnr des neuen Mitglieds ein\n"); fgets(mitglied->telefonnr, 100, stdin); }
-
@sheel
malloc reserviert den Speicher den ich für die mitglieder benötige.
Wenn ich das jetzt mit fgets einlesen will:
Muss ich das irgendwie casten oder sonst was machen ?
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
typedef struct { char vorname[100]; char nachname[100]; char mitgliedsnr[100]; char telefonnr[100]; } Mitglied; void eingabe(Mitglied *personen){ Mitglied *personen; personen = (Mitglied*)malloc(sizeof(Mitglied)); printf("Geben Sie den Nachnamen des neuen Mitglieds ein\n"); personen[0].nachname = fgets(personen->nachname, 100, stdin); printf("Geben Sie den Vornamen des neuen Mitglieds ein\n"); printf("Geben Sie die Mitgliedsnr des neuen Mitglieds ein\n"); printf("Geben Sie die Telefonnr des neuen Mitglieds ein\n"); free(personen); }
Kannst du mir sagen wie so eine Zeile aussehen müsste ? Jetzt nur um erstmal nur ein Mitglied einzulesen, damit ich das dann übertragen kann, oder es versuchen.
@Trulleberg
Danke für den Hinweis!
Auch auf die Gefahr hin als Volldepp dazustehen, aber würde das auf die eine oder andere Art in der programmierung nachher ein großes Unterschied machen ?
-
Zum typedef von trulleberg: Nein, macht keinen großen Unterschied
Zum Einlesen: Dein fgets ist eigentlich komplett richtig, aber das = und alles links davon ist beim fgets nicht nötig
Was auch Probleme macht: Deine Funktion eingabe bekommt ein "Mitglied *personen" übergeben und macht gleich danach noch eine Variable namens personen.
Welches personen soll fgets jetzt befüllen?
Und in der Aufgabe ist angegeben, dass nur der Pointer an einlesen übergeben werden soll.
Klingt danach, dass es den Speicherbereich schon geben soll.
Also malloc/free besser außerhalb von einlesen machen
In einlesen zuerst ein malloc zu machen, dann was einlesen und sofort danach im einlesen noch ein free würde auch irgendwie keinen Sinn machen.
Mit free schmeißt du das Eingelesene ja sofort wieder weg!
(Genau genommen bleibt das Eingelesene schon noch da, du kannst dir aber nicht sicher sein wann das Betriebssystem genau diesen Platz für ein anderes Programm etc wieder verwenden will und dieses eigene Sachen drin abspeichert. Kann sofort sein, muss aber bis zum Ausschalten auch gar nicht passieren...)
GrußGeändert von sheel (03.12.10 um 00:30 Uhr)
-
Also den Segmentation Fault Fehler habe ich jetzt nicht mehr.
Aber ein anderes kleines Problem. Das programm gibt mir nicht die Möglichkeit was einzugeben.
Ich hab schon versucht da was mit if verzweigungen zu machen, aber dann bricht er die funktion nur früher ab.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
void eingabe(Mitglied *personen){ int x; if(x==0){ printf("Geben Sie den Nachnamen des neuen Mitglieds ein\n"); fgets(personen->nachname, 50, stdin); x++; } if(x==2){ printf("Geben Sie den Vornamen des neuen Mitglieds ein\n"); fgets(personen->vorname, 50, stdin); x++; } if (x==3) { printf("Geben Sie die Mitgliedsnr des neuen Mitglieds ein\n"); fgets(personen->mitgliedsnr, 50, stdin); x++; } if(x==4){ printf("Geben Sie die Telefonnr des neuen Mitglieds ein\n"); fgets(personen->telefonnr, 50, stdin); } x=0; }
Normalerweise gibt das Programm doch die Möglichkeit um etwas einzugeben,oder ?
Ein Idee wie man das bewerkstelligen kann ?
-
So kann das nicht gehen.
Du machst ein int x und weist ihm am Anfang noch keinen Wert zu.
Dann steht irgendwas nicht voraussehbares drin, zB -887321283
Und nur wenn zufällig 0 drinsteht (was in ca 99.99999999% nicht sein wird), wird der Nachname eingelesen.
Das Gleiche für 2,3,4 mit Vorname etc.
Wozu sind überhaupt die Ganze ifs?
Alle if, alle x++, das int x und überhaupt alles mit x weg, dann ists gut.
-
Code :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
void eingabe(Mitglied *personen){ printf("Geben Sie den Nachnamen des neuen Mitglieds ein\n"); fgets(personen->nachname, 50, stdin); printf("Geben Sie den Vornamen des neuen Mitglieds ein\n"); fgets(personen->vorname, 50, stdin); printf("Geben Sie die Mitgliedsnr des neuen Mitglieds ein\n"); fgets(personen->mitgliedsnr, 50, stdin); printf("Geben Sie die Telefonnr des neuen Mitglieds ein\n"); fgets(personen->telefonnr, 50, stdin); }
Entschuldigung vllt. war ich etwas undeutlich.
So Sieht die Konsole aus:
(1)Ausgabe eines vorhandenen Eintrags
(2)Eingabe eines neuen Eintrages
(0)Ende des programms
Eingabe: 2
Geben Sie den Nachnamen des neuen Mitglieds ein
Geben Sie den Vornamen des neuen Mitglieds ein
Den Vornamen,Mitgliednr. , telnr, kann ich eingeben, den Nachnamen jedoch nicht. Ich erkenne nicht weshalb. Das ist das Problem.
-
03.12.10 11:19 #13
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Hi.
Das Problem ist, dass du folgende Sequenz im Programm hast:
Du könntest jetzt einfach in einer Zeile eingeben:
Das würde funktionieren.Code :1
2Meier-Schulze-Hohmann
Du aber gibst ein "2" "ENTER". Das führt dazu, dass "2\n" in der Eingabe steht. Die 2 liest du in menu ein und dann kommt fgets, womit du dann nur eine leere Zeile einliest.
Wenn du zeilenweise arbeiten willst, dann lies auch die Eingabe für die Menüauswahl mit fgets ein und verwende dann statt scanf einfach sscanf auf dem String.
GrußIf at first you don't succeed, try again. Then quit. No use being a damn fool about it.
-
Ach, wieder mal dieses gemeine scanf

Das hat leider manchmal solche Problemchen...
Im main verwendest du ja zum Einlesen, was der Benutzer machen will, ein scanf.
Das liest solange ein, bis du einmal Enter drückst.
Jeder deiner Tastendrücker kommt zuerst in einen Tastaturbuffer(/Zwischenspeicher) und wird dann von dort von scnaf abgeholt.
Aus ungeklärten Grunden lässt es aber manchmal das abschließende Enter drin (im Tastaturbuffer.
Es hört zwar durchd as Enter zu lesen auf, entfernt das Enter aber nicht.
das fgets für den Nachnamen ist dann die nächste Funktion, die den Tastaturbuffer braucht.
Das Enter ist noch drin.
fgets liest es ein; denkt dass der Benutzer schon Enter gedrückt hat und hört sofort wieder auf zum Lesen.
Wenigstens entfernt es das Enter aus dem Tastaturbuffer.
Dann kommt das fgets für den Vornamen, das findet nicht sofort ein Enter und wartet deshalb wieder ordentlich auf eine Eingabe.
So, genug Erklärung.
Zum Problemlösen könntest du zB:
Die Zahl auch zuerst als String mit fgets einlesen
und dann mit sscanf in ein int "umwandeln".
sscanf ist wie scanf, liest aber nicht von der Tastatur sondern aus einem String.
Code cpp:1 2 3 4 5 6 7 8 9 10 11 12 13
int menu; char menustring[10]; printf("Willkommen im Mitgliedsverzeichnis\n"); printf("------------------------------------\n"); printf("Aus Gruenden des Datenschutzes werden\nkeine Eintraege dauerhaft gespeichert.\n"); printf("------------------------------------\n"); printf("(1)Ausgabe eines vorhandenen Eintrags\n"); printf("(2)Eingabe eines neuen Eintrages\n"); printf("(0)Ende des programms\n"); printf("Eingabe: "); fgets(menustring,10,stdin); sscanf(menustring,"%d",&menu);
Gruß
-
Jap das wars Danke.
Vielen Dank!
Ähnliche Themen
-
Segmentation Fault
Von Schnoogle im Forum C/C++Antworten: 1Letzter Beitrag: 10.02.10, 12:25 -
Segmentation Fault
Von flogy92 im Forum C/C++Antworten: 23Letzter Beitrag: 28.01.09, 09:31 -
Segmentation fault
Von stain im Forum Linux & UnixAntworten: 0Letzter Beitrag: 28.04.08, 18:34 -
C: Segmentation fault
Von Westbär im Forum C/C++Antworten: 3Letzter Beitrag: 05.07.07, 10:46 -
MC-Fehler Segmentation Fault?
Von piti66 im Forum Linux & UnixAntworten: 0Letzter Beitrag: 06.07.05, 21:06



3Danke

Zitieren


Login






