Element in einer Liste abspeichern schlägt fehl

Cherrycoke

Mitglied
Hallo,

ich habe Schwierigkeiten mit folgendem Code:

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

/* Liste = Zeiger auf einen Knoten */
typedef struct Knot * Liste;

/* Knoten enthaelt eine eingelesene Zahl */
typedef struct Knot{
	int k;
	Liste rest;
} Knoten;

Liste list = NULL;

int maxi (int eingabe, int maximum)
{
	if (eingabe > maximum)
	{
		return eingabe;
	}
	else
	{
		return maximum;
	}
}

void add_left (int eingabe, Liste list)
{
	Liste neu;
	neu = calloc(1, sizeof(Knoten));

	neu->k = eingabe;
	neu->rest = NULL;

	if (list == NULL)
	{
		list = neu;
		printf("Die Liste ist leer (nun gefuellt)\n");
	}
	else
	{
		neu->rest = list;
		list = neu;
		printf("Die Liste war bereits gefuellt\n");
	}
}

int main (void){

	int eingabe = 1;
	int summe = 0;
	int anzahl = 0;
	int maximum = 0;

	while (eingabe != 0)
	{
		printf("Zahl eingeben (0 fuer Ende): ");
		scanf("%d", &eingabe);
		
		add_left(eingabe, list);

		anzahl++;
		summe=summe+eingabe;
		maximum = maxi(eingabe, maximum);
	}	

	printf("Anzahl der Zahlen: %d\n", anzahl);
	printf("Summe: %d\n", summe);
	printf("Maximum: %d\n", maximum);

	return 0;

}

Und zwar sollte die Funktion "add_left" eine Liste erstellen, und ein Element an der linken Seite der Liste hinzufügen. Wie man an meiner Testausgabe sehen kann, ist der else-Teil der If-Abfrage nie erfüllt. Leider weiß ich jedoch nicht warum. Ich kann daraus nur Ableiten, dass

Code:
list = neu;

aus dem oberen Teil der If-Abfrage eine falsche Anweisung wäre? Wie müsste das denn richtig heißen?

Ich danke schon einmal für einen kurzen Tipp!
 
hm also ich bin zwar selber kein Profi aber...
Ich werde nicht ganz schlau aus deinem "Programm".
So wie du das erstellst läuft ja garnichts.
Aber an deine If-abfrage scheint eigentlich alles in Ordnung zu sein.
mfg
 
hm also ich bin zwar selber kein Profi aber...
Ich werde nicht ganz schlau aus deinem "Programm".
So wie du das erstellst läuft ja garnichts.
Aber an deine If-abfrage scheint eigentlich alles in Ordnung zu sein.
mfg

Höh? Warum sollte es nicht laufen? Also der Großteil funktioniert einwandfrei. Okay, ich habe nicht wirklich erklärt, was das Programm überhaupt leisten soll und auch nicht wirklich gut kommentiert. *shame on me*

Ich rufe nun die Funktion mittels
Code:
add_left (eingabe, &list);

auf. Übergebe also nur die Adresse des Pointers der auf die Liste zeigt.

Nun schreibe ich folgende Funktion:

Code:
void add_left (int eingabe, Liste *list)
{
	/* erzeuge ein neues Listenelement */
	Liste neues_element = malloc(sizeof(Knoten));

	neues_element->k = eingabe;
	neues_element->rest = *list;
	*list	= neues_element;

}

Und alles funktioniert, so wie es soll! :-)

Warum funktioniert aber

Code:
void add_left(int eingabe, Liste list)
{
	/* erzeuge ein neues Listenelement */
	Liste neues_element = malloc(sizeof(Knoten));

	neues_element->k = eingabe;
	neues_element->rest = list;
	list	= neues_element;

}
.
.
.
int main (void)
{
.
.
.
add_left(eingabe, list);
.
.
.
}

nicht? Das habe ich jetzt noch nicht ganz durchschaut. Könnte hierzu noch jemand ein paar Worte verlieren? Danke!
 
Bei der ersten Funktion übergibst du ja einen Pointer auf die Liste
Damit weis die Funktion, an der und der Stelle im Speicher ist das und soll auch dort geändert werden

Bei Funktion 2 übergibst du aber die Variable selber, damit übergibst du eine Kopie(!).
Die Kopie wird in der Funktion geändert, und sobld die Funktion fertig ist wieder vernichtet
Die Originalvariable im main etc bekommt von den Änderungen nichts mit

In C ist es grundsätzlich so, dass alles als Kopie übergeben wird.
Als Abhilfe zB die Pointer:

Übergibt man die Variable selber, wird eine Kopie übergeben;
Wenn man aber einen Pointer darauf übergibt, der ja nichts anderes als eine Platzangabe ist (zB deine Variable ist am Byte 4321 im RAM), wird nur die 4321-Angabe kopiert.
Greift man (mit dem * ) aber auf das zu, was beim Byte 4321 selber ist, ist es wieder deine Originalvariable.

Hoffe dass ich dich nicht zu sehr verwirrt habe :-)

Gruß
 
Okay, ich denke ich konnte dir ganz gut folgen und habe das Vorgehen verstanden.

Aber ist "list" aus der zweiten Funktion nicht eigentlich schon ein Pointer auf einen Knoten? Somit würde ich doch bereits einen Pointer übergeben, so dass der "original" Knoten in der Funktion geändert werden sollte, und nicht dessen "Kopie"?

Übergebe ich in der ersten Funktion meines letzten Beitrages, nicht eine Adresse auf ein Pointer, der auf einen Knoten zeigt, und erhalte in der Funktion somit einen Pointer auf einen Pointer auf einen Knoten? Wo liegt hier mein Denkfehler?
 
Hi, versuchs wie folgt zu implementieren:

C++:
//Header:
#include <list>

//Liste anlegen:
typedef std::list</*Objekt oder das was du verwalten möchtest*/> list1;
//iterator anlegen: (sowas wie Zeiger zum Liste druchlaufen)
typedef std::list</*Objekt oder das was du verwalten möchtest*/>::iterator list1_iter;

benutzen wie folgt:
C++:
//z.b.: in der main
int main (/*bla bla*/)
{
 list1_iter.begin();//iterator auf beginn der liste setzen
list1.push_back(/*dein werwaltetes objekt, welches du einfügen willst*/);//ans Ende der Liste einfügen.
}

in deinem Fall links einfügen mit
Code:
list1.push_front();

Weshalb benuzt du nicht die fertige List Klasse?

EDIT: Oder möchtest du eine selbstgeschirebene Klasse benutzen? Danach siehts nämlich aus.
Wenn du auch "links" einfügen willst brauchst du eine mehfach verkettete Liste, also eine Liste mit einem Zeiger aufs nächte und auf vorherige Element, wenn ich mich nicht irre. Wie du vllt schon gemerkt hast ist pointer-programmierung so ne Sache... benutz lieber die schöne und komfortable List klasse;)

MfG
 
Zuletzt bearbeitet von einem Moderator:
Die zweite Funktion würde reichen, wenn du nur den knot hinter der list ändern würdest
Angenommen, es geht um einen Knot, der im RAM auf Platz 1234 liegt

list zeigt auf den knot; dh list ist eigentlich nur ein int, das 1234 gespeichert hat

Der Unterschied zum normalen int ist eben, das man list zwar auch als Zahl mit dem Wert 1234 verwenden kann; aber hauptsächlich das interressant ist, das am gespeicherten Platz liegt
(Worauf man ja mit * zugreifen kann)
Trotzdem ist list eigentlich nichts anderes wie ein int

Bei der zweiten Funktion würde das dann folgend ablaufen:
Übergeben wird
<1234> (zeigt auf ->knot)
"Ankommen" in der Funktion wird
<Kopie von 1234> ->knot
zeigt auch auf das gleiche knot
Wenn du jetzt nur das knot ändern möchtest, ist die zweite Funktion ok.

Das Problem sind malloc/calloc
Diese Funktionen suchen einen freien Speicherplatz, soviel man halt angegeben hat,
und geben einem den Platz im RAM, wo was passendes gefunden wurde
Und da dieser neue Platz so gut wie nie auch auf 1234 sein wird, musst du die neue Adresse in list speichern

Mit der zweiten Funktion kann man eben gut auf den knot zugreifen;
wenn man aber list ändert, wird nur die Kopie angepasst und das Original denkt noch immer, ihm gehört 1234, auch wenn der neu zugeteilte Platz ein paar Millionen Byte daneben liegt

Deswegen wird jetzt die Adresse von list übergeben (ist ja auch nur ein int ...), damit man list auch ändern kann.

Sorry, aber ich kanns nicht kompakter erklären
Solche Pointerspielereien um Mitternacht... :-)

@Marschal: Ich glaub eher, er will die Funktionen selber implementieren
 
Zuletzt bearbeitet:
@Shell: nun gut. Dann reichts doch aber wenn man einfach in jedem Listen Element einen Pointer auf das jeweils nächste und vorherige Element hat. In den Funktionen add Links und add rechts muss man nur noch die Pointer richtig setzen und fertig, oder verstehe ich hier irgendwelche Zusammenhänge falsch?:) denn zugegeben deinen Riesen Beitrag habe ich nicht gelesen:P

MfG

EDIT: hab deinen Beitrag grad doch noch gelesen:P die Beschreibung was ein Integer im arbeisspeicher und was ein Pointer darauf ist, ist echt der Hammer:) erinnert much schon fast an die kleinen grünen Männchen, die die Bits setzen:) (ich hatte früher Lehrer die so argumentierten)
 
Zuletzt bearbeitet:
Ok kenn ich;) hab ich früher auch mal gemacht.

@Cherrycoke: wenn du mochtest kann ich mal in alten Projekten suchen. Da durfte ich eine funktionierende Liste haben.

MfG
 
Zurück