Rekursion erste Gehversuche versch. Varianten



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

  • Mod

    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 Linux 😉 auf 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 🙂



  • =>=> Mir ist jetzt noch was wichtiges eingefallen, was mir sehr am Herzen liegen würde, weil ich darauf auch in dem Realloc Thread nicht wirklich gekommen bin:

    Zitat:
    Ignorieren wir das mal und nehmen an, dass du einfach aus Prinzip malloc benutzen möchtest und dass du die Indexschreibweise meiden möchtest

    Jep, das möchte ich immer noch, bin mir aber nicht sicher wie sich das im folgenden Fall verhält / ich lösen könnte (Hab keine Code, ist nur eine Überlegung):

    iterator = feld;
    
      for (i=0; i<ZEILEN; i++){
        printf("Eingabe[%d]: ", i);
        fgets(*iterator, LEN, stdin);
         if(mehr_speicher_bedingung){
        //angenoommen ich habe für iterator schon ge-malloct, brauch jetzt aber doch mehr speicher : 
       *iterator=realloc(was_neues);    //  überprüfung mit evtl. tmp=realloc usw usw
      // => dann ist iterator mein "originalzeiger" 
           }
        iterator++  //=> Dann hab ich doch hier ein Problem, Rückgegebener Zeiger von Realloc / Malloc in Ruhe lassen....
    

    =>Müsste ich dann mit noch einem Hilfszeiger arbeiten? Aber wo weise ich den so sinvoll zu, das er weiterhin nach "jedem" Realloc noch passt?

    Also wenn quasi unter Umständen zum 4. mal Realloc kommt(fügt ja den neuen Speicher hinten an...), sollte mein Zeiger auf den nächsten "freien" Platz zeigen....

    Ich komm nur auf ne Index Lösung, aber das MUSS auch anders gehen.
    =>"index" wegspeichern mit pointerende-pointeranfang und dann später iterator+=weggespeichererter_index?? Is doch Käse oder??
    Ich hoffe das war verständlich, blick grad selber nicht mehr durch 😕 😕

    Also wer mir das verständlich rüberbringt, hat echt was gut.


  • Mod

    Du kannst Pointerarithmetik benutzen. Vor dem realloc kannst du dir damit ausrechnen, wie groß der Offset des Laufzeigers relativ zum Beginn ist, nach dem realloc rechnest du auf den neuen Beginn den Offset drauf und hast dann wieder einen passenden Laufzeiger.

    Bezüglich sauberer Eigenimplementierung eines dynamischen gets: Das sauberste wäre es wohl sich hier die ganze Speicherverwaltung zu kapseln. Ein struct mit den wichtigsten Daten (Anfang des reservierten Bereichs, Ende des reservierten Bereichs, Ende des belegten Bereichs) und eine Art "Konstruktor" und "Destruktor" (falls du diese Begriffe von anderen Sprachen kennt) und weitere Funktionen zum Zugriff, ganz nach Bedarf.
    Ist viel Aufwand.



  • Ok, danke. Das dynamische "gets" ist eigentlich dann für meine pillepalle Programme den Aufwand nicht wert. Aber vielleicht wenn mal viel Zeit ist.

    Du kannst Pointerarithmetik benutzen. Vor dem realloc kannst du dir damit ausrechnen, wie groß der Offset des Laufzeigers relativ zum Beginn ist, nach dem realloc rechnest du auf den neuen Beginn den Offset drauf und hast dann wieder einen passenden Laufzeiger.

    => würde das so passen?:
    (Beispiel ist ziemlich beschränkt, das geb ich zu...)

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define BRK 3
    #define END 30
    
    void re_int_ptr(void){
    
    int *feld, *iterator, run, index, value ;
    
    feld=malloc(sizeof(*feld)*BRK);  
    if (!feld){ puts("Error Mallocation"); exit(1);}
    iterator=feld   ;  
    
    for (run=0; run < END; run++){
                printf("Input for Feld[%d]:", run);
                scanf(" %d", &value);
                *iterator=value;
                index=iterator-feld;
                        if (run+1 < BRK)  {
                                  puts("Stored in Malloced Memory");
                                  }
                                  else if (run+1 ==BRK) {
                                           puts("Realloc Needed");
                                           feld=realloc(feld, (sizeof(*feld)*END));
                                           if(!feld){puts("Error Realloc!!"); exit(1);}
                                           iterator=feld;
                                           iterator+=index;
                                       }
                iterator++;
    
          }                                        
    
    int j; 
    iterator=feld;
    for (j=0; j<END; j++){
        printf("Feld[%d]: %d\n", j, *iterator++); 
    }           
    
    free(feld);     
    
    }//END
    

    =>Index=iterator-feld... müsste so passen, ja?

    =>feld = malloc (3) oder feld = malloc(sizeof(int) *3 ??
    Laut Referenz ist für Malloc und Realloc je größe in Bytes.... => feld =malloc(3) wäre bei nem char feld richtig, bei Int falsch. !?

    Wenn ich speicher nicht freigebe mit free.... kann es sein das mein Windows dann keinen Speicher mehr hergibt? Habe beim Tippen nämlich das free aus versehen mal mitgelöscht. Nach zirka 10 mal "Testen" war realloc immer NULL, also ich bekam immer meine Fehlermeldung "Error Realloc". Habe dann Win neu gestartet und es ging wieder.


  • Mod

    Das Programm ist technisch korrekt. Aber es ist irgendwie total verwirrt. Was ist denn der Unterschied zwischen deiner Variablen run und einem Index? Du hast doch jetzt nur den Namen geändert, dafür aber nochmal eine unnötige (denn index == run) Extra-Indexberechnung rein gemacht (die auch eigentlich in den Block bei Zeile 27 gehört).

    Wenn ich speicher nicht freigebe mit free.... kann es sein das mein Windows dann keinen Speicher mehr hergibt? Habe beim Tippen nämlich das free aus versehen mal mitgelöscht. Nach zirka 10 mal "Testen" war realloc immer NULL, also ich bekam immer meine Fehlermeldung "Error Realloc". Habe dann Win neu gestartet und es ging wieder.

    Nein, außer du hast einen Rechner und Betriebssystem von 1965. Du hast bei deinen Experimenten irgendeinen anderen Fehler eingebaut.

    Laut Referenz ist für Malloc und Realloc je größe in Bytes.... => feld =malloc(3) wäre bei nem char feld richtig, bei Int falsch. !?

    So ist es.



  • Das Programm ist technisch korrekt.

    Das freut mich doch sehr, vor allem der block ab Zeile 27 war mir wichtig mit dem "berechneten" Index... Der wie du schon geschrieben hast, natürlich nicht nötig wäre, da run==index..... Tja was soll ich sagen...

    Aber es ist irgendwie total verwirrt

    => schon 🙂

    Nein, außer du hast einen Rechner und Betriebssystem von 1965. Du hast bei deinen Experimenten irgendeinen anderen Fehler eingebaut.

    hm... seltsam, naja, wird dann wohl so sein. Also wenn meine Speicheranforderungen kein free erhalten UND mein Programm nicht abstürzt, dann ist nach Programm-Ende wida alles Paletti? Windoof ist das auch egal? hmm


  • Mod

    beginner_offl schrieb:

    hm... seltsam, naja, wird dann wohl so sein. Also wenn meine Speicheranforderungen kein free erhalten UND mein Programm nicht abstürzt, dann ist nach Programm-Ende wida alles Paletti? Windoof ist das auch egal? hmm

    Ja, jedes Betriebssystem, dem du jemals begegnen wirst, holt sich nach Programmende seine Ressourcen zurück, egal wie das Programm beendet wurde. Sonst wären Computer ziemlich unbenutzbar.
    Dies gilt vielleicht nicht mehr, wenn du mal für einen Microcontroller programmierst, also schön aufpassen und gleich richtig angewöhnen.
    Es gilt ebenfalls nicht für Ressourcen, die gar nicht vom Betriebssystem verwaltet werden. Wenn dein Programm z.B. irgendwelche Kommunikationsverbindungen aufmacht und diese nicht sauber beendet, dann bleiben die auch nach Programmende bestehen, weil das Betriebssystem gar nicht weiß, was solch eine Verbindung ist. Da die Techniken, wie man Ressourcen sauber reserviert und wieder frei gibt ziemlich genau die gleichen sind, egal um welche Art von Ressource es sich handelt, ist es eine gute Idee, es bei allen Arten von Ressourcen gleich richtig zu machen, damit man es sich angewöhnt. Gerade bei dynamischem Speicher hast du recht leicht die Möglichkeit, Fehler zu entdecken, und du kannst beim Experimentieren auch nichts kaputt machen. Da dran kann man also gut üben.


Anmelden zum Antworten