Rekursion erste Gehversuche versch. Varianten
-
beginner88888 schrieb:
Zu den Änderungen:
Programm 1: Keine Fragen
Programm 2:
Das mit der Funktion implementieren, ist mit klar, besonders ausgearbeitet war das nicht von mir.
=> mein:if (index < tiefe-1)
zu deinem :
if (index + 1 < tiefe)
? Ist dir das "persönlich" lieber, oder übersehe ich etwas entscheidendes?
So wird ein Unterlauf in
tiefe - 1
verhindert.[quote]Zur zweiten Frage: Ich entdecke nichts, was ich nicht schon vorher gesagt hätte. Und auch nichts, was Bauchschmerzen auslöst.
-
Das mit dem Unterlauf leuchtet mir ein.
Zur zweiten Frage: Ich entdecke nichts, was ich nicht schon vorher gesagt hätte. Und auch nichts, was Bauchschmerzen auslöst.
Ok, das beruhigt mich.Könnte man es irgendwie an der Stelle:
rek_charP(work+1, anfang); // work++ geht nicht , da hier zu schnell das "Ende" erreicht wird, liege ich richtig???
mit Zeiger++ lösen, wenn man evtl. davor den Zeigerstand wegspeichert? Kaum oder?, da sich die funktion ja damit wieder selbst aufruft....
Zeiger++ ist wolh eher nix für ne Rekursive funktion, sehe ich das richtig?Wünsche schon mal allen ein schönes Wochenende!
-
Es macht halt einen Unterschied, ob man
work + 1
oder++work
oderwork++
schreibt. Mal will man das eine, mal das andere. Da du work mehrmals benutzt, sind die Unterschiede dazwischen wichtig, da sie sich eben in den anderen Teilen des Codes auswirken. Was richtig ist, kommt eben auf den Einzelfall an.
Ich verstehe aber nicht, wieso du so wild aufwork++
bist. Es bedeutet eben nicht "eins mehr als work" (das wärework + 1
), was hier aber gemeint zu sein scheint.P.S.: Der Unterschied zwischen
++work
undwork++
ist dir klar?
-
P.S.: Der Unterschied zwischen ++work und work++ ist dir klar?
hmm... Ich hoffe.. ++work, erhöhen und work benutzen, work++ work benutzen , erhöhen ?
Ich verstehe aber nicht, wieso du so wild auf work++ bist. Es bedeutet eben nicht "eins mehr als work" (das wäre work + 1), was hier aber gemeint zu sein scheint.
Ich auch nicht... work++ => Zeiger auf nächstes Element vom Typ auf den work zeigt?? Hope so...??
-
beginner88888 schrieb:
hmm... Ich hoffe.. ++work, erhöhen und work benutzen, work++ work benutzen , erhöhen ?
Ich auch nicht... work++ => Zeiger auf nächstes Element vom Typ auf den work zeigt?? Hope so...??
Passen die beiden Aussagen zusammen?
-
Nö, nicht wirklich.
work++ => Zeiger auf nächstes Element vom Typ auf den work zeigt?? Hope so...??
Soweit noch richtig ?
Für eine gute Erklärung wäre ich echt dankbar!!!
-
Nein, die andere Erklärung war richtig. work++ gibt dir den aktuellen Wert von work, erhöht work danach um 1. Das work dabei ein Zeiger ist, ändert auch nicht wirklich was. Der zeigt dann eben hinterher auf das nächste Element des Zeigertyps.
-
*work='x';
work++;
*work='y';... puts(work) => xy
So wird ein Schuh draus würd ich sagen. Hab ich etwas doof geschrieben gehabt.
Also die andere Erklärung war "generell" gemeint,Zitat:
work++ => Zeiger auf nächstes Element vom Typ auf den work zeigt?? Hope so...??... War "zur weiteren Verwendung"
So stimmts doch, hätt ich gesagt?
-
beginner88888 schrieb:
*work='x';
work++;
*work='y';... puts(work) => xy
Korrekt. Wobei du, wenn du es so schreibst, den ganzen Vorteil des Postinkrements verschenkst. Der Code ist schließlich identisch zu
*work='x'; ++work; *work='y';
oder
*work='x'; work += 1; *work='y';
oder ähnliches.
Die spezielle Eigenschaft, dass das Postinkrement den ursprünglichen Wert zurück liefert, kannst du so nutzen:
*work++='x'; *work='y';
-
So, nun géhts weiter mit **char bzw. 2 Dim Array. Ich weiß es ist nicht dasselbe.
Vorab:
1.) Ich hab mich nicht eingelesen, ich hab´s jetzt mal so probiert wie ich es mir erdacht habe, möglich das es total falsch ist( obwohl es funktioniert)
2.) Übung, bzw. Experimental, das hier **char unnötig ist, da ich ja ein statisches 2 Dim Array machen könnte da ja ZEILEN und LEN fest ist. Aber darum geht´s ja nicht.=> Erklärungen, bzw. Fragen im Code als Kommentar, bin gespannt.
Variante 1:
Arbeitet mit Index, ich bin mir ziemlich sicher das es so stimmt
dsi.c:#include <stdio.h> #include <stdlib.h> #define ZEILEN 3 #define LEN 100 void dsi(void){ char **feld; // Feld ist ein Zeiger auf einen Zeiger, der auf char zeigt int i, j; feld=malloc(ZEILEN*sizeof(*feld)); //feld bekommt von Malloc speicher für 3(Zeilen) x Zeiger auf char => char *feld[3]?? if (!feld){ puts("Error Mallocation"); exit(1); } for (i=0; i<ZEILEN; i++){ printf("Input[%d]:", i); feld[i]=malloc(LEN); // Hier Speicher für den Zeiger[i] anfordern fgets(feld[i], LEN, stdin); } puts("Now let´s see the Inputs..."); for (j=0; j<ZEILEN; j++){ printf("Input[%d] was:\n", j); puts(feld[j]); } free(feld); //wird auch der Speicher von fled[i]=malloc(LEN) hier frei oder?? }//END
Variante 2 ist mein "Sorgenkind". Auch sie funktioniert so weit ich es getestet habe, jedoch ist die derefferenzierung mit ** etwas haarig
Die Überlegung im Code ist hoffentlich verständlich, noch besser wäre wenn sie Richtig ist.dsp.c
#include <stdio.h> #include <stdlib.h> #define ZEILEN 3 #define LEN 100 void dsp(void){ char **feld, **start; int i, j; feld=malloc(ZEILEN*sizeof(*feld)); // Feld ist ein Zeiger auf einen Zeiger, der auf char zeigt if (!feld){ puts("Error Malloc"); exit(1); } start=feld; //start für spätere Anzeige "setzen" /* Für die Pointer hab ich mir folgenden Zusammenhang erdacht: value <= *pointer <= ** pointer pointer++ erhöht *pointer , also bei mir : erhöhung der 3 Feld Zeiger (*pointer)++ => wenn value ein String wäre, Zeiger zeigt auf nächsten Buchstaben? (**pointer)++ => erhöht value */ for (i=0; i<ZEILEN; i++){ printf("Eingabe[%d]: ", i); *feld=malloc(LEN); // Dereferenziert : 1.ZEiger auf Char Speicherplatz zuweisen fgets(*feld, LEN, stdin); feld++; // Feldzeiger erhöhen, feld[0] auf feld[1] quasi } puts("Lets see again...\n"); for (j=0; j<ZEILEN; j++){ printf("Input[%d] was:\n", j+1); puts(*start); start++; } free(feld); //reicht das? }//END
Stimmt das mit den Pointern so ?
-
Erstes Programm:
free(feld); //wird auch der Speicher von fled[i]=malloc(LEN) hier frei oder??
Nein, wird nicht wieder frei. Muss vorher noch explizit freigegeben werden, ansonsten Speicherloch.
Zweites Programm:
Wieder falsch, sollte beim Ausführen Abstürzen. Wieder die gleichen Fehler wie in diesem Thread:
http://www.c-plusplus.net/forum/323104
Ich wiederhole mal nicht, was dort gesagt wurde.
-
Stürzt nicht ab bei mir, darum hab ich mir auch nicht weiter Gedanken gemacht.
Würde es reichen, wenn ich
feld=malloc(ZEILEN*sizeof(*feld));
char **arbeit =feld;
und dann mit "arbeit" weitermache? alsoo statt feld++ arbeit++ ??
Nicht oder, in der 1. For schleife erhalte ich ja wieder Speicher von Malloc, den ich nicht "verbiegen" darf....
Wie gesagt, bei der Index Variante war ich mir fast sicher das es passt, ich würde es aber trotzdem gerne mit Pointern lösen. Sch*dr**.Stimmt wenigstens das wie ich es mir mit den Pointern gedacht habe?
Also erst Speicher für 3 Zeiger und dann jeden Zeiger speicher zuweisen?
-
beginner_offl schrieb:
Stimmt wenigstens das wie ich es mir mit den Pointern gedacht habe?
Also erst Speicher für 3 Zeiger und dann jeden Zeiger speicher zuweisen?Das ist an sich die richtige Vorgehensweise, wenn man eine (zur Compilezeit) unbekannte Anzahl von Zeichenketten mit jeweils unterschiedlicher, unbekannter Länge möchte. Hier ist das natürlich doppelt umständlich, da sowohl die Länge aller Zeilen gleich ist. Das heißt, du könntest direkt Zeilenzahl*Zeilenlänge reservieren, anstatt Zeilenzahl Male einzeln eine einzelne Zeilenlänge zu reservieren. Da die Zeilenzahl zudem zur Compilezeit bekannt ist, kannst du dir auch gleich malloc sparen und ein statisches Array
char daten[zeilenzahl][zeilenlänge]
benutzen.
Ignorieren wir das mal und nehmen an, dass du einfach aus Prinzip malloc benutzen möchtest und dass du die Indexschreibweise meiden möchtest. Dann bieten sich zwei Ideen an:
-Du machst es richtig sauber und trennst die Verantwortlichkeiten. Funktionen die sich um Speicher kümmern, Funktionen die auf diesem Speicher arbeiten.
-Du korrigierst deine Version. Das könnte so aussehen:void dsp(void){ char **feld, **iterator; int i; feld=malloc(ZEILEN*sizeof(*feld)); if (!feld){ puts("Error Malloc"); exit(1); } iterator = feld; for (i=0; i<ZEILEN; i++){ printf("Eingabe[%d]: ", i); *iterator=malloc(LEN); fgets(*iterator, LEN, stdin); iterator++; } puts("Lets see again...\n"); iterator = feld; for (i=0; i<ZEILEN; i++){ printf("Input[%d] was:\n", i+1); puts(*iterator); iterator++; } iterator = feld; for (i=0; i<ZEILEN; i++){ free(*iterator); iterator++; } free(feld); }
Du siehst, das ist nicht sehr verschieden von dem, was du hattest, aber ich habe aufgepasst, dass der ursprüngliche Zeiger auf das Feld nicht verloren geht und habe zum Arbeiten immer eine Arbeitskopie (den iterator) benutzt.
Hier sind sehr oft noch Codes wie
for (...) { tu_was(*iterator); iterator++; };
drin. Wie ich dir im anderen Thread schon erklärt habe, lässt sich das auch kompakter schreiben als:
for (...) { tu_was(*iterator++); };
-
Ignorieren wir das mal und nehmen an, dass du einfach aus Prinzip malloc benutzen möchtest und dass du die Indexschreibweise meiden möchtest
Ja, das war Sinn und Zweck der Übung. Index = bäh
Spass beiseite, Zeilen und Spalten länge sind mir ja bekannt, aber ich wollte mal das "Grundprizip" wie ich aus **char ein 2Dim Array machen kann (ist so nicht ganz richtig, ich weiß) erarbeiten.Du siehst, das ist nicht sehr verschieden von dem, was du hattest, aber ich habe aufgepasst, dass der ursprüngliche Zeiger auf das Feld nicht verloren geht und habe zum Arbeiten immer eine Arbeitskopie (den iterator) benutzt
Das habe ich mit
Würde es reichen, wenn ich
feld=malloc(ZEILEN*sizeof(*feld));
char **arbeit =feld;
und dann mit "arbeit" weitermache? alsoo statt feld++ arbeit++ ??
gemeint. Cool, ich lag gar nicht so falsch. Jipieio!!
=>Malloc wie Realloc, ich darf den "Original-Zeiger" den ich von Mall bzw. Reall erhalte einfach nicht anfassen und schon bin ich save...
Das mit dem Speicher wiede freigeben, habe ich in den Minuten vor deinem Post gemacht. (Klar das kann jetzt jeder schreiben, ist aber so
).
So, jetzt noch was anderes.... Index Schreibweise , ja oder nein? Wie sieht´s aus in der Praxis? Geschmackssache oder nicht?
=>Und noch wichtiger: Wie gesagt, bei mir ist es nicht abgestürzt, weder mit DevC++ noch mit CodeBlocks.... Bei DevC++ find ich auch nicht´s um die Compilerwarnstufen hochzusetzten, aber davon abgesehe... Der Compiler würde da auch nicht meckern schätz ich. .... Wie prüf ich solche Fälle am besten? (Klar durch "es Besser wissen" wird einfacher...)
-
Nachtrag : Die "Erklärung" für die Dereffernzierungen passen soweit ja?
-
Überarbeitet Version:
#include <stdio.h> #include <stdlib.h> #define ZEILEN 3 #define LEN 100 void dsp(void){ char **feld, **work; int i, j, dummy; feld=malloc(ZEILEN*sizeof(*feld)); if (!feld){ puts("Error Malloc"); exit(1); } work=feld; for (i=0; i<ZEILEN; i++){ printf("Eingabe[%d]: ", i+1); *work=malloc(LEN); if (!work){ puts("Error Malloc"); exit(1); } fgets(*(work++), LEN, stdin); } puts("Lets see again...\n"); work=feld; for (j=0; j<ZEILEN; j++){ printf("Input[%d] was:\n", j+1); puts(*(work++)); } //Free Lines for (dummy=0; dummy < ZEILEN; dummy++){ free(*(feld++)) ; } free(feld); }//END
-
beginner_offl schrieb:
So, jetzt noch was anderes.... Index Schreibweise , ja oder nein? Wie sieht´s aus in der Praxis? Geschmackssache oder nicht?
Du nimmst das, was du brauchst. Wenn du von vorne bis hinten iterierst, ist eine Indexvariante eher unnötiger Aufwand, die ist dazu da, dass man wahlfrei zugreifen kann, wo es gerade nötig ist. Daher ist sie (wenn sie nicht wegoptimiert wird) ganz miniml langsamer, was manchmal wichtig sein kann. Dafür finde ich die Schreibweise leserlicher, was wieder an anderen Stellen wichtig sein kann.
=>Und noch wichtiger: Wie gesagt, bei mir ist es nicht abgestürzt, weder mit DevC++ noch mit CodeBlocks.... Bei DevC++ find ich auch nicht´s um die Compilerwarnstufen hochzusetzten, aber davon abgesehe... Der Compiler würde da auch nicht meckern schätz ich. .... Wie prüf ich solche Fälle am besten? (Klar durch "es Besser wissen" wird einfacher...)
Das sind Laufzeitfehler, da kann der Compiler nichts mehr machen. Also ich habe es dadurch gemerkt, dass bei meiner Implementierung (von malloc/free) ein fetter Fehler vonwegen ungültigem free kam. Wenn das deine Implementierung nicht macht, ist das ein bisschen ungünstig, dann musst du dich eben über andere Debugmethoden deiner Plattform kundig machen. Weiterhin ist auf meiner Plattform auch das schöne Progrämmchen valgrind verfügbar, mit dem man sehr viele Fehler dieser automatisch Art findet, selbst gut versteckte. Wieder dürfte dies bei dir nicht gehen und daher musst du dir selbstständig passende Werkzeuge suchen (oder mal im passenden Forum fragen, was andere empfehlen).
beginner_offl schrieb:
Nachtrag : Die "Erklärung" für die Dereffernzierungen passen soweit ja?
Welchen Beitrag genau meinst du? Der Thread ist ziemlich lang geworden
-
Weiterhin ist auf meiner Plattform auch das schöne Progrämmchen valgrind verfügbar
Wenn man fragen darf, was benutzt du?
Code im Nachtrag passt jetzt so , ja?
Welchen Beitrag genau meinst du? Der Thread ist ziemlich lang geworden
/* Für die Pointer hab ich mir folgenden Zusammenhang erdacht: value <= *pointer <= ** pointer pointer++ erhöht *pointer , also bei mir : erhöhung der 3 Feld Zeiger (*pointer)++ => wenn value ein String wäre, Zeiger zeigt auf nächsten Buchstaben? (**pointer)++ => erhöht value */
-
beginner_offl schrieb:
Wenn man fragen darf, was benutzt du?
Diese geheimnisvolle Hackersystem, von dem immer alle reden. Linux oder so ähnlich heißt das.
Code im Nachtrag passt jetzt so , ja?
Sieht vom Lesen her korrekt aus.
Hier sieht man auch schön das Speicherloch, dass du erzeugst, wenn du in Zeile 26 abbrichst. Weil dann ja nie ein free erfolgt. Aber das in C vollkommen korrekt umsetzen zu wollen, das ist der Grund, warum man höhere Sprachen erfunden hat, die das automatisch machen. Das darfst du bloß mal im Hinterkopf behalten, als etwas was so nicht 100% korrekt ist, aber mach dich darum nicht verrückt.
Welchen Beitrag genau meinst du? Der Thread ist ziemlich lang geworden
/* Für die Pointer hab ich mir folgenden Zusammenhang erdacht: value <= *pointer <= ** pointer pointer++ erhöht *pointer , also bei mir : erhöhung der 3 Feld Zeiger (*pointer)++ => wenn value ein String wäre, Zeiger zeigt auf nächsten Buchstaben? (**pointer)++ => erhöht value */
Korrekt außer
pointer++ erhöht *pointer
pointer++ erhöht pointer.
-
Ok danke.
Privat hab ich auch dieses ominöse Linuxauf Arbeit aber Windows. Das wird wohl auch so bleiben :|
Wenn ich noch eine Frage frei habe:
Jetzt wo malloc und realloc so weit klar ist, will ich mal meinen ersten c Versuch , zeilenweises einlesen von Strings wida aufnehmen. Auch wenn es wohl mit Elefanten auf Spatzen schießen ist, probierm will ichs.
Aber mir ist nicht klar wie ich sinnvoll zurückgebe.
Hab noch keinen Code, aber will quasi char Weise einlesen bis ZeilenEnde und dabei Speicher erweitern. Nur wie geb ich zurück? Als Zeiger? Dann musste ich beim Aufruf schon Speicher bereitstellen. Nicht der Hit. In nen char buffer? Könnte zu klein sein. Die Funktion soll ja erleichtern....
Hoffe das war verständlich. Muss am Handy tippen weil ich gerade für Monika gruber Karten anstehe in der Kälte