Pointer-Einsatz in einer Funktion



  • Interessiert schrieb:

    Hmm, also lieber void als rückgabe-typ (oder int für Fehlercodes), ein weiteren Parameter für die Länge des Arrays (anstatt fehleranfälliges strlen) und ein pointer für das Resultat?
    Oder wie genau?

    Eher wie bei strcpy aber mit Angabe der Größe vom Ziel.

    Die Größe des Ziels ist in C das Problem.
    Die Größe der Quelle könntest du mit strlen bestimmen.
    Aber auf strlen kannst du verzichten, da du ja eh in einer Schleife durch den String gehst.

    Als Rückgabewert kommt das Ziel.

    char* markText2(char *d, size_t len, const char *s, char sel)
    
      ... // Im einfachsten Fall ein strcpy :-)
    
      return d;
    }
    


  • Hmm, aber ich dachte der Sinn ist es gerade, dass die Funktion selber bestimmt, wie viel zusätzliche chars gebraucht werden. Also auch wie groß das Ziel sein muss.

    Ist das nicht irgendwie komisch, wenn der Aufrufer das selber wissen muss?

    Und noch mal die Sache mit dem strlen: Das Problem ist doch, dass niemand garantiert, dass der übergebene cstring nullterminiert ist, oder?
    Daher best practice -> Aufrufer die Länge mitgeben lassen?



  • Interessiert schrieb:

    Hmm, aber ich dachte der Sinn ist es gerade, dass die Funktion selber bestimmt, wie viel zusätzliche chars gebraucht werden. Also auch wie groß das Ziel sein muss.

    Ist das nicht irgendwie komisch, wenn der Aufrufer das selber wissen muss?

    Das ist halt C.
    Man kann ja auch noch einen Wrapper darum schreiben, der das macht.
    Dann wäre eine Rückgabe der Größe des neuen Speichers aber auch sinnvoll.

    Interessiert schrieb:

    Und noch mal die Sache mit dem strlen: Das Problem ist doch, dass niemand garantiert, dass der übergebene cstring nullterminiert ist, oder?
    Daher best practice -> Aufrufer die Länge mitgeben lassen?

    Wenn der String nicht nullterminiert ist, dann ist es kein C-String.
    Du kannst das machen, dann musst du aber auch alle anderen Stringfunktionen ersetzen.

    Wenn die Funktion einen C-String erwartet, aber keinen bekommt, dann ist das ein Fehler.



  • Interessiert schrieb:

    Hmm, aber ich dachte der Sinn ist es gerade, dass die Funktion selber bestimmt, wie viel zusätzliche chars gebraucht werden. Also auch wie groß das Ziel sein muss.

    Ist das nicht irgendwie komisch, wenn der Aufrufer das selber wissen muss?

    Jein.

    Der Punkt ist, dass eine Funktion für _eine_ Sache tun sollte, nicht zwei. Und Speicher zu reservieren, gehört nicht zu einer Funktion, die Unterstriche hinzufügt. Das sind zwei völlig verschiedene Dinge. Bedenke auch: was soll passieren, wenn das Speicherreservieren fehlschlägt? Dieses Problem existiert nicht in einer Funktion, die dafür nicht verantwortlich ist. Außerdem sieht man der Funktion ja nicht an, dass sie Speicher reserviert, der wieder freigegeben werden muss.

    Das "jein" oben, weil es natürlich blöd ist, das wissen zu müssen. Aber man kann das entweder wrappen oder einen guten Default wählen, der groß genug ist.



  • char *markText(char *s, char sel) {
    	char *zeichenkette = s;
    	int slaenge = 0;
    	int anzahlsel = 0;
    	int groesse;
    
    	while(*s) {
    		slaenge++;
    		if(*s == sel) anzahlsel++;
    		s++;
    	}
    
    	s = zeichenkette;
    
    	groesse = slaenge+anzahlsel*2;
    	zeichenkette = malloc(groesse);
    
    	if(!zeichenkette) return 0;
    
    	while(*s) {
    		if(*s == sel) {
    			*zeichenkette++ = '_';
    			*zeichenkette++ = *s;
    			*zeichenkette++ = '_';
    		} else {
    			*zeichenkette++ = *s;
    		}
    		s++;
    	}
    
    	*zeichenkette = '\0';
    
    	return zeichenkette-groesse;
    }
    
    int main() {
    	char *text;
    
    	text = markText("Hello World!", 'l');
    	if(!text) return 1;
    	printf("%s\n", text);
    	free(text);
    
    	return 0;
    }
    


  • Irgendein Dorftrottel findet sich immer.



  • Wo wir doch die ganze ZEit über Nullterminierung gesprochen haben.
    groesse wird zu klein berechnet.

    int slaenge = 1;
    

    Und es ist auch keine Schande mehrere Zeiger zu verwenden.
    Wenn die nicht gleichzeitig gebraucht werden, richtet das der Compiler.



  • Okay, jetzt bin ich vollkommen überzeugt, die Punkte waren sehr plausibel! Danke 👍



  • DirkB schrieb:

    Wo wir doch die ganze ZEit über Nullterminierung gesprochen haben.
    groesse wird zu klein berechnet.

    int slaenge = 1;
    

    Und es ist auch keine Schande mehrere Zeiger zu verwenden.
    Wenn die nicht gleichzeitig gebraucht werden, richtet das der Compiler.

    Man könnte dann auch gleich noch auf zwei der drei int-Variablen und die Berechnung der Buffer-Größe im Anschluss an die erste Schleife verzichten, wenn man 'groesse' zu Beginn mit 1 für die Nullterminierung intialisiert und dann in der Schleife für jedes Zeichen um 1 erhöht und bei Auftreten von 'sel' zusätzlich um 2 erhöht.



  • ich habe nun etwas an meinem Code gearbeitet und mein Momentaner Stand zeigt mir weiterhin noch Fehler, aber verstehe diese noch nicht so Recht bzw kann diese nicht korrekt nachvollziehen und korrigieren.

    Mein momentaner Stand:

    #include <stdio.h>
    #include <string.h>
    
    char *markText(char *s, char sel) {
    
    char s = "Hello World!";
    sel = 'l';
    
    char ubergabe[17];   
    char s2[]= s;
    
    int i;
    int m;
    
        for(i=0,m=0; i<12; ++i,++m) {
    
            s2[i]; 
    
            if(s2[i]==sel) {
                ubergabe[m] = sel ;
                ++m;
                ubergabe[m] = s2[i];
                ++m;
                ubergabe[m] = sel ;
                printf("Ausgabe m gleich: %d \n", m);
            }
    
            if(s2[i]!=sel) {
                ubergabe[m] = s2[i];
                printf("Ausgabe m undgleich: %d \n", m);
    
            }
    
        }   
    
        s = ubergabe;
    
        return(s);
    }
    
    int main () {
    
    char ArrayA[] = "Tschüss";
    char zeichen = 'P';
    
    markText(ArrayA,zeichen);
    
    printf("\n\nAusgabe: %s \n\n", ArrayA);
    
    return 0;
    
    }
    


  • DirkB schrieb:

    Cobain schrieb:

    Es werden mir mehrere Fehler angezeigt.

    Mir nicht. (ich habe das aber auch nicht compiliert, daher weiß ich nicht welche Fehler du meinst)

    Damit war gemeint, dass du die Fehlermeldungen auch postest.

    Wo sind die Unterstriche denn jetzt wieder hin?

    Einem Array kannst du nicht durch Zuweisung ein anderes Array (oder Zeiger) zuweisen.

    Was sollen Zeile 6 und 7?

    Das funktioniert so nicht, da ubergabe nach Zeile 39 (da ist die Funktion zuende) aufhört zu existieren.
    Und wir haben hier schon mehrmals über Nullterminierung von C-Strings geschrieben. Die fehlt auch.

    Du sollst nicht rumraten, sondern vorher ein Konzept aufstellen, dass du dann umsetzt.
    Probier das Ganze mit Bleistift(en) und Papier aus. So ein Stift kannst du auch als Zeiger nehmen.
    BEobachte dich dabei, wann du welche Zeichen kopierst und wann du welche Zeiger weiter schiebst.



  • habe jetzt paar Fehler beheben können. Der Code läuft, aber die bearbeitete Version von Hello World! wird nicht wieder in der main ausgegeben.
    In der Main habe ich zwei char variablen deklariert mit falschen "werten", mir ging es nur darum eine basis zu haben die dann in der Funktion umgeändert wird. Der Grund für dieses Denken war, dass in der Aufgabenstellung nur nach einer Funktion gefragt war und eine Funktion alleine lässt sich nicht einfach compilieren und ausführen.

    #include <stdio.h>
    #include <string.h>
    
    char *markText(char *s, char sel) {
    
    s = "Hello World!";
    sel = 'l';
    
    char ubergabe[17];   
    
    int i;
    int m;
    
        for(i=0,m=0; i<12; ++i,++m) {
    
            //s2[i]; 
    
            if(s[i]==sel) {
                ubergabe[m] = '_' ;
                ++m;
                ubergabe[m] = s[i];
                ++m;
                ubergabe[m] = '_' ;
                printf("Ausgabe m gleich: %d \n", m);
            }
    
            if(s[i]!=sel) {
                ubergabe[m] = s[i];
                printf("Ausgabe m undgleich: %d \n", m);
    
            }
    
        }   
    
        s = ubergabe;
    
        return(*s);
    }
    
    int main () {
    
    char ArrayA[] = "Tschüss";
    char zeichen = 'P';
    
    markText(&ArrayA,zeichen);
    
    printf("\n\nAusgabe: %s \n\n", ArrayA);
    
    return 0;
    
    }
    


  • In der Funktion wird der Text Hello World! korrekt bearbeitet aber nicht wieder in die Main eingeführt.



  • Das ist nun der Code der ausführbar ist, jedoch nicht in die Main zurückgegeben wird.

    #include <stdio.h>
    #include <string.h>
    
    char *markText(char *s, char sel) {
    
    s = "Hello World!";
    sel = 'l';
    
    char ubergabe[17];   
    
    int i;
    int m;
    
        for(i=0,m=0; i<12; ++i,++m) {
    
            if(s[i]==sel) {
                ubergabe[m] = '_' ;
                ++m;
                ubergabe[m] = s[i];
                ++m;
                ubergabe[m] = '_' ;
                printf("Ausgabe m gleich: %d \n", m);
            }
    
            if(s[i]!=sel) {
                ubergabe[m] = s[i];
                printf("Ausgabe m ungleich: %d \n", m);
    
            }
    
        }   
    
        s = ubergabe;
        printf("\n\nAusgabe: %s \n\n", s);
    
        return(s);
    }
    
    int main () {
    
    char ArrayA[] = "Tschüss";
    char zeichen = 'P';
    
    markText(ArrayA,zeichen);
    
    printf("\n\nAusgabe: %s \n\n", ArrayA);
    
    return 0;
    
    }
    

  • Mod

    Wie würdest du denn überhaupt irgendetwas aus einer Funktion zurück geben? Mach mal an einem einfacheren Beispiel vor!



  • funktionsaufruf (&blabla)

    dann call by reference

    und dann am ende der Funktion return (*blabla2)

    Ich habe es nach diesem Schema versucht, jedoch werden mir dann aufeinmal mehrere Fehler angezeigt, sprich falscher Funktionsaufruf etc



  • Du nutzt den Rückgabewert von markText in main nicht.

    Die Adresse von ArrayA wird in deiner Funktion im Zeiger s als Kopie gespeichert.

    In Zeile 6 zeigt dann dieser Zeiger auf "Hello World!". Der Zeiger zeigt woanders hin. Da wird keine Zeichenkette kopiert! GRUNDLAGEN

    Damit geht schon mal jeder Bezug zu ArrayA verloren.

    Ab Zeile 35 zeigt s dann auf ubergabe
    Du gibst demnach in Zeile 39 die Anfangsadresse von ubergabe zurück.
    Aber danach ist der Speicherbereich von ubergabe ungültig. Du darfst ihn nicht mehr benutzen.



  • Cobain schrieb:

    funktionsaufruf (&blabla)

    dann call by reference

    und dann am ende der Funktion return (*blabla2)

    Ich habe es nach diesem Schema versucht, jedoch werden mir dann aufeinmal mehrere Fehler angezeigt, sprich falscher Funktionsaufruf etc

    Und wie sieht es bei call by value mit Rückgabewerte aus?

    Vergiss das Schema mal, das ist Schrott wie du selber merkst.
    Wann beim Funktionsaufruf und beim rerturn ein & oder * hinkommt, hängt von den Typen der Variablen und Argumente ab.
    Vor allem hat "call by reference" nichts mit return zu tun.


  • Mod

    Cobain schrieb:

    funktionsaufruf (&blabla)

    dann call by reference

    und dann am ende der Funktion return (*blabla2)

    Eben nicht. Du wirfst alles durcheinander.

    Schreib mal wirklich zwei kleine Programme, welche demonstrieren:
    a) Funktion gibt einen Wert zurück (z.B. 5), dieser wird irgendwie weiter benutzt (z.B. ausgegeben).
    b) Funktion verändert den Wert einer Variablen (z.B. auf 5), diese Variable wird irgendwie weiter benutzt (z.B. ausgegeben).



  • void zahlenausgabe(int n) {
    printf("Ausgabe: %d",n);
    }

    int main () {
    int zahl = 5;
    return 0;
    }

    void zahlenausgabe(int *n) {
    *n = 10;
    }

    int main () {
    int zahl = 5;
    zahlenaendern(&zahl);
    printf("Ausgabe: %d",zahl);
    return 0;
    }


Anmelden zum Antworten