erste verkettete liste



  • struct sEmpList *swap(struct sEmpList *A){
    
    	struct sEmpList *X;
    
    	X=A;
    	A=A->next;
    	X->next=A->next;
    	A->next=X;
    
    	return(A);
    
    }
    

    nach 12938skizzen kommt nie das getauschte raus sondern immer nur 4 elemente wo dann das zweite dann fehlt.

    meine skizze sieht wie folgt aus:

    X=A;
    
    X,A->[1|n]->[2|n]->[3|n]->...
    
    A=A->next;
    
    X->[1|A]->[2|n]->[3|n]->...
    
    X-next=A->next;
      A->next=X;
    
    A->[2|X]->[1|n]->[3|n]->...
    

    sieht jemand meinen fehler? 😕



  • Wertest du den Rückgabewert der Funktion auch aus?
    Steht da ein

    [b]A = [/b]swap(A);
    

    Sonst zeigt das A aus main natürlich weiterhin auf 1.



  • oh gott -.- das es daran scheitert, dann hab ich jetzt die ganze zeit zeiger geschoben und das war garnicht der fehler..



  • Du solltest beim zeichnen auf Papier auch nur die Verlinkungen umzeichnen und nicht die Objekte selber.

    Das folgende stimmt z.B. nicht, da A ja zusätzlich auf das 2. Objekt zeigt

    X->[1|A]->[2|n]->[3|n]->... falsch
    
    X->[1|n]->[2|n]->[3|n]->...
            A-^   so ist besser, 1 und A zeigen auf 2
    

    Am Ende sollte dann

    +----------+
                |          |
      +-->[1|n]-+  [2|n]+  +->[3|n]->...
      | X-^      A-^    |  
      +-----------------+
    

    rauskommen.

    Und da könnetst du dann sehen, warum 2 nicht mehr ausgegeben wird, weil die Information verloren gegeangen ist, wo es liegt.
    Wenn du dann noch unterschiedliche Variablennamen in main und swap hast, ist es sogar klar ersichtlich.



  • Vielen vielen dank leute! ich glaub jetzt hab ichs gerafft

    #include <stdio.h>
    #include <stdlib.h>
    
    struct sEmpList {
    	int PersNr;
    	char *Name;
    	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;
    	F->Name=Name;
    
    	F->next=E;
    	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(){ 
    
        struct sEmpList *A;
    	A= (struct sEmpList*) malloc (sizeof(struct sEmpList));
    	A->PersNr=1;
    	A->Name="Peter";
    
        A = NewEmployee(A,2,"Hans"); // auf erstes Element achten! ggf. NULL anstatt A
    	A = NewEmployee(A,3,"Wurst"); 
        A = NewEmployee(A,4,"Detlef"); 
        A = NewEmployee(A,5,"Dieter"); 
    	A = swap(A);
    
        printList(A); 
    
    	while (A != NULL) {
    		A=A->next;
    		free(A);
    	}
    
    }
    

    so läuft das programm richtig und gibt auch das aus was gefragt war.
    bin grad am üben für eine prüfung und werd mich noch an weiteren funktionen für verkettete listen erproben, das muss alles sitzen bis nächste woche montag! 🙂



  • Mit deinem Namen wirst du so auf dauer nicht glücklich.

    Gib die Namen doch mal per Hand ein:

    char Namen[30];
    int i = 10;
    
    // statt Zeile 56:
      while(1) {
        scanf("%29[^\n]", Namen);
        if (strlen(Namen) <2)
          break;
        A = NewEmployee(A,i++,Namen); 
      }
    


  • was stimmt denn mit dem namen nicht?



  • Hast du es mal probiert? Und mehr als einen Namen eingegeben?

    Du benutzt Stringliterale. Die sind konstat und können nicht verändert werden.
    Mein Beispiel verwendet ein Array.



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



  • wintik schrieb:

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

    lol



  • sehr hilfreicher kommentar



  • Da hier offensichtlich noch ein grosses Defizit in Stringsverarbeitung
    vorliegt hier mal ein "Lückentext" der möglicherweise weiterhilft.

    struct sEmpList *NewEmployee(struct sEmpList *E, int PersNr,char *Name){
    
    	struct sEmpList *F;
    
    	F= (struct sEmpList*) malloc (sizeof(struct sEmpList));
    	if(F == NULL) return NULL;
    
    	F->Name = (char *) malloc(...);
    	if(F->Name == NULL) return NULL;  
    
    	F->PersNr=PersNr;
    	strcpy(F->Name, ...);
    
    	/* wenn Vorgänger, dann anhängen */         
    	if(E != NULL) {
    	  while(E->next) E = E->next;
    	  E->next=F;
    	  }
    
    	return(F);	
    }
    

    Ich würde zudem die neuen Elemente hinten an die Liste anhängen. Dann kann man
    den Returnwert prüfen, ohne den Rest der Liste zu verlieren. Bei malloc sollte
    man damit rechnen, das es mal nicht klappt ...

    Das Hauptprogramm könnte dann auf Fehler reagieren:

    struct sEmpList *head=NULL, *neu;
    
      neu = NewEmployee(head,i++,Namen); 
    
      if(neu == NULL)
        { printf("Fehler ... ->exit ?}
    
      if(head == NULL)
         head = neu;
    


  • 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


Anmelden zum Antworten