C - Telefonbuch Zeiger/Listen

Neue Frage »

Auf diesen Beitrag antworten »
LightSideOfLife C - Telefonbuch Zeiger/Listen

Hallo Leute,
ich muss euch leider noch einmal nerven!

Unsere letzte Praktikumsaufgabe hat es (meiner Meinung nach) in sich.
Wir sollen ein einfaches Telefonbuch mithilfe von Listen realisieren.

Es soll:
1.: Einträge neu erstellen können (vom Nutzer eingegeben)
2.: Alle Einträge ausgeben können
3.: Nach einem Nachnamen suchen und die dazu passende Telefonnummer ausgeben
4.: Nach einem Nachnamen suchen und diesen Eintrag dann löschen
5.: Das komplette Telefonbuch löschen.

Mit der theoretischen Umsetzung an sich habe ich kein Problem, aber es hapert noch am Verständnis von Listen und etwas bei Zeigern.
Ich habe bereits Teilaufgabe 1 und 2 programmiert bekommen, jedoch weißt dies noch einen Fehler auf:

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:
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    char *nachname;
    char *vorname;
    char *wohnort;
    long int telefonnummer;
	struct Person *next;
}Person;

void Hinzufuegen(Person *derzeitige)
{
	Person *naechste;
	char *n_name;
	char *v_name;
	char *w_ort;
	long int t_nummer;
		if (derzeitige == NULL) return;
		if (derzeitige->next != NULL) return;

			printf("\nGeben Sie den Nachnamen ein\n");		scanf("%s", n_name);	
			printf("\nGeben Sie den Vornamen ein\n"); 		scanf("%s", v_name);
			printf("\nGeben Sie den Wohnort ein\n"); 		scanf("%s", w_ort);	
			printf("\nGeben Sie die Telefonnummer ein\n"); 	scanf("%d", &t_nummer);
	
		derzeitige->next	= (struct Person*) malloc(sizeof(Person));
		naechste 			= (Person*) derzeitige->next;
			naechste->nachname 		= n_name;
			naechste->vorname 		= v_name;
			naechste->wohnort 		= w_ort;
			naechste->telefonnummer = t_nummer;
			naechste->next 			= NULL;
}

void Ausgabe(Person *erste)
{
	int i = 1;
	Person *derzeitige = erste;
		while (derzeitige != NULL)
		{
			printf("%d. Person: %s, %s, %s, %ld \n",i, derzeitige->nachname, derzeitige->vorname, derzeitige->wohnort, derzeitige->telefonnummer);
			derzeitige = (Person*) derzeitige->next;
			i++;
		}
}

main()
{
    Person *erste, *derzeitige;
	erste = (Person*) malloc(sizeof(Person));
	
	erste->nachname = "Kinkel";
	erste->vorname = "Marvin";
	erste->wohnort = "Dinslaken";
	erste->telefonnummer = 491635685977;
	erste->next = NULL;
	derzeitige = erste;
	
	Hinzufuegen(derzeitige);
	Hinzufuegen(derzeitige);
	Ausgabe(erste);
}


Schaut man sich die Funktion "Hinzufuegen()" an sieht man, dass ich per scanf Werte an die Zeiger übergeben möchte.
Sobald ich aber den v_namen eingeben möchte (nach dem n_namen) bricht das Programm (mittendrin) ohne Fehlermeldung ab, als wäre nichts passiert.
Nutze ich aber stattdessen die Befehle:

code:
1:
scanf("%s", &v_name);         scanf("%s", &w_ort);


Speichert er n_name korrekt ein und gibt es auch bei der Ausgabe korrekt aus.
Nur v_name und w_ort dann natürlich nicht.
Ist meine Methode um Benutzereingaben an eine Struktur zu übergeben falsch?

Für Hilfe wäre ich sehr dankbar!
 
Auf diesen Beitrag antworten »
eulerscheZahl

Hast du da deinen Namen und die Mobilfunknummer mit reingeschrieben?

Du hast erst mal nur Zeiger auf char definiert, keinen Speicher reserviert.
Versuche mal char n_name[20];. Damit ist der Absturz schonmal weg.
Jetzt kommen aber nur falsche Daten bei der Ausgabe. Du suchst strcpy, das = klappt da nicht.
Achja: scanf("%ld", &t_nummer);. Habe das %d zum %ld gemacht.
Auf diesen Beitrag antworten »
LightSideOfLife

Ok ich versuche es mal großes Grinsen
Habe gerade mist gebaut
Auf diesen Beitrag antworten »
LightSideOfLife

Hiermit:

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:
void Hinzufuegen(Person *derzeitige)
{
	Person *naechste;
	char *n_name[20];
	char *v_name[20];
	char *w_ort[20];
	long int t_nummer;
		if (derzeitige == NULL) return;
		if (derzeitige->next != NULL) return;

			printf("\nGeben Sie den Nachnamen ein\n");		scanf("%s", n_name);	
			printf("\nGeben Sie den Vornamen ein\n"); 		scanf("%s", v_name);
			printf("\nGeben Sie den Wohnort ein\n"); 		scanf("%s", w_ort);	
			printf("\nGeben Sie die Telefonnummer ein\n"); 	scanf("%ld", &t_nummer);
	
		derzeitige->next	= (struct Person*) malloc(sizeof(Person));
		naechste 			= (Person*) derzeitige->next;
			strcpy(naechste->nachname,n_name);
			strcpy(naechste->vorname,v_name);
			strcpy(naechste->wohnort,w_ort);
			naechste->telefonnummer = t_nummer;
			naechste->next 			= NULL;
}


Bekomme ich jetzt folgende Fehlermeldung:

code:
1:
2:
3:
4:
5:
Telefonbuch.c: In Funktion »Hinzufuegen«:
Telefonbuch.c:30:4: Warnung: Unverträgliche implizite Deklaration der eingebauten Funktion »strcpy«
    strcpy(naechste->nachname,*n_name);
    ^
 
Auf diesen Beitrag antworten »
eulerscheZahl

Hast du string.h eingebunden?
Auf diesen Beitrag antworten »
LightSideOfLife

Ja gerade eben :/
Man bin ich doof...

Jetzt hab ich folgendes:

Diese Zeilen:

code:
1:
2:
3:
strcpy(naechste->nachname,n_name);
	  strcpy(naechste->vorname,v_name);
	  strcpy(naechste->wohnort,w_ort);


geben mir diese Fehlermeldung:

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:
Telefonbuch.c: In Funktion »Hinzufuegen«:
Telefonbuch.c:31:30: Warnung: Übergabe des Arguments 2 von »strcpy« von inkompatiblem Zeigertyp
    strcpy(naechste->nachname,n_name);
                              ^
In file included from /usr/include/stdio.h:29:0,
                 from Telefonbuch.c:1:
/usr/include/string.h:30:8: Anmerkung: »const char *« erwartet, aber Argument hat Typ »char **«
 char  *_EXFUN(strcpy,(char *__restrict, const char *__restrict));
        ^
Telefonbuch.c:32:29: Warnung: Übergabe des Arguments 2 von »strcpy« von inkompatiblem Zeigertyp
    strcpy(naechste->vorname,v_name);
                             ^
In file included from /usr/include/stdio.h:29:0,
                 from Telefonbuch.c:1:
/usr/include/string.h:30:8: Anmerkung: »const char *« erwartet, aber Argument hat Typ »char **«
 char  *_EXFUN(strcpy,(char *__restrict, const char *__restrict));
        ^
Telefonbuch.c:33:29: Warnung: Übergabe des Arguments 2 von »strcpy« von inkompatiblem Zeigertyp
    strcpy(naechste->wohnort,w_ort);
                             ^
In file included from /usr/include/stdio.h:29:0,
                 from Telefonbuch.c:1:
/usr/include/string.h:30:8: Anmerkung: »const char *« erwartet, aber Argument hat Typ »char **«
 char  *_EXFUN(strcpy,(char *__restrict, const char *__restrict));
        ^


und wenn ich es darin ändere:

code:
1:
2:
3:
	strcpy(naechste->nachname,*n_name);
	        strcpy(naechste->vorname,*v_name);
		strcpy(naechste->wohnort,*w_ort);


kriege ich einen Segmentation fault unglücklich
Auf diesen Beitrag antworten »
eulerscheZahl

Du musst den Datentypen in der struct auch anpassen:
code:
1:
2:
3:
4:
5:
6:
7:
8:
typedef struct
{
    char nachname[20];
    char vorname[20];
    char wohnort[20];
    long int telefonnummer;
	struct Person *next;
} Person;

Das zieht Änderungen für die main nach sich.
Auf diesen Beitrag antworten »
LightSideOfLife

Also Änderungen an meiner Zuweisung der ersten Person?
Auf diesen Beitrag antworten »
eulerscheZahl

richtig.
Solltest du aber auch merken, wenn du es kompilieren willst.
Auf diesen Beitrag antworten »
LightSideOfLife

Ich bin den Segmentation Fault jetzt losgeworden und die Eingabe durchläuft er jetzt so ohne sich zu beschweren.
Jedoch komme ich nicht in die AusgabeFunktion.
Außerdem hat es nichts gebracht malloc in der main Funktion für mein erstes Element aufzurufen sondern ich musste es in der Hinzufuegen Funktion machen. Woran liegt das?

Hier mein jetziger Code:

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:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
    char nachname[15];
    char vorname[15];
    char wohnort[15];
    char telefonnummer[15];
	struct Person *next;
}Person;

void Hinzufuegen();

void Ausgabe();

main()
{
    Person *erste, *derzeitige;
	
	erste = NULL;
	
	Hinzufuegen(erste, derzeitige);
	Hinzufuegen(erste, derzeitige);
	Ausgabe(erste);
}

void Hinzufuegen(Person *erste, Person *derzeitige)
{
	if (erste == NULL){
				
				erste = (Person *) malloc(sizeof(Person));
				printf("\nGeben Sie den Nachnamen ein\n");		gets(erste->nachname);	
				printf("\nGeben Sie den Vornamen ein\n"); 		gets(erste->vorname);
				printf("\nGeben Sie den Wohnort ein\n"); 		gets(erste->wohnort);	
				printf("\nGeben Sie die Telefonnummer ein\n"); 	gets(erste->telefonnummer);
				erste->next 			= NULL;
				derzeitige = erste;
	}
	else{
		Person *naechste;
			if (derzeitige == NULL) return;
			if (derzeitige->next != NULL) return;
			
				derzeitige->next	= malloc(sizeof(Person));
				naechste 			= (Person*) derzeitige->next;

				printf("\nGeben Sie den Nachnamen ein\n");		gets(naechste->nachname);	
				printf("\nGeben Sie den Vornamen ein\n"); 		gets(naechste->vorname);
				printf("\nGeben Sie den Wohnort ein\n"); 		gets(naechste->wohnort);	
				printf("\nGeben Sie die Telefonnummer ein\n"); 	gets(naechste->telefonnummer);
	
				naechste->next 			= NULL;
	}
}

void Ausgabe(Person *erste)
{
	int i = 1;
	Person *derzeitige = erste;
		while (derzeitige != NULL)
		{
			printf("%d. Person: %s, %s, %s, %ld \n",i, derzeitige->nachname, derzeitige->vorname, derzeitige->wohnort, derzeitige->telefonnummer);
			derzeitige = (Person*) derzeitige->next;
			i++;
		}
}


Es kommt mir so vor als wenn sich mein Programm über die Funktionsgrenzen hinaus nichts merkt...
Aber erste und derzeitige müssten doch global sein oder nicht?
Auf diesen Beitrag antworten »
eulerscheZahl

Mit Person* kannst du nur den Inhalt der Person ändern, ihr z.B. einen anderen Namen geben oder auch einen Nachfolger zuweisen. Aber es ist nicht möglich den Zeiger so zu ändern, dass die Person selbst eine andere wird. Wenn Person* vorher NULL war, musst du die Adresse von Person* ändern. Sonst kriegt die main davon nichts mit. Daher der Doppelzeiger.
Bei der Ausgabe reicht ein Zeiger - und den kann man sogar überschreiben.

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:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
	char nachname[15];
	char vorname[15];
	char wohnort[15];
	char telefonnummer[15];
	struct Person *next;
}Person;

void Hinzufuegen(Person**);
void Ausgabe(Person*);

int main()
{
	Person *erste;
	Hinzufuegen(&erste);
	Hinzufuegen(&erste);
	Ausgabe(erste);
	return 0;
}

void Hinzufuegen(Person **erste) //Doppelzeiger, weil wir nicht nur den Inhalt, sondern auch die Adresse ändern müssen
{
	Person* naechste;
	if (*erste == NULL) {
		*erste = (Person*) malloc(sizeof(Person));
		naechste = *erste;
		while (naechste->next != NULL) 
			naechste = (Person*) naechste->next;
	}
	else {
		naechste = *erste;
		while (naechste->next != NULL) 
			naechste = (Person*) naechste->next;
		Person* tmp = (Person*) malloc(sizeof(Person));
		naechste->next = (Person*) tmp;
		naechste = (Person*) naechste->next;
	}
	printf("Geben Sie den Nachnamen ein: ");		scanf("%s", naechste->nachname);
	printf("Geben Sie den Vornamen ein: "); 		scanf("%s", naechste->vorname);
	printf("Geben Sie den Wohnort ein: "); 		scanf("%s", naechste->wohnort);
	printf("Geben Sie die Telefonnummer ein: "); 	scanf("%s", naechste->telefonnummer);
}

void Ausgabe(Person *erste)
{
	int i = 1;
	while (erste != NULL)
	{
		printf("%d. Person: %s, %s, %s, %s \n",i, erste->nachname, erste->vorname, erste->wohnort, erste->telefonnummer);
		erste = (Person*) erste->next;
		i++;
	}
}
Auf diesen Beitrag antworten »
LightSideOfLife

Ok das mit dem Doppelzeiger ist jetzt etwas kompliziert für mich da muss ich mich mal genauer reinlesen und reindenken.
Außerdem beschwert sich noch mein Compiler oO

code:
1:
2:
3:
4:
5:
6:
7:
	else{
			naechste = *erste;
			while (naechste->next != NULL)
				naechste = (Person*) naechste->next;
			Person *tmp = (Person*) malloc(sizeof(Person));
			naechste->next = (Person*) tmp;
			naechste = (Person*) naechste->next;


code:
1:
2:
3:
4:
Telefonbuch.c:39:19: Warnung: Zuweisung von inkompatiblem Zeigertyp
    naechste->next = (Person*) tmp;
                   ^
Auf diesen Beitrag antworten »
LightSideOfLife

Hier auch mal mein Versuch das Löschen eines Eintrags zu realisieren:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
void Loeschen(Person *erste)
{
	Person *derzeitige = erste;
	char gesucht;
		printf("Wessen Eintrag soll gelöscht werden? (Nachname)"); scanf("%s",gesucht);
			while (derzeitige != NULL)
			{
				if (derzeitige->next->nachname == gesucht)
				{
					Person *tmp1 = derzeitige->next->next;
					free(derzeitige->next);
					derzeitige->next = tmp1;
				}
			}
		
}


Hier sagt mir der Compiler immer:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
Telefonbuch.c: In Funktion »NummerSuchen«:
Telefonbuch.c:75:30: Warnung: Vergleich zwischen Zeiger und Ganzzahl
     if (derzeitige->nachname == gesucht)
                              ^
Telefonbuch.c: In Funktion »Loeschen«:
Telefonbuch.c:88:25: Fehler: Dereferenzierung eines Zeigers auf unvollständigen Typen
     if (derzeitige->next->nachname == gesucht)
                         ^
Telefonbuch.c:90:37: Fehler: Dereferenzierung eines Zeigers auf unvollständigen Typen
      Person *tmp1 = derzeitige->next->next;
                                     ^
Telefonbuch.c:92:23: Warnung: Zuweisung von inkompatiblem Zeigertyp
      derzeitige->next = tmp1;
                       ^


Ihm scheinen also diese doppelten Pfeile nicht zu schmecken.
Außerdem wieder das "Zuweisung von inkomtabliblem Zeigertyp" Problem.
Man... Ich hab echt Verständnisprobleme bei Zeigern...
Auf diesen Beitrag antworten »
eulerscheZahl

Der Stringvergleich klappt so nicht, zumindest nicht in C. strcmp heißt die Funktion, nach der du und gleich auch google suchen.
Und beim Löschen kann es passieren, dass der erste Eintrag entfernt werden soll. Bei deinem aktuellen Entwurf will die aufrufende Funktion dann immer noch auf die mittlerweile gelöschte Person zugreifen. Du brauchst auch hier Person**.
 
Neue Frage »
Antworten »


Verwandte Themen

Die Beliebtesten »
Die Größten »
Die Neuesten »