erste verkettete liste



  • wintik schrieb:

    char Namen[20];
    ...
            scanf(" %29[^\n]", Namen);     // Namen einlesen (maximal 29 Zeichen bis zu einem '\n'
    

    Es ist blöd, 29 Zeichen eingeben zu können, wenn nur Platz für 19 Zeichen vorhanden ist.

    Bei deinem swap und delete gibt es noch das Problem, dass du nur Zugriff auf nachfolgende Elemente hast.

    Du kannst eigentlich nur das nächste und übernächste Element tauschen, bzw. das nächste Element löschen.

    Du willst 2 und 3 vertauschen:

    [1|n]->[2|n]->[3|n]->...
            A-^  Die Funktion weiss von A...
    

    ... kann aber den next-Zeiger von 1 nicht auf 3 umbiegen.

    Am besten, du gibst deinen Funktionen noch den Listeanfang als zusätzlichen Parameter mit.



  • -Nope, es stürzt nicht ab ^^

    if (E != NULL) {
    		F->next=E;
    	}
        else F->next=NULL;E=NULL; //also so bin ich mir ganz sicher aber ich rate mal das es nicht so eine saubere lösung ist? 
        return(F);
    

    -also malloc hab ich aus der uni

    -aber wird der speicher des zeigers dann nicht einfach wieder frei gegeben?

    - A ist doch der Listenanfang? Deswegen benutz ich ja X als kopie von A, damit mittels X die zeiger gebogen werden können und trd A als anfang erhalten bleibt und zurück gegeben werden kann

    struct sEmpList *del(struct sEmpList *A, int n){
    
    	int i=1;
    	struct sEmpList *tmp, *X;
    	X=A;
    
    	while (i<n) {
    		X=X->next;
    		i++;
    	}
    	if(n=1){X=X->next;return X;}
    	else{tmp=X;
    		 X=X->next;
    		 free(tmp);
    		 return A;}
    }
    

    jetzt wird zwar das erste auch ohne fehler gelöscht doch geb ich jetzt ein das das 3.element gelöscht werden soll wird wieder alles bis zum 4.element gelöscht.
    hab ja extra X erstellt damit A erhalten bleibt womit ich dann halt den anfang der liste hab, x verbigt dann an gewünschter stelle ein weiter, was stimmt da an meiner logik nicht? das problem wird ja portiebar auf die andere funktion sein



  • Der Vergleichsoperator ist == und nicht =
    ⚠ Beachte unbedingt die Warnungen von deinem Compiler und behandle sie wie Fehler.

    Wenn du ein Element löschen willst, musst du vom Vorgänger auf den Nachfolger umbiegen.

    tmp=X->next;  // tmp ist das zu löschende Element
             X->next=X->next->next; // X->next zeigt auf das übernächste Element
             free(tmp);
    

    Wie das dann mit deiner Zählung hinhaut, musst du selber schauen



  • wintik schrieb:

    -Nope, es stürzt nicht ab ^^

    Das wundert mich aber! 😮

    wintik schrieb:

    if (E != NULL) {
    		F->next=E;
    	}
        else F->next=NULL;E=NULL; //also so bin ich mir ganz sicher aber ich rate mal das es nicht so eine saubere lösung ist?
    

    Ne, so meinte ich das nicht. Das E=NULL hat an der Stelle Null Effekt und das Meiste ist komplett überflüssig.
    Worauf ich hinaus will ist, dass du in der main Funktion deine Liste initialisieren solltest:

    struct sEmpList* A = NULL; // Saubere Initialisierung, NULL-Terminierung der Liste gewährleisten.
    

    Nachdem du den Rückgabewert von malloc geprüft hast genügt dann ein einfaches

    F->next=E;
    

    wintik schrieb:

    -also malloc hab ich aus der uni

    Man castet den Rückgabewert von malloc nicht, siehe Link.

    wintik schrieb:

    -aber wird der speicher des zeigers dann nicht einfach wieder frei gegeben?

    Dafür sorgt man mit der Funktion free.
    Aber nicht so:

    wintik schrieb:

    while (A != NULL) {
            A=A->next;
            free(A);
        }
    

    So gibst du maximal den Speicher eines Elements frei, nämlich das des zweiten, wenn die Anzahl der Listenelemente >= 2 ist, der Rest der Liste verbleibt im
    Speicher als Speicherleck(memory leak).



  • CJosef schrieb:

    Man castet den Rückgabewert von malloc nicht, siehe Link.

    Wenn man will, dass der Code auch gültiges C++ ist, was ich mal als potentiell durchaus erstrebenswert sehen würde, dann schon... 😉



  • dot schrieb:

    CJosef schrieb:

    Man castet den Rückgabewert von malloc nicht, siehe Link.

    Wenn man will, dass der Code auch gültiges C++ ist, was ich mal als potentiell durchaus erstrebenswert sehen würde, dann schon... 😉

    In dieser Ecke des Forums aber nicht 😃



  • Wie soll ich denn dann ohne den cast vom malloc speicher für das neue element allokieren?

    den listen anfang hab ich in die main geschrieben, spart mir die abfragen und ist wohl auch die beste lösung ^^

    zum wieder freigeben, wie komm ich denn am einfachsten an alle werte? von hinten die liste durchgehen stell ich mir grad zu aufwendig vor aber was anderes fällt mir nicht zu ein 😕



  • wintik schrieb:

    Wie soll ich denn dann ohne den cast vom malloc speicher für das neue element allokieren?

    Cast weglassen, ganz einfach.

    wintik schrieb:

    den listen anfang hab ich in die main geschrieben, spart mir die abfragen und ist wohl auch die beste lösung ^^

    Ja, der Listenanfang ist in diesem Fall in main gut aufgehoben, aber du hast ihn nicht vernünftig initialisiert.

    wintik schrieb:

    zum wieder freigeben, wie komm ich denn am einfachsten an alle werte? von hinten die liste durchgehen stell ich mir grad zu aufwendig vor aber was anderes fällt mir nicht zu ein 😕

    Mit nem Hilfszeiger.



  • wintik schrieb:

    Wie soll ich denn dann ohne den cast vom malloc speicher für das neue element allokieren?

    malloc gibt einen Zeiger auf void zurück.
    Und die sind in alle anderen Datenzeiger konvertierbar.

    wintik schrieb:

    zum wieder freigeben, wie komm ich denn am einfachsten an alle werte?

    Im Prinzip so wie du in auch angefordert hast (evtl in einer anderen Reihenfolge).

    wintik schrieb:

    von hinten die liste durchgehen stell ich mir grad zu aufwendig vor aber was anderes fällt mir nicht zu ein 😕

    Dann ist C wohl nichts für dich.



  • CJosef schrieb:

    wintik schrieb:

    Wie soll ich denn dann ohne den cast vom malloc speicher für das neue element allokieren?

    Cast weglassen, ganz einfach.

    du meinst (char *), wieso ist das denn dann in mehreren quellen so geschrieben? also abgesehen von den gründen die in dem link standen, wenn es überflüssig ist hier ists ja auch quatsch außer man brauchs für C++ oder so

    CJosef schrieb:

    wintik schrieb:

    den listen anfang hab ich in die main geschrieben, spart mir die abfragen und ist wohl auch die beste lösung ^^

    Ja, der Listenanfang ist in diesem Fall in main gut aufgehoben, aber du hast ihn nicht vernünftig initialisiert.

    int main(){ 
        int i=1;
    	char Namen[20];
    
        struct sEmpList* A = NULL; 
    .
    .
    .
    }
    

    ich hab den doch garnicht nochmal hier gepostet?
    was meinst du mit in diesem fall? also wenn ich eine neue liste erstelle und noch keine elemente vorhanden sind ist dies der richtige weg oder gibt es noch weitere ausnahmen?

    CJosef schrieb:

    wintik schrieb:

    zum wieder freigeben, wie komm ich denn am einfachsten an alle werte? von hinten die liste durchgehen stell ich mir grad zu aufwendig vor aber was anderes fällt mir nicht zu ein 😕

    Mit nem Hilfszeiger.

    also wenn ich mir einen hilfszeiger nehme und diesen gleich A setze und dann weiter schiebe hab ich doch wieder das gleiche problem das nach einem free(hilfszeiger) dieser wieder weg ist?

    DirkB schrieb:

    wintik schrieb:

    von hinten die liste durchgehen stell ich mir grad zu aufwendig vor aber was anderes fällt mir nicht zu ein 😕

    Dann ist C wohl nichts für dich.

    das C mir nicht gerade liegt ist mir auch schon aufgefallen, etwas damit klarkommen muss ich trotzdem, deswegen versuch ich soviel es geht zu verstehen und zu lernen 😉



  • wintik schrieb:

    du meinst (char *), wieso ist das denn dann in mehreren quellen so geschrieben?

    Das weiß ich nicht. Vllt. benutzen manche Autoren einen C++ Compiler.
    Ein C++ Compiler kompiliert das nicht ohne den Cast.

    wintik schrieb:

    ich hab den doch garnicht nochmal hier gepostet?

    Oh ... okay!

    wintik schrieb:

    was meinst du mit in diesem fall? also wenn ich eine neue liste erstelle und noch keine elemente vorhanden sind ist dies der richtige weg oder gibt es noch weitere ausnahmen?

    Man hält sich üblicherweise seine Objekte so lange am Leben wie nötig.
    Brauchst man ne Liste irgendwo temporär in einem Programm, dann lagert man die ganze Chose in Funktionen aus und hällt nicht unbedingt alle Objekte während der kompletten Laufzeit des Programms in der main-Funktion.

    wintik schrieb:

    also wenn ich mir einen hilfszeiger nehme und diesen gleich A setze und dann weiter schiebe hab ich doch wieder das gleiche problem das nach einem free(hilfszeiger) dieser wieder weg ist?

    Standard Vorgehen ist vom Ansatz her: next-Zeiger per Hilfszeiger speichern, Vorgänger löschen ... so hangelst du dich durch bis zum Listenende NULL.

    wintik schrieb:

    das C mir nicht gerade liegt ist mir auch schon aufgefallen, etwas damit klarkommen muss ich trotzdem, deswegen versuch ich soviel es geht zu verstehen und zu lernen 😉

    Das am Anfang nicht gleich alles klappt ist normal, gerade bei C. 😃
    Also, nicht entmutigen lassen.



  • dot schrieb:

    CJosef schrieb:

    Man castet den Rückgabewert von malloc nicht, siehe Link.

    Wenn man will, dass der Code auch gültiges C++ ist, was ich mal als potentiell durchaus erstrebenswert sehen würde, dann schon... 😉

    Die Betonung liegt auf wenn.
    😃



  • CJosef schrieb:

    wintik schrieb:

    also wenn ich mir einen hilfszeiger nehme und diesen gleich A setze und dann weiter schiebe hab ich doch wieder das gleiche problem das nach einem free(hilfszeiger) dieser wieder weg ist?

    Standard Vorgehen ist vom Ansatz her: next-Zeiger per Hilfszeiger speichern, Vorgänger löschen ... so hangelst du dich durch bis zum Listenende NULL.

    ah klar, jetzt wo du es geschrieben hast, hätte mir eigentlich auch einfallen können sollen 🙄

    CJosef schrieb:

    wintik schrieb:

    das C mir nicht gerade liegt ist mir auch schon aufgefallen, etwas damit klarkommen muss ich trotzdem, deswegen versuch ich soviel es geht zu verstehen und zu lernen 😉

    Das am Anfang nicht gleich alles klappt ist normal, gerade bei C. 😃
    Also, nicht entmutigen lassen.

    danke danke, besonders für die ermutigung 😃



  • do { 
            A->next=B; 
            free(A); 
    		A=B;
        }while (B != NULL);
    

    löschen diese zeilen richtig oder sieht es für mich nur so aus? (also hab noch printList zur kontrolle dahinter,
    das hat aber vorher mit der alten while-schleife auch schon nichts mehr angezeigt)



  • Das sieht vermutlich für dich nur so aus. Wie soll denn B jemals NULL werden?
    Wenn du das anfangs noch nicht überblickst dann mals dir auf, das ist keine Schande und sehr lehr/hilfreich. Mit rumraten kommste nicht allzu weit...



  • sagen wir mal die liste hat 3 elemente

    A->[1|n]->[2|n]->[3|n]->NULL
    

    1.B=A->next;

    A->[1|n]B->[2|n]->[3|n]->NULL
    

    2.free(A);

    [ | ]B->[2|n]->[3|n]->NULL
    

    3.A=B;

    [ | ]B,A->[2|n]->[3|n]->NULL
    

    damit wär man wieder beim ausgangszustand, nur das halt das erste element befreit ist.

    dann müsste im 3ten durchlauf es so aussehen

    1.   B,A->[3|n]->NULL
    2.     A->[3|n]B->NULL
    3.        [ | ]B->NULL
    

    ist dann nicht B=NULL? wer sieht den fehler in meiner logik? ^^


  • Mod

    Bei Zuweisungen steht das Objekt, das verändert werden soll, auf der linken Seite.



  • ach mist, natürlich

    do { 
            B=A->next; 
            free(A); 
    		A=B;
        }while (B != NULL);
    


  • wintik schrieb:

    sagen wir mal die liste hat 3 elemente

    A->[1|n]->[2|n]->[3|n]->NULL
    

    1.B=A->next;

    A->[1|n]B->[2|n]->[3|n]->NULL
    

    2.free(A);

    [ | ]B->[2|n]->[3|n]->NULL
    

    3.A=B;

    [ | ]B,A->[2|n]->[3|n]->NULL
    

    damit wär man wieder beim ausgangszustand, nur das halt das erste element befreit ist.

    dann müsste im 3ten durchlauf es so aussehen

    1.   B,A->[3|n]->NULL
    2.     A->[3|n]B->NULL
    3.        [ | ]B->NULL
    

    ist dann nicht B=NULL? wer sieht den fehler in meiner logik? ^^

    Das sieht gut aus, hättest du das mal auch so umgesetzt 😃

    wintik schrieb:

    do {
            B=A->next;
            free(A);
            A=B;
        }while (B != NULL);
    

    Das ist noch nicht so prall, das kann noch crashen, wenn A NULL ist!



  • if(A != NULL){
        do { 
            B=A->next; 
            free(A); 
    		A=B;
        }while (B != NULL);
    }
    

    so nicht mehr oder? 🙂


Anmelden zum Antworten