Segmentation fault

Vippis

Mitglied
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:
#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 fu?r die Mitgliedseintra?ge eine geeignete Struktur (bestehend aus Vorname, Nachname, Mit- gliedsnummer und Telefonnummer). Schreiben Sie dann eine Funktion mit der Aufgabe, per Dialog einen Mitgliedseintrag auszufu?llen und eine andere Funktion, die fu?r die Ausgabe eines einzelnen Eintrags zusta?ndig ist. Hier sollen selbstversta?ndlich immer nur Pointer auf den jeweiligen Eintrag u?bergeben werden. Im Hauptprogramm gibt es ein Menu?, in dem man die jeweiligen Funktionalita?ten und Eintra?ge auswa?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:
C++:
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:

C++:
//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 ( :D )

Der Vorteil liegt darin, dass man nicht bei einer Person bleiben muss...
C++:
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ß
 
Zuletzt bearbeitet:
gefordert war:
Definieren Sie fu?r die Mitgliedseintra?ge eine geeignete Struktur (bestehend aus Vorname, Nachname, Mit- gliedsnummer und Telefonnummer).
Du machst:
C:
struct mitglied {
	char vorname[100];
	char nachname[100];
	char mitgliedsnr[100];
	char telefonnr[100];
};
Warum nimmst du die Aufgabenstellung nicht wörtlich und DEFinierst einen TYP von einer Struktur:
C:
typedef struct {
	char vorname[100];
	char nachname[100];
	char mitgliedsnr[100];
	char telefonnr[100];
} Mitglied;
Schreiben Sie dann eine Funktion mit der Aufgabe, per Dialog einen Mitgliedseintrag auszufu?llen und eine andere Funktion, die fu?r die Ausgabe eines einzelnen Eintrags zusta?ndig ist. Hier sollen selbstversta?ndlich immer nur Pointer auf den jeweiligen Eintrag u?bergeben werden.
Wo ist denn bei dir der geforderte Parameter?
So sieht sowas z.B. aus:
C:
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:
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ß
 
Zuletzt bearbeitet:
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:
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 ?
 
Zurück