Zeiger "kopf" bei Listen



  • Hallo, als erstes hier mal ein kleiner Ausschnitt aus meinem Listenverarbeitungsprogramm (Elemente einfügen hinten)

    typedef struct ELEMENT
    {
         ELEMENT *n; //Zeiger auf das nächste Element
         int inhalt;
    }Element;
    
    void main()
    {
        Element *kopf;
        Element *p;
        Element *ende;
    
    .......
    .......
    .......
    
    if(kopf==NULL) //Wenn Liste leer
    {
         kopf=p;
         ende=p;
         p->n=NULL;
    }
    
    ......
    ......
    ......
    

    Wenn ich kopf->n = p schreibe, bekomme ich eine Fehlermeldung (Programmabsturz).

    Aber wieso kann ich einfach kopf = p schreiben? Das bedeutet ja, dass der Zeiger kopf dort hinzeigen soll, wo p hinzeigt (p zeigt auf das neu generierte Element). Aber wenn ich das übernächste Elemnt z.B. ansprechen möchte, dann muss ich ja auch p->n schreiben...Weil eigentlich ist ja nur die Variable "n" ein Zeiger und nicht die gesamte Variable "kopf"...

    Bitte um eine logische, kurze Erklärung 😉

    Danke!



  • kopf ist ein Zeiger, d.h. ein Verweis auf Daten, d.h. ein Platzhalter für eine Adresse.
    Demzufolge kannst du gefahrlos kopf eine Adresse(bzw. einen anderen Zeiger desselben/kompatiblen Typs) zuweisen.
    kopf->n bedeutet eine Dereferenzierung des Zeigers mit anschließendem Zugriff auf ein Strukturelement. Wenn kopf auf undefinierten Speicher verweist (uninitialisiert ist) oder ==NULL ist, versuchst du, auf diesen undefinierten Speicherbereich (angezeigt durch die Adresse, die der Zeiger gerade beinhaltet) zuzugreifen und wirst vom Laufzeitsystem (meistens) abgewiesen.



  • Danke!

    Ist mir gestern noch selbst aufgefallen, dass ich mich mit kopf->n ja auf ein Element beziehe, und nicht auf den Zeiger selbst 😉

    Ich habe aber jetzt ein Problem mit meinem Programm:

    /*
     * Funktion: Beispiel einer einfach verketteten Liste (einfügen hinten)
     */
    
    #include <stdio.h>
    #include <conio.h>
    #include <stdlib.h>
    
    typedef struct ELEMENT
    { 
    	struct ELEMENT *n; // Zeiger auf das nächste Listenelement
    	int inhalt;
    } Element;
    
    void main()
    { 
    	Element *kopf, *p, *ende, *loesch;
    	int zahl, loesch_nr, i, auswahl, gone;
    
    	i = auswahl = gone = 0;
    	kopf = ende = loesch = NULL;
    
    	printf("%d.Listenelement: " ,++i);
    	scanf("%d", &zahl);
    
    	while(zahl != 0)
    	{ 
    		p = (Element*)malloc(sizeof(Element));
    
    		if (p != NULL) //Wenn die Speicherallokierung erfolgreich war
    		{ 
    			/*p->inhalt = zahl; //Bei einfügen vorne
    			p->n = kopf;
    			kopf = p;
    			*/
    
    			//Einfügen hinten
    
    			p->inhalt=zahl;
    
    			if(kopf==NULL) //Wenn Liste leer
    			{
    				kopf=p;
    				ende=p;
    				p->n=NULL;
    			}
    
    			else //Wenn Liste nicht leer
    			{
    				ende->n=p;
    				p->n=NULL;
    				ende=ende->n;
    			}
    
    			printf("%d.Listenelement: " ,++i);
    			scanf("%d", &zahl);
    		}
    
    		else //Wenn kein Speicherplatz reserviert werden konnte
    		{ 
    			printf("Zu wenig Speicherplatz");
    			break;
    		}
    	}
    
    	printf("\n\nAusgabe der Liste\n\n");
    
    	p = kopf;
    
    	while (p != NULL)
    	{ 
    		printf("%d\n" , p->inhalt);
    		p = p->n;
    	}
    
    	//////////Ein Element löschen//////////
    
    	p = kopf; //p auf das 1. Element setzen
    
    	printf("\nWelches Element soll geloescht werden?");
    
    	printf("\nEingabe: ");
    	scanf("%d", &loesch_nr);
    
    	while(loesch_nr != p->inhalt)
    	{
    		p = p->n;
    
    		gone++; //Anzahl der Weiterschaltungen wird mitgezählt
    	}
    
    	p = kopf;
    
    	for(i=1; i<=gone-1; i++)
    	{
    		p = p->n;	
    
    		loesch = p; 
    	}
    
    	p->n = p->n->n;
    
    	free(loesch);
    
    	//////////Element löschen ENDE//////////
    
    	printf("\n\nAusgabe der Liste (eventuell wurden Elemente gelöscht)\n\n");
    
    	p = kopf;
    
    	while(p != NULL)
    	{ 
    		printf("%d\n" , p->inhalt);
    		p = p->n;
    	}
    
    	getch();
    }
    

    Ich gebe folgende Zahlen: 5,4,3,2,1 und anschließend 0 zum abschließen ein. Dann gebe ich ein, dass ich die zahl 3 löschen möchte. Anschließend wird folgendes ausgegeben (die letzte ausgabe im programm (nach dem löschen)):

    5
    -13494962 (irgeneine Adresse)

    und ich bekomme einen Programmabsturz...

    Die Zeile Nr. 124 wird mir markiert: "This is the next statement to execute when this thread returns from the current function".

    Was ist da los?

    Danke!



  • Da Problem liegt hier:

    loesch = p;
        }
    
        p->n = p->n->n; 
    
        free(loesch);
    

    Das Element vor p, sagen wir o, zeigt auf p.
    Das Element nach p (q) zeigt auf r

    o -> p -> q -> r

    Du lässt jetzt p auf r zeigen und löscht dann p
    o zeigt weiterhin auf p.



  • Vielen Dank!

    Klappt jetzt so:

    statt loesch = p gehört loesch = p->n

    weil die schleife ermittelt das Element VOR dem zu löschendem, p soll darauf zeigen. und das NÄCHSTE soll ja eigentlich gelöscht werden, deswegen p->n 😉



  • Basti 13 schrieb:

    p beschreibt bei mir immer das aktuelle Element (bzw. ist ein Zeiger auf das zuletzt erstellte Element, solange ich ihn nirgends anders hinzeigen lasse...)

    Es geht doch ums löschen.
    Da bei dir aber loesch = p; steht, sind loesch und p identisch.
    Wenn du loesch löschen willst, muss das Element vor loesch auf das Element nach loesch zeigen.
    Entweder du merkst dir das vorhergehende Element oder du zählst nicht so weit.

    Ein Lösung wäre:

    }
        loesch = p->n;
        p->n = p->n->n;
    
        free(loesch);
    

    Das loesch das richtige Element ist, musst du mit deiner Zählschleife sicherstellen.

    Und o und q habe ich genommen, damit die anderen Element einen Namen haben.



  • Da habe ich etwas lange zum abschicken gebraucht 😞
    Denn bis zum Edit stand da noch was ganz anderes 😡


Anmelden zum Antworten