"Christmas - the time to fix the computers of your loved ones" « Lord Wyrm

C-Basics (Linked List)

prayerslayer 20.12.2008 - 11:35 2095 18
Posts

prayerslayer

Oar. Mh.
Avatar
Registered: Sep 2004
Location: vorm Sucher
Posts: 4073
hi there.

ich muss für die uni wieder c programmieren und diese hardwarenähe macht mir echt zu schaffen inzwischen. jedenfalls ist die aufgabenstellung, eine implementierung einer einfach verketteten liste zu schreiben. ich scheitere irgendwie schon an der append-funktion.

Code:
void Append(IntList *l, int n)
{ 
  IntList neu = (IntList)malloc(sizeof(elemtype));
  neu->wert=n;
  neu->next=NULL;
  if (*l==NULL) //liste leer
  {
    printf("NEU\n");
    *l=neu;
  }
  else
  {
    while ((*l)->next!=NULL)
    {
      printf("Eins weiter\n");
      *l=((*l)->next);
    }
    (*l)->next=neu;
  }
}

ich hab immer nur die letzten 2 elemente in der liste und beim einfügen hangelt er sich auch maximal 1x durch. deswegen nehm ich an, dass in zeile 18 beim anhängen der hund begraben liegt. aber ich seh den fehler einfach nicht, vielleicht steh ich auch komplett auf der leitung.

hat wer einen hint? sorry, falls es wirklich zu offensichtlich ist, aber mmn sollte es so gehen.

tia

Souly

Addicted
Avatar
Registered: Mar 2004
Location: Graz
Posts: 480
Kannst vielleicht den ganzen Code posten.

Ansonsten hilft dir vielleicht das:
http://openbook.galileocomputing.de...0.htm#Xxx999328

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14594
der ganze while block ist wahnsinn, ich check ehrlichgsagt im moment ned mal wieso das überhaupt geht... du setzt da den zeiger, welcher auf den listenanfang zeigen soll, ständig weiter...

probier im else zweig mal folgendes:
Code:
IntList *tmp = l;
while((*tmp)->next != null) {
  *tmp = (*tmp)->next;
}
(*tmp)->next = neu;
somit bleibt dein l pointer schön am anfang der kette und du itterierst dennoch durch.

Weiters, nur als Kosmetik: Es ist unschön wenn Liste und Knoten den selben Datentyp haben, weil es das ganze unlustig zum lesen macht. Schöner ist ma haut ein typedef drüber, welcher IntList und IntNode seperat definiert (obwohl sie beide ein und die selbe klasse sind im hintergrund).

edit: ich hätt auch gern den source, irgendwie schaut das ganze gscheit merkwürdig aus (auch was das allokieren und null setzen betrifft...)
Bearbeitet von semteX am 20.12.2008, 12:10

aNtraXx

trailer park king
Avatar
Registered: Apr 2002
Location: Linz
Posts: 6906
Jop, du brauchst eine temporäre Variable, die dir quasi immer den nächsten Knoten referenziert, denn sonst verlierst du am Ende die Referenz auf den Listenkopf.

jives

And the science gets done
Avatar
Registered: Sep 2001
Location: Baden
Posts: 3548
Warum eigentlich
Code:
(*temp)->next
und nicht
Code:
temp.next
?

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14594
ja, irgendwas passt da ganz gewaltig ned zam

aNtraXx

trailer park king
Avatar
Registered: Apr 2002
Location: Linz
Posts: 6906
Zitat von jives
Warum eigentlich
Code:
(*temp)->next
und nicht
Code:
temp.next
?

Weil er einen Zeiger auf eine Liste hat und die wiederum auf einen Knoten zeigt

l->next würde nur einmal dereferenzieren, dann dürfte er aber die Liste nicht als Referenz übergeben.

Daher (*l)->next.

Dynamische Objekte werden als Zeiger gehandelt, zwecks dynamischer Bindung. Und da er die Liste ja per maloc erstellt ist sie dynamisch :).
Bearbeitet von aNtraXx am 20.12.2008, 13:06

Bowser

Addicted
Avatar
Registered: Aug 2004
Location: Austria, 1050
Posts: 492
Ich glaub du denkst einfach zu kompliziert. Das machen alle die von Java oder ähnlichem kommen. C bzw. C++ ist in vielen Belangen viel einfach konstituiert, eben genau wegen der Hardware nähe.
Also du hat ein Objekt (struct nehm ich amal an) mit irgendwelchen Daten und dem Pointer zum nächsten Element. Dann hast du noch den Pointer auf das erste Element und einen auf das neue das du anhängen willst.
Also:
neu ist der Pointer auf das neue Element
l ist der Pointer auf das erste Element
current ist z.B. der Pointer auf das Aktuelle Element (zum Schleifendurchzählen)

Code:
current = l; //Anfang, ist vielleicht besser in der Schleife nicht l zu nehmen um das Erste Element nicht zu verlieren
while ( current->next != NULL ) { // current ist ein Pointer, somit ist die "->" Syntax am einfachsten. Alternativ "(*current).next"
current = current->next  //und zum nächsten gehen
}  //So, jetzt sollten wir in current das letzte Element haben
printf("%i",current->n); //Test, haben wir wirklich das Letzte??
current->next = neu;  //Anhängen vom neuen Element. Beides Pointer, also einfache Zuweisung.

Ich hab jetzt nix getestet oder so, aber es sollt ungefähr so hinhaun.

jives

And the science gets done
Avatar
Registered: Sep 2001
Location: Baden
Posts: 3548
Zitat von aNtraXx
Und da er die Liste ja per maloc erstellt ist sie dynamisch :).
Ah! Ja, das ist des Rätsels Lösung ;)

prayerslayer

Oar. Mh.
Avatar
Registered: Sep 2004
Location: vorm Sucher
Posts: 4073
mit einer tmp variable hab ichs auch schon versucht gehabt, aber ich probier mal. thx derweil :)

im anhang die aufgabenstellung. main und 2 andre funktionen waren gegeben.

Zitat von semteX
Code:
IntList *tmp = l;
while((*tmp)->next != null) {
  *tmp = (*tmp)->next;
}
(*tmp)->next = neu;
somit bleibt dein l pointer schön am anfang der kette und du itterierst dennoch durch.

hab ich so auch schon probiert gehabt und deswegen haut es mit deiner lösung auch nicht hin :(

Zitat von semteX
Weiters, nur als Kosmetik: Es ist unschön wenn Liste und Knoten den selben Datentyp haben, weil es das ganze unlustig zum lesen macht. Schöner ist ma haut ein typedef drüber, welcher IntList und IntNode seperat definiert (obwohl sie beide ein und die selbe klasse sind im hintergrund).

nicht auf meinem mist gewachsen :)

@Bowser: danke für die schöne erklärung, aber wennst dir meinen code anschaust wirst sehen, dass ich es eh "so ungefähr" ausschaut :)
aufgabe4_134787.txt (downloaded 101x)
Bearbeitet von prayerslayer am 20.12.2008, 17:25

Bowser

Addicted
Avatar
Registered: Aug 2004
Location: Austria, 1050
Posts: 492
Es schaut ungefähr so aus, ja, aber du vermischt doch 2 Dinge miteinander. Du versuchst immer (*tmp)->new zu verwenden, was aber keinen Sinn macht. Also, mit malloc erhältst du die Adresse (Pointer) zu dem neu erstellen Element. Wenn du den Pointer dereferenzierst erhältst du das Element selbst (*tmp). Wenn du dann auf ein Element daraus zugreifen willst kannst du das mit der Punkt Syntax machen (*tmp).new oder aber die Kurzschreibweise mit dem Pfeil tmp->new. Bei dem Pfeil ist eben kein dereferenzieren mehr dabei.
Übrigens ist mir da schon ein Fehler in der ersten Zeile bei deinem Append aufgefallen. Dein neu ist kein Pointer was es aber sein sollte, weil sonst ja der gesamte Sinn von malloc verloren geht.

DirtyHarry

aka robobimbo
Avatar
Registered: Apr 2001
Location: outer space
Posts: 464
merkst du dir irgendwo start und ende deiner liste? also zwei pointer auf das erste bzw. das letzte element?

wenn nein, das macht das ganze viel leichter, erstes bzw. letztes element aufrufen, dort den eintrag auf das neue struct setzen und fertig

prayerslayer

Oar. Mh.
Avatar
Registered: Sep 2004
Location: vorm Sucher
Posts: 4073
Zitat von Bowser
Es schaut ungefähr so aus, ja, aber du vermischt doch 2 Dinge miteinander. Du versuchst immer (*tmp)->new zu verwenden, was aber keinen Sinn macht. Also, mit malloc erhältst du die Adresse (Pointer) zu dem neu erstellen Element. Wenn du den Pointer dereferenzierst erhältst du das Element selbst (*tmp). Wenn du dann auf ein Element daraus zugreifen willst kannst du das mit der Punkt Syntax machen (*tmp).new oder aber die Kurzschreibweise mit dem Pfeil tmp->new. Bei dem Pfeil ist eben kein dereferenzieren mehr dabei.
Übrigens ist mir da schon ein Fehler in der ersten Zeile bei deinem Append aufgefallen. Dein neu ist kein Pointer was es aber sein sollte, weil sonst ja der gesamte Sinn von malloc verloren geht.

ich hab noch viel nachzuholen, seh ich grad. danke jedenfalls :)

Bowser

Addicted
Avatar
Registered: Aug 2004
Location: Austria, 1050
Posts: 492
So schlimm is es nicht. Ich glaub dir fehlt nur der Pointer als echter Datentyp an Wissen und dann würd schon alles rennen.
Wie gesagt, C ist weder kompliziert noch komplex, es ist ja gerade weil doch sehr nahe an der Hardware eher einfach. Java find ich da viel komplexer, weil jede kleine Bibliotheksfunktion in Wirklichkeit ein wahnsinns Aufand ist.

semteX

begehrt die rostschaufel
Avatar
Registered: Oct 2002
Location: Pre
Posts: 14594
da mein rehcner endlich mal wieder rennt hab ich es noch gschwind ausprogrammiert.

der "fallstrick" hier ist, dass IntList selbst schon ein zeiger ist. du hast somit beim append einen zeiger auf einen zeiger.

Code:
void Append(IntList *l, int n)
{ 
	if(*l == 0) {
		*l = (IntList)malloc(sizeof(elemtype));
		(*l)->next = 0;
		(*l)->wert = n;
	} else {	
		IntList tmp = *l;
		while(tmp->next != 0)
			tmp = tmp->next;
			
		IntList neu = (IntList)malloc(sizeof(elemtype));
		neu->next = 0;
		neu->wert = n;
		tmp->next = neu;
	}

}
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz