3Danke
ERLEDIGT
NEIN
NEIN
ANTWORTEN
11
11
ZUGRIFFE
269
269
EMPFEHLEN
-
24.02.10 20:28 #1
- Registriert seit
- Jan 2010
- Beiträge
- 51
Hallo,
ich habe Schwierigkeiten mit folgendem Code:
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
#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 :1
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!
-
24.02.10 21:07 #2
- Registriert seit
- Oct 2009
- Beiträge
- 60
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
-
24.02.10 21:20 #3
- Registriert seit
- Jan 2010
- Beiträge
- 51
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 :1
add_left (eingabe, &list);
auf. Übergebe also nur die Adresse des Pointers der auf die Liste zeigt.
Nun schreibe ich folgende Funktion:
Code :1 2 3 4 5 6 7 8 9 10
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 :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
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ß
-
24.02.10 23:24 #5
- Registriert seit
- Jan 2010
- Beiträge
- 51
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?
-
24.02.10 23:54 #6
Hi, versuchs wie folgt zu implementieren:
Code cpp:1 2 3 4 5 6 7
//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:
Code cpp:1 2 3 4 5 6
//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 :1
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
MfGGeändert von Marschal (24.02.10 um 23:59 Uhr)
" Gehirn: ein Organ, mit dem wir denken, daß wir denken. "
Ambrose Bierce
-
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 implementierenGeändert von sheel (25.02.10 um 00:06 Uhr)
-
25.02.10 00:09 #8
@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)
Geändert von Marschal (25.02.10 um 00:15 Uhr)
" Gehirn: ein Organ, mit dem wir denken, daß wir denken. "
Ambrose Bierce
-
Schon, aber er hat eben Probleme mit dem ganzen Pointerwerk dabei
-
25.02.10 07:50 #10
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
" Gehirn: ein Organ, mit dem wir denken, daß wir denken. "
Ambrose Bierce
-
25.02.10 13:54 #11
- Registriert seit
- Jan 2010
- Beiträge
- 51
Ja, ich möchte die Klasse selbst schreiben - rein zu Übungszwecken. Aber trotzdem Danke für deinen Tipp!

Oh, ich hoffe, dass du mit dieser Aussage falsch liegst. Wenn nicht, habe ich etwas falsch verstanden und das wäre ärgerlich.
Um bei einer einfach verketteten Liste rechts anzufügen, erstelle ich einen neuen Knoten mit neu->k = die zu speichernde Zahl und neu->rest = NULL. Nun gehe ich die Liste durch und verweise bei dem letzten Eintrag den Pointer, der auf NULL zeigt, auf den Knoten neu.
Um einen Eintrag links hinzuzufügen, erstelle ich einen neuen Knoten. neu->k ist die Zahl, neu->rest = list. Anschließend setze ich den Anfang der Liste auf neu, also *list = neu.
Müsste doch so funktionieren, oder? Und das ohne doppelte Verkettung.
Genau! Die Liste ist mittlerweile nicht mehr das Problem.
Zitat von sheel;

Okay, ich habe mal das Programm, welches Problemlos funktioniert durchkommentiert, so wie ich den Ablauf verstehe. Kann mal jemand drüber schauen ob ich es richtig verstanden habe? Ich weiß, dass es ein kleiner Aufwand ist. Ich wäre demjenigen sehr dankbar. Wenn nicht, ist es auch nicht schlimm...
Code c:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
#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; void add_element (int eingabe, Liste *list) /* Es steht nun zur Verfuegung, der Inhalt einer "Kopie" der Variable eingabe und ein Zeiger auf den Zeiger Knot *list, der auf den Speicherbereich 2345 zeigt */ { Liste neues_element = malloc(sizeof(Knoten)); /* Sagen wir der Zeiger neues element zeigt nun auf den Adressbereich = 3456 */ neues_element->k = eingabe; neues_element->rest = *list; /* in dem Speicherbereich 3456(.rest) wird die Adresse 2345 abgelegt */ *list = neues_element; /* Der Zeiger (zeigt auf 2345) auf den Zeiger (zeigt auf 1234) wird einmal dereferenziert, also wird in die Speicherstelle mit der Adresse 1234 der Wert 3456 abgelegt*/ } int main (void){ int eingabe = 1; while (eingabe != 0) { /* Meine Kommentare nehmen jetzt einfachheitshalber nur einen Schleifendurchlauf an */ printf("Zahl eingeben (0 fuer Ende): "); scanf("%d", &eingabe); add_element(eingabe, &list); /* Ich uebergebe den Inhalt der Variable eingabe und die Adresse des Zeigers list vom Typ Knoten - Sagen wir Knot *list zeigt auf den Speicherbereich 1234 Sagen wir &list ist 2345 */ } printf("Zahlen in umgekehrter Rheinefolge:\n"); print(list); printf("\n"); return 0; }
Nun weiß ich aber immernoch nicht, warum folgende Variante nicht läuft. Das würde ich wirklich gerne verstehen, weil das müsste sie nach meinem Verständnis.
Code c:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
. . . typedef struct Knot * Liste; typedef struct Knot{ int k; Liste rest; } Knoten; void add_left(int eingabe, Liste list) /* Es steht nun zur Verfuegung: eine "Kopie" der Variablen eingabe und Der Zeiger Knot* list, der nun auf den Adressbereich 1234 zeigt */ { Liste neues_element = malloc(sizeof(Knoten)); /* Zeiger Knot * neues_element zeigt auf den Adressbereich 2345 */ neues_element->k = eingabe; neues_element->rest = list; /* In den Adressbereich 2345(.rest) wird nun die Adresse 1234 geschrieben. *** Liegt hier ein Fehler vor? Muss das nicht heissen neues_element->rest = *list ? *** */ list = neues_element; /* Der Zeiger list soll nun auf Adressbereich 2345 zeigen */ } . . . int main (void) { . . . add_left(eingabe, list); /* Es wird uebergeben der Wert der Variablen eingabe und der Zeiger list Nehmen wir an list zeigt auf 1234, also wird auch 1234 uebergeben */ . . . }
Du hast das zwar ausführlich erklärt, aber ich verstehe immer noch nicht, warum ich mit der zweiten Funktion mein Ziel nicht erreichen würde. Ich übergebe bei der zweiten Funktion doch auch einen Zeiger, oder etwa nicht? Ich übergebe ja eingabe und list. list wurde definiert als Liste list, und dies als per typedef als Knot *liste.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
Also habe ich hier wirklich den Denkfehler? Ich dachte mit add_left (eingabe, list) übergebe ich eien Zeiger (list ist doch nun mal ein Zeiger). Demnach sollte dieser Adressbereich bearbeitet werden, und keine Kopie in der Funktion bearbeitet werdenMit 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
Danke! Das ist nett von dir! Aber ich denke nicht, dass es notwendig ist. Meine Liste funktioniert ja nun. Nur habe ich sie an ein paar Stellen noch nicht so ganz verstanden.
Zitat von Marschal
-
25.02.10 14:07 #12
- Registriert seit
- Jun 2005
- Beiträge
- 8.168
Hi.
Beim ersten Programm übergibst du ja einen Knot** (Zeiger auf einen Zeiger auf eine Knot Struktur) als Liste. Damit kannst du eben nicht nur auf eine Liste zugreifen, sondern eben auch auf die Variable die die Liste speichert.
Deswegen funktioniert dein zweites Programm nicht, du hast keine Möglichkeit auf die Variable zuzugreifen, da du deren Adresse nicht hast:
GrußCode c:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
int foo(int *ptr) { int* p = malloc(sizeof(int)); (*ptr) = 55; // Wert auf den x in main() zeigt wird geändert. ptr = p; // ändert aber nichts an x in main() } int bar(int **ptr) { (*ptr) = malloc(sizeof(int)); } int main(void) { int* x = NULL; foo(x); // NULL wird übergeben, x kann nicht verändert werden. bar(&x); // Adresse von x wird übergeben, der Wert von x kann geändert werden. }
If at first you don't succeed, try again. Then quit. No use being a damn fool about it.
Ähnliche Themen
-
Berechnung der Mitte der Liste für binäre Suche schlägt fehl
Von xbugsx im Forum C/C++Antworten: 0Letzter Beitrag: 20.11.07, 03:29 -
Element in einer Liste verschieben
Von nelly-furatdo im Forum JavaAntworten: 2Letzter Beitrag: 31.05.07, 19:15 -
SCardEstablishContext(..) schlägt fehl
Von apotechnik im Forum VisualStudio & MFCAntworten: 1Letzter Beitrag: 19.08.05, 11:02 -
Registrieren einer ActiveX - Komponente schlägt fehl
Von MadJedy im Forum Microsoft WindowsAntworten: 0Letzter Beitrag: 23.06.05, 08:42 -
Erstes und Letztes Element einer Liste wiedergeben
Von suedi im Forum PHPAntworten: 10Letzter Beitrag: 16.01.04, 13:43





Zitieren

Login






