einfach Liste mit struct - Einfügen und Ausgeben von Elementen

neuesich

Mitglied
Code:
#include <stdio.h>
#include <stdlib.h>

typedef struct list_izahl_element  {
        int  izahl;
        struct list_izahl_element *pnext;
    } Liste_izahlen;

void print_list(Liste_izahlen **list){
    int counter=1;
    Liste_izahlen* runner=*list;

    if (!runner)
        printf("Leere Liste!\n");
    else
        while (runner){
            printf("%d. %d\n", counter++, runner->izahl);
            runner=runner->pnext;}
}

void insert(Liste_izahlen **select, int iZahlinput){
    Liste_izahlen *newelement=(Liste_izahlen*) malloc (sizeof(Liste_izahlen));
    newelement->izahl=iZahlinput;
    newelement->pnext=NULL;

    if (*select==NULL)
        *select=newelement;
    else{
        newelement->pnext=(*select)->pnext;
        (*select)->pnext=newelement;}
    free(newelement);
}

 void insert_sort(Liste_izahlen **list, int iZahlinput){
    Liste_izahlen *runner=*list;

    if (runner!=NULL)
       while((iZahlinput>(runner->izahl))&&(runner->pnext!=NULL)&&(iZahlinput>(runner->pnext->izahl)))
           runner=runner->pnext;
    insert(&runner,iZahlinput);
}

int main(void){
int input=0;
Liste_izahlen *xylist=NULL;

while(1){
    printf("Geben Sie eine Ganzzahl ein: ");
    if (scanf("%d", &input)){
        insert_sort(&xylist,input);
        print_list(&xylist);
    }
}
}
Hallo,

Ich stehe momentan total aufm Schlauch und komme nicht voran. Ich habe Probleme beim Erstellen und Einfügen einer Liste. Irgendwie passt die Zuordnung innerhalb der Funktion nicht. Ich bin dankbar für jede Hilfe!
Lg
 
Ich habe das Programm jetzt nicht ganz genau durchgeschaut, aber 2 Sachen einmal vorweg:

1: Du übergibst an die Funktionen immer einen Pointer auf einen Pointer, das ist aber unnötigt, eine Dimension, also nur ein Pointer reicht vollkommen. So machst du deinen Code nur unübersichtlich.

2: Beim 1.Durchlauf ist das if in Zeile 26 war und *select = newelement; wird gemacht. Danach in Zeile 31 schreibst du free (newlement), du gibst also das frei, auf was *select gerade zeigt, das ist keine gute Idee.

Lg
 
Hey danke für die schnelle Antwort!

zu 1. Ich habe mich an diesem Post aus dem Forum orientiert:

Eine Möglichkeit wäre, am Schluss von add den Pointer returnen und im main halt
list=addElement(list...)
zu schreiben

Oder du übergibst die Adresse vom Pointer und schreibst in add immer einen * vor list :)

Oder du nimmst die Referenz vom Pointer
Ich hab mich jetzt für zweiten Methode entschieden, oder ist die unpraktikabel? Der Vorteil ist/war, dass ich auch eine leere Liste übergeben kann und bei Methode 3 muss man ein erstes Element mit Nullwerten vorher initialisieren. Das fand ich auch unpraktikabel.

zu 2. Ja stimmt, damit habe ich mir selbst ins Bein geschossen. Wenn ich die Zeile entferne, dann läuft die printf- und sort-Funktion schonmal wie sie sollte. Jetzt muss nur noch der Fehler in der insert_sort gefunden werden...
 
Hi

Das mit dem Doppelpointer ist nur dann nötig,
wenn die Liste (genauer das erste Element) in der Funktion verändert wird.
Bei zB. print_liste würde auch ein einfacher Pointer reichen.

Methode 3 ist auch ohne Element möglich.
Man braucht nur eine Referenz auf den Pointer, nicht auf einen existierenden Inhalt.
xylist im main reicht,auch wenn es NULL ist.

Vorteil: Etwas weniger Schreibarbeit, und beim Aufruf muss man in keinem Fall ein & verwenden
(egal ob Änderfunktion oder nicht)

Nachteil: Wenn man reines C (ohne C++) programmieren will,
darf man keine Referenzen verwenden. Die gibts in C nämlich nicht.


Zum insert_sort und insert:
insert selbst hat zuerst auch noch ein Problem:
Es fügt immer nach dem aktuellen Element ein.
Für insert_sort müsste es auch davor einfügen können.
Weil sonst kann man bei einer bestehenden Liste nie am Anfang einfügen.


Gruß

PS: Nachträglich Willkommen bei tutorials.de :)
 
Du kannst es auch mit Pointer auf Pointer machen, tut mir leid ich hatte einen kleinen Denkfehler.
Das Problem ist hier, in Zeile 35 in insert_sort() zeigt der Zeiger runner auf das, was in xylist in der main() steht, also auf NULL. runner hat also nur mehr die Adresse NULL gespeichert und von xylist keine Adresse mehr, deshalb kannst du xylist nicht mehr abändern. Du arbeitest nur mehr mit runner weiter und hast keinen Bezugspunkt zu xylist.

Du müsstest runner auch einen Pointer auf einen Pointer machen und da das speichern, auf was list zeigt, also so:

C++:
Liste_izahlen **runner = list;

Jetzt zeigt runner auf das, was list zeigt, also auf die Adresse von xylist vom main(). Ich hoffe ich habe das halbwegs verständlich ausgedrückt.

Lg
 
Das Problem ist hier, in Zeile 35 in insert_sort() zeigt der Zeiger runner auf das, was in xylist in der main() steht, also auf NULL. runner hat also nur mehr die Adresse NULL gespeichert und von xylist keine Adresse mehr, deshalb kannst du xylist nicht mehr abändern. Du arbeitest nur mehr mit runner weiter und hast keinen Bezugspunkt zu xylist.

Du müsstest runner auch einen Pointer auf einen Pointer machen und da das speichern, auf was list zeigt, also so:

C++:
Liste_izahlen **runner = list;

Jetzt zeigt runner auf das, was list zeigt, also auf die Adresse von xylist vom main()
Ok super, das klingt einleuchtend. Ich hab es mal im Code angepasst. Danke!

Das mit dem Doppelpointer ist nur dann nötig,
wenn die Liste (genauer das erste Element) in der Funktion verändert wird.
Bei zB. print_liste würde auch ein einfacher Pointer reichen.
Ja das habe ich mir auch überlegt. Ich habe die print_list nochmal angepasst.

Wenn man reines C (ohne C++) programmieren will,
darf man keine Referenzen verwenden. Die gibts in C nämlich nicht.
Ok dann scheidet Methode 3 sowieso aus, da es C sein soll.

Zum insert_sort und insert:
insert selbst hat zuerst auch noch ein Problem:
Es fügt immer nach dem aktuellen Element ein.
Für insert_sort müsste es auch davor einfügen können.
Weil sonst kann man bei einer bestehenden Liste nie am Anfang einfügen.
Fange ich das nicht ab durch
Code:
 if (!*select)
? Dass die Funktion insert immer hinter ein übergebenes Element der Liste einträgt ist gewollt (und muss leider auch so sein). Ich dachte ich hätte den Sonderfall, dass die Liste leer ist durch die If-Bedingung abgedeckt (in insert_sort sowie auch in insert).

Derzeit sieht es so aus:
Code:
#include <stdio.h>
#include <stdlib.h>

typedef struct list_izahl_element  {
        int  izahl;
        struct list_izahl_element *pnext;
    } Liste_izahlen;

void print_list(Liste_izahlen *list){
    int counter=1;
    Liste_izahlen* runner=list;

    if (!runner)
        printf("Leere Liste!\n");
    else
        while (runner){ 
            printf("%d. %d\n", counter++, runner->izahl);
            runner=runner->pnext;}
}

void insert(Liste_izahlen **select, int iZahlinput){
    Liste_izahlen *newelement=(Liste_izahlen*) malloc (sizeof(Liste_izahlen));
    newelement->izahl=iZahlinput;
    newelement->pnext=NULL;

    if (!*select)
        *select=newelement;
    else{
        newelement->pnext=(*select)->pnext;
        (*select)->pnext=newelement;}
}


 void insert_sort(Liste_izahlen **list, int iZahlinput){
    Liste_izahlen **runner=*list;

    if (*runner)
       while((iZahlinput>((*runner)->izahl))&&((*runner)->pnext!=NULL)&&(iZahlinput>((*runner)->pnext->izahl)))
           *runner=(*runner)->pnext;
    insert(&runner,iZahlinput);
}

int main(void){
int input=0;
Liste_izahlen *xylist=NULL;

while(1){
    printf("Geben Sie eine Ganzzahl ein: ");
    if (scanf("%d", &input)){
        insert_sort(&xylist,input);
        print_list(xylist);
    }
}
}
Danke euch Beiden, ihr habt mir schon mal geholfen etwas Klarheit in diesen Nebel zu bringen^^
 
Zum Abfangen vom NULL-Fall bei Insert:
Jein.
Es stimmt, das du beim Danach-Einfügen
für das Einfügen am Anfang Was Leeres übergeben müsstest.
Aber: Die Funktion denkt dann, dass noch keine Liste vorhanden ist (in dem Fall ist ja auch NULL).
Als Next wird dann NULL eingetragen, auch wenn es schon eine gefüllte Liste gibt/gab.

Wenns nicht im inser sein darf/kann muss man eben ggf. das Next außerhalb selbst setzen,
wenn man was ganz am Anfang haben will.
Zuerst ein Insert auf Leer und dann den Rest dazuhängen.


Zum insert_sort: Geht es nach dem Beitrag von ibafluss oder noch immer nicht?
Zumindest das Anfangs-Problem gibt es dann auch hier.
Und beim Sortiert-sein wäre das wichtig.
 
Du darfst bei der Zuweisung von runner keinen Stern bei list schreiben! Überprüfe jetzt noch einmal ganz genau ob mit den * und & operatoren alles stimmt, denn da ändert sich einiges. Poste dann noch einmal den neuen Code und was noch nicht funktioniert.

Lg
 
So die Lösung kommt näher^^ Echt danke, ich war schon so verzweifelt...

Es funktioniert alles soweit bis auf den erwähnten Fall, dass das einzufügende Element kleiner ist als das erste Element der Liste (Also davor einfügen). Da meine Aufgabenstellung vorgibt, dass insert_sort nur danach einfügen soll, hab ich versucht das in der insert_sort zu umgehen. Leider mit mäßigem Erfolg...

Den Fall, dass beim ersten Aufruf eine Liste mit einem Element erstellt wird, habe ich wie vorgeschlagen mit einem ersten insert in der main umgesetzt.

Hier mein derzeitiger Stand:
Code:
#include <stdio.h>
#include <stdlib.h>

typedef struct list_izahl_element  {
        int  izahl;
        struct list_izahl_element *pnext;
    } Liste_izahlen;


void print_list(Liste_izahlen *list){
    int counter=1;
    Liste_izahlen* runner=list;

    if (!runner) 
        printf("Leere Liste!\n");
    else
        while (runner){ 
            printf("%d. %d\n", counter++, runner->izahl);
            runner=runner->pnext;}
}

void insert(Liste_izahlen **select, int iZahlinput){
    Liste_izahlen *newelement=(Liste_izahlen*) malloc (sizeof(Liste_izahlen));
    newelement->izahl=iZahlinput;
    newelement->pnext=NULL;

    if (!*select)
        *select=newelement;
    else{
        newelement->pnext=(*select)->pnext;
        (*select)->pnext=newelement;}
}

 void insert_sort(Liste_izahlen **list, int iZahlinput){
    Liste_izahlen **runner=list;

    if(((*runner)->izahl>iZahlinput)){
        Liste_izahlen *newelement=(Liste_izahlen*) malloc (sizeof(Liste_izahlen));
        newelement->izahl=iZahlinput;
        newelement->pnext=*runner;
        *runner=newelement;
    }

    else{
        while((iZahlinput>((*runner)->izahl))&&((*runner)->pnext!=NULL)&&(iZahlinput>((*runner)->pnext->izahl)))
            *runner=(*runner)->pnext;
        insert(runner,iZahlinput);}
}

int main(void){
int input=0;
Liste_izahlen *xylist=NULL;

printf("Geben Sie eine Ganzzahl ein: ");
if (scanf("%d", &input)){
        insert(&xylist,input);
        print_list(xylist);}

while(1){
    printf("Geben Sie eine Ganzzahl ein: ");
    if (scanf("%d", &input)){
        insert_sort(&xylist,input);
        print_list(xylist);}
}
}
lg
 
Zuletzt bearbeitet:
Zum ersten main-insert:
Das
C++:
if (!*select)
    *select=newelement;
else
könntest du doch auch am Anfang von insert_sort machen? (Variablennamen anpassen)
Die Nur-danach-einfügen-Regel wird dadurch nicht verletzt.
Dann musst du für das erste Element im main keine Sonderbehandlung machen.

Und wenn insert-sort unbedingt nichts davor einfügen darf,
gleich nach dem oberen ersten if noch eine Abfrage, ob das erste vorhandene Element
größer als das Neue ist.
Wenn nein, weitermachen, sonst:
Ein neues auf Leer anlegen (insert macht das ja gut),
danach den Rest an Next hängen,
return.
 
Zurück