Pointer-Einsatz in einer Funktion


  • Mod

    Interessiert schrieb:

    ...

    Guck dir die Vorgaben an, zum Beispiel die Funktionssignatur. Vergleiche sie mit best-practices in C. Die Schnittmenge sollte ungefähr leer sein.

    Das mit dem free hast du schon erkannt. Warum ist s nicht const char* ? Dass hier die Verwendung von strlen angeregt wird ist ebenfalls ein bisschen komisch.

    edit: Nichts von dem, was vermut0r schrieb, kam mir in den Sinn.



  • ich habe die Aufgabenstellung innerhalb der main gelöst und wollte mich nun dran machen, dass ich alles in die Funktion einbaue, aber so ganz komme ich auch nicht weiter. Es werden mir mehrere Fehler angezeigt. Ich habe die Funktion jetzt leer gelassen. Mir fehlt der Ansatz mit den pointern. Mit Pointern kenne ich mich aus, aber in Kombination mit arrays komme ich komplett durcheinander. Ich verstehe auch nicht wieso innerhalb des Funktionnamens ein pointer ist also vor dem markText.

    #include <stdio.h>
    #include <string.h>
    
    char *markText ( char* s, char sel) {
    
    }
    
    int main () {
    
    int i;
    int m;
    char s[] = {"Hello World!"};
    char ubergabe[16];
    
    for(i=0,m=0; i<12; ++i,++m) {
    
        s[i]; 
    
        if(s[i]=='o') {
            ubergabe[m] = '_' ;
            ++m;
            ubergabe[m] = s[i];
            ++m;
            ubergabe[m] = '_' ;
            printf("Ausgabe m: %d \n", m);
        }
    
        if(s[i]!='o') {
            ubergabe[m] = s[i];
        }
    
    }
    
    printf("\n\nAusgabe: %s \n\n", ubergabe);
    
    return 0;
    
    }
    


  • Cobain schrieb:

    Mit Pointern kenne ich mich aus, aber in Kombination mit arrays komme ich komplett durcheinander.

    DAs widerspricht sich aber

    Cobain schrieb:

    Ich verstehe auch nicht wieso innerhalb des Funktionnamens ein pointer ist also vor dem markText.

    Das gehört zum Rückgabetyp.
    Folgende Definitionen sind identisch:

    char *markText( char* s, char sel)
    char * markText( char* s, char sel)
    char* markText( char* s, char sel)
    

    Es wird also ein char* (Pointer to char) zurückgegeben.

    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)

    Es kann sowas sein wie "Anweisung und Effekt"

    kennst du eigentlich else ?

    Die Aufgabe war für beliebig lange Texte und bliebige Zeichen gestellt. Nicht nur 12 Zeichen und 'o' und zwei Vorkommen.

    Und Standard-Stringfunktionen (dazu gehört auch printf mit %s) kannst du auf uebergabe nicht anwenden - Oder der Platz in ubergabe ist zu knapp.

    Nach fast einem Jahr solltest du dich mit C-Strings aber auskennen.



  • SeppJ schrieb:

    Interessiert schrieb:

    ...

    Guck dir die Vorgaben an, zum Beispiel die Funktionssignatur. Vergleiche sie mit best-practices in C. Die Schnittmenge sollte ungefähr leer sein.

    Das mit dem free hast du schon erkannt. Warum ist s nicht const char* ? Dass hier die Verwendung von strlen angeregt wird ist ebenfalls ein bisschen komisch.

    edit: Nichts von dem, was vermut0r schrieb, kam mir in den Sinn.

    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?



  • 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


Anmelden zum Antworten