erste verkettete liste



  • wintik schrieb:

    ich habs probiert und das programm will aus der whileschleife nicht mehr raus..

    Ich habe extra keine Anleitung dazugegeben, denn ich bin davon ausgegangen, dass du zumindest die Grundlagen kennst, bevor du verkettete Listen machst.

    while(1) {                  // Endlosschleife
        scanf(" %29[^\n]", Namen);     // Namen einlesen (maximal 29 Zeichen bis zu einem '\n'
        if (strlen(Namen) <2)          // Wen der Name weniger als 2 Zeichen hat (1 oder 1) ...
          break;                       // ... dann beende die while-Schleife
        A = NewEmployee(A,i++,Namen);  // Namen in Liste eintragen
      }
    

    Gib zum beenden einfach 1 Zeichen ein und drücke Return.



  • hab die whileschleife wieder eingebaut, abbrechen funktioniert jedoch übernimmt er nicht die namen sondern das einzelene zeichen welches zuletzt eingegeben wurde?



  • wintik schrieb:

    hab die whileschleife wieder eingebaut, abbrechen funktioniert jedoch übernimmt er nicht die namen sondern das einzelene zeichen welches zuletzt eingegeben wurde?

    Wer ist er? 😕
    😃
    In deiner Funktion NewEmployee werden den Zeigern auf die Namen stets ein und derselbe Speicherplatz zugewiesen(wenn du die while Schleife zur Eingabe benutzst).
    Gibst du also z.B. 3 Namen ein, so erzeugst du 3 Listenelemente deren Member *char Name- Zeiger alle auf das Array char Namen[30] zeigen.
    Wenn du also willst, das "er" es übernimmt, musst du den Namen irgendwie eigenen Speicher spendieren.
    Die einfachste Variante ist, du machst aus dem Zeiger ein Array

    struct sEmpList {
        int PersNr;
        char Name[64]; // Array anstelle eines Zeigers
        struct sEmpList *next;
    };
    

    und kopierst die eingegebenen Namen ins Array, oder aber du arbeitest mit malloc oder calloc wie hier schon ansatzweise gezeigt wurde.



  • badaboom! es läuft, danke danke danke!
    er ist der compiler/das Programm/die Console! 😃

    #include <stdio.h> 
    #include <stdlib.h> 
    #include <string.h>
    
    struct sEmpList { 
        int PersNr; 
        char Name[20]; 
        struct sEmpList *next; 
    }; 
    
    struct sEmpList *NewEmployee(struct sEmpList *E, int PersNr,char *Name){ 
    
        struct sEmpList *F; 
    
        F= (struct sEmpList*) malloc (sizeof(struct sEmpList)); 
        F->PersNr=PersNr; 
    
    	strcpy(F->Name,Name); //wenn Arry schon fest bestimmt (bei *name F->Name=Name)
    
    	if (E != NULL) {
    		F->next=E;
    	}
        else F->next=NULL; 
        return(F);    
    } 
    
    struct sEmpList *swap(struct sEmpList *A){ 
    
        struct sEmpList *X; 
    
        X=A; 
        A=A->next; 
        X->next=A->next; 
        A->next=X; 
    
        return(A); 
    
    } 
    
    void printList(struct sEmpList *list) { 
        while(list != NULL) { 
            printf("Personalnummer: %i | ", list->PersNr); 
            printf("Name: %s\n", list->Name); 
            list = list->next; 
        } 
    } 
    
    int main(){ 
        int i=1;
    	char Namen[20];
    
        struct sEmpList *A; 
    
    	while(1) {                  // Endlosschleife 
    		scanf(" %29[^\n]", Namen);     // Namen einlesen (maximal 29 Zeichen bis zu einem '\n' 
    		if (strlen(Namen) <2)          // Wen der Name weniger als 2 Zeichen hat (1 oder 1) ... 
    			break;                       // ... dann beende die while-Schleife 
    		A = NewEmployee(A,i++,Namen);  // Namen in Liste eintragen 
    	}
    
        //A = swap(A); 
    
        printList(A); 
    
        while (A != NULL) { 
            A=A->next; 
            free(A); 
        } 
    
    }
    

    ich hatte jetzt schon ne delet funktion geschrieben die hat auch funktioniert, nun wollt ich diese sowie die swap funktion so umschreiben das ich angeben kann welches element gelöscht bzw getauscht werden soll (bei swap einfach nur stelle angeben und mit dem nächsten wird dann getauscht).
    zunächst hab ich einen neuen zeiger erstellt damit ich den anfang der liste nicht verlier, dann mit dem neuen den zeiger umgebogen, ausgegeben krieg ich nur die elemente die vor dem aufruf der deletfunktion sind

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


  • Das guck dir lieber noch einmal an ...

    wintik schrieb:

    if (E != NULL) {
            F->next=E;
        }
        else F->next=NULL;
        return(F);
    

    ... und überleg dir was du tun musst, damit auch wirklich E=NULL in NewEmployee reinkommt ...
    ... dein Eingabe Array ist von einer Sprengung bedroht ... 😃 ... warum castest du malloc, das ist pfui, in C ist das verpönt...
    http://www.c-plusplus.net/forum/206606
    ... deine schleife für die Spreicherfreigabe .. hüüüstel ... da gucke nochmal hin (ein Zeiger wird nicht NULL, wenn man ihn an free übergibt) ... stürzt dein Programm denn nicht ab? 😃



  • 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...


Anmelden zum Antworten