Rekursion erste Gehversuche versch. Varianten



  • Allgemein: Mit genügend Leerzeilen kann man einen Code so sehr formatieren, dass er nicht mehr formatiert aussieht .

    Ja 🙂 Eher schon :-), nö, ich hab im "Original" Code Kommentare für mich selbst und "stümper"-Debug Codes ausgeklammer, wo jetzt die Leerzeichen sind.

    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?

    Noch was, für die "später" Sache mit den Strings... Angenommen ich möchte die Wörter dann aus einer Datei einlesen.... Lieg ich mit **char , bzw. 2 Dim Array[wörter][zeichenanzahl_max] richtig, bzw. ist das mein Stichwort ?? 😉

    Ja, das geht schon in die richtige Richtung. Dir ist aber schon klar, dass das beides was unterschiedliches ist?

    Ja, ist mir klar. Was genau für mich interessant ist, weiß ich selbst noch nicht, da ich mir noch keine genauen Gedanken gemacht habe wie es werden soll.
    =>Mühsam nährt sich das Eichhörnchen 🙂 Wichtig war mir jetzt vor allem, das das Grundprizip der Rekursion richtig ausgeführt ist bei mir, sprich : OK, das funktioniert so wie ich es will und nicht nur zufällig. (Das hatte ich schon des öfteren).

    OT: Danke für die Antworten und die mühen. Bin ja mittlerweile Dauergast im Forum, hoffe ich falle nicht zu sehr auf die Nerven 😞 :Kuchen_für_die_Helfer 😉



  • =>Nachtrag : Könnte man die Variante mit den Char auch mit Pointern lösen?
    Ungeachtet Sepp´s generellen Verbesserungen( Der folgende Code Stammt noch von vor-vorgestern), war dies mal ein Ansatz von mir.
    Aber ehrlich gesagt... Naja...

    #include <stdio.h>
    #include <stdlib.h>
    #include "sys.h"
    #include "cpatP.h"
    
    void rek_charP(char *string , char *anfang){
    
    const int tiefe=strlen(patternP);     
    int run;
    char* work;
    
    work=string;
    
    for (run=0; run< tiefe  ; run++){      
    
         *work=patternP[run];   
    
          if ( (work-anfang) < (tiefe-1)) { 
                   rek_charP(work+1, anfang);    // work++ geht nicht , da hier zu schnell das "Ende" erreicht wird, liege ich richtig??? 
              }                                    
             else 
    
                puts(anfang);
         }    
    
    }//END
    

    Funktionieren Tut es... Hab aber irgendwie etwas Bauchweh bei dem Code.
    Hier würde mich brennend Interessieren, wie man das "richtig" macht.
    =>wie gesagt, ich habe SeppJ´s Anregungen nicht umgesetzt, weil dieser Code VOR dem Post hier war, und ich auf dem "Grundgerüst" evtl. weiterarbeiten will.


  • Mod

    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!


  • Mod

    Es macht halt einen Unterschied, ob man work + 1 oder ++work oder work++ 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 auf work++ bist. Es bedeutet eben nicht "eins mehr als work" (das wäre work + 1 ), was hier aber gemeint zu sein scheint.

    P.S.: Der Unterschied zwischen ++work und work++ 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...??


  • Mod

    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!!!


  • Mod

    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?


  • Mod

    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 ?


  • Mod

    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?


  • Mod

    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
    

  • Mod

    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 */
    

Anmelden zum Antworten