Pointer-Einsatz in einer Funktion



  • Hay liebe Community,
    ich hätte mal eine Frage zu einer Aufgabe die ich unten mit meinem momentanen Code posten werde. Mir gelingt es nicht die folgende Aufgabe zu lösen, mir werden nur Fehler angezeigt. Ich hoffe jemand kann mir weiterhelfen.

    Aufgabenstellung:

    Entwickeln Sie in C ein Unterprogramm markText, das in einem String s (char-Array) jedes Vorkommen eines als Parameter übergebenen Buchstabens durch eine Unterstreichung davor und dahinter markiert. Der Prototyp des Unterprogramms lautet: char * markText( char* s, char sel). Der Rückgabewert ist ein pointer auf das neu erstellte char-Array, in dem die Markierung vorgenommen wurde.
    Beispiel: Mit s="Hello world!" und sel = 'l' wird erzeugt: "He_l__l_o wor_l_d!"
    Hinweis: Stellen Sie zunächst fest, wie oft das übergebene Zeichen vorkommt. Ermitteln Sie damit die Größe des neuen Arrays und legen Sie dieses Array an.
    Verwenden Sie keine Bibliotheksfunktionen für die Stringoperationen außer strlen!

    Mein momentaner Code:

    #include <stdio.h>
    
    char *markText ( char* s, char sel) {
    
        int i;
        s = "Hello World";
        sel ='l';
        char Text[100];
    
        for (i=0; i<s[i]; ++i) {
    
            s[i];
    
                if (s[i]==sel) {
                    m++;
                }
    
                if (s[i]!=sel) {
                    Text[m] = s[i];
                }        
        }
    
        return (*s);
    
    }
    
    int main () {
    
     int Arr[] = "Text";
    
    char Buchstabe ='s';
    
    int *pfeil;
    int *pfeil2;
    
    pfeil = &Arr;
    pfeil2 = &Buchstabe;
    
    markText(&pfeil,&pfeil2);
    
    printf("Ausgabe: %s ", Arr);
    
    return 0;
    
    }
    

  • Mod

    Cobain schrieb:

    Der Prototyp des Unterprogramms lautet: char * markText( char* s, char sel). Der Rückgabewert ist ein pointer auf das neu erstellte char-Array, in dem die Markierung vorgenommen wurde.

    Hi. Der Aufgabensteller hat 0 Ahnung von C. Die Aufgabe ist daher nicht wirklich gut lösbar, man kann bloß ein wackeliges Gerüst bauen, um irgendwie der Aufgabe nahe zu kommen. Halten wird es nicht.

    Dein Code ist leider ähnlich. Man sieht, dass du von deinem Lehrer gelernt hast. Sieht aus wie eine vom Zufallsgenerator erzeugte Folge verschiedener C-ähnlicher Zeilen. Code ist aber Logik pur. Wenn du selber Code schreibst, dann musst du ihn auch verstehen. Du muss von jedem einzelnen Zeichen genau wissen, wo und warum du es setzt.

    Ich sehe daher leider keinen Ansatz um dir zu helfen, außer dir zu sagen, dass du mit C eigentlich von vorne anfangen kannst und das gelernte besser vergisst. Wenn du konkrete Fragen hättest, könnte man diese vielleicht beantworten, so allgemein kann man zu dem gezeigten Code nur sagen, dass jede einzelne Zeile falsch ist.



  • SeppJ schrieb:

    Cobain schrieb:

    Der Prototyp des Unterprogramms lautet: char * markText( char* s, char sel). Der Rückgabewert ist ein pointer auf das neu erstellte char-Array, in dem die Markierung vorgenommen wurde.

    Hi. Der Aufgabensteller hat 0 Ahnung von C. Die Aufgabe ist daher nicht wirklich gut lösbar, man kann bloß ein wackeliges Gerüst bauen, um irgendwie der Aufgabe nahe zu kommen. Halten wird es nicht.

    Aus Interesse: Magst Du eben erklären, wieso du das so drastisch siehst (plus den starken Schlussfolgerungen (Lehrer hat keine Ahnung))?
    Nicht weil ich widersprechen will, sondern, wie gesagt, aus Interesse.

    Geht es Dir um die unglimpfliche Situation mit der Frage, wer für das free sorgt oder was genau?

    Danke 🙂



  • Möglicherweise kommst du einer Lösung viel näher, wenn du die Hinweise aus der Aufgabe auch umsetzt.

    Aufgabe schrieb:

    Der Rückgabewert ist ein pointer auf das neu erstellte char-Array

    Lokale Arrays verlieren am Ende der Funktion ihre Gültigkeit. Daher kann hier nur ein dynamischer Speicherbereich gemeint sein.

    Damit ein Rückgabewert auch sinnvoll ist, muss er auch verarbeitet werden. (einer Variablen zugewiesen, einer Funktion übergeben oder in einem Term verarbeitet)

    Aufgabe schrieb:

    Hinweis: Stellen Sie zunächst fest, wie oft das übergebene Zeichen vorkommt. Ermitteln Sie damit die Größe des neuen Arrays und legen Sie dieses Array an.
    Verwenden Sie keine Bibliotheksfunktionen für die Stringoperationen außer strlen!

    Wo machst du das?

    Aufgabe schrieb:

    .... durch eine Unterstreichung davor und dahinter markiert.

    Wo kommt in deiner Funktion der Unterstrich vor?

    Deine Funktion soll ein char* zurückgben, *s ist vom Typ char . (Das sind verschiedene Typen).
    Zudem soll der neue Text zurückgegeben werden. In s steht das Original.

    Deine main deutet darauf hin, dass du die Fehlermeldungen nicht richtig gelesen hast.
    Und stelle noch den Warnlevel auf Maximum.



  • Interessiert schrieb:

    Aus Interesse: Magst Du eben erklären, wieso du das so drastisch siehst (plus den starken Schlussfolgerungen (Lehrer hat keine Ahnung))?
    Nicht weil ich widersprechen will, sondern, wie gesagt, aus Interesse.

    Ich vermute, dass die Antwort auf die pedantische Unterscheidung der in der Alltagssprache von Programmierern Synonym verwendeten Begriffe "Zeiger auf char" einerseits und "dynamisches char-Array" andererseits hinauslaufen wird.

    Von 0 Ahnung zu Schreiben halte ich viel zu weit hergeholt.
    Ich hätte btw.

    das in einem String s
    

    zitiert, weil es diesen Datentypen in C nicht gibt.
    MfG
    🙂


  • 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.


Anmelden zum Antworten