Verständisfrage zu Pointern und char[]

Schnelle objektorientierte, kompilierende Programmiersprache.
Zenerid
Beiträge: 38
Registriert: Do Feb 05, 2015 4:15 pm

Re: Verständisfrage zu Pointern und char[]

Beitrag von Zenerid » So Mai 08, 2016 2:23 am

Hmm .. mir ist im letzten Beitrag auch ein kleiner Code Fehler Tag passiert. Kann mir denn keiner die letzten Fragen beantworten bzw. du Xin? Kann ja auch sein, dass du den neuen Beitrag übersehen hast? Ich will hier keinesfalls spammen aber es ist ja schon einige Tage her.

Wäre es eigentlich auch möglich einen char * an eine Methode zu übergeben und diesen dann wieder an mehrere Methoden zu übergeben und dann auch so, dass der Buffer so bleibt, wie er in der Methode ist, also weiterhin auf die selbe Stelle zeigt?

Code: Alles auswählen

void myFunction(char *ptr) {
    myFunction2(ptr);
    myFunction3(ptr);
    myFunction4(ptr);
    myFunction5(ptr);
    // usw ...
}
oder wäre das so nicht möglich, ohne die Variable ptr vorher in einem char * zu speichern, also so:

Code: Alles auswählen

void myFunction(char *ptr) {
    char *_ptr = ptr;

    myFunction2(_ptr);
    myFunction3(_ptr);
    myFunction4(_ptr);
    myFunction5(_ptr);
    // usw ...
}
Geht das überhaupt? Ich habe das bei mir nämlich mal versucht, weil ich mich halt weiter mit Pointern beschäftigen wollte aber selbst wenn ich dann den Pointer mit &_ptr übergebe, scheint der Pointer trotzdem immer noch am Anfang zu stehen, obwohl ich mich in den Methoden myFunction mit

Code: Alles auswählen

ptr++ 
oder auch

Code: Alles auswählen

ptr += was auch immer
weiter bewege. Den Stand würde ich halt gerne auch an die andeen Methoden weiter geben. Geht das?

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Verständisfrage zu Pointern und char[]

Beitrag von cloidnerux » So Mai 08, 2016 10:01 am

Wäre es eigentlich auch möglich einen char * an eine Methode zu übergeben und diesen dann wieder an mehrere Methoden zu übergeben und dann auch so, dass der Buffer so bleibt, wie er in der Methode ist, also weiterhin auf die selbe Stelle zeigt?
Ja ist es, du musst dir nur bewusst sein, welchen Pointer du wohin übergibst.
Übergibst du eine Variable an eine Funktion, so wird der Inhalt der Variable Kopiert. Übergibst du einen Pointer an eine Funktion, so wird der Inhalt des Pointers(die Speicheradresse) kopiert und in einem neuen Pointer, der lokal für die Funktion ist, abgelegt.
Geht das überhaupt? Ich habe das bei mir nämlich mal versucht, weil ich mich halt weiter mit Pointern beschäftigen wollte aber selbst wenn ich dann den Pointer mit &_ptr übergebe, scheint der Pointer trotzdem immer noch am Anfang zu stehen, obwohl ich mich in den Methoden myFunction mit
CODE: ALLES AUSWÄHLEN
Wenn du &_ptr übergibst, hast du einen Pointer auf einen Pointer, nicht unbedingt das was du willst.
Wie kommst du darauf, dass es nicht Funktionert?
Mit diesem Code funktioniert es:

Code: Alles auswählen

#include "stdio.h"

void myFunc2(const char * ptr)
{
	printf("%s", ptr);
}

void myFunc(const char * ptr)
{
	ptr += 5;
	myFunc2(ptr);
}

int main()
{
	const char * text = "Hallo Welt";
	myFunc(text);
	return 0;
}
Ausgabe:

Code: Alles auswählen

 Welt
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Verständisfrage zu Pointern und char[]

Beitrag von Xin » So Mai 08, 2016 11:19 am

Zenerid hat geschrieben:Kann mir denn keiner die letzten Fragen beantworten bzw. du Xin? Kann ja auch sein, dass du den neuen Beitrag übersehen hast? Ich will hier keinesfalls spammen aber es ist ja schon einige Tage her.
Solange Du Fragen hast, ist das kein Spam. Es kann durchaus sein, dass ich irgendwo die Frage lese aber für eine brauchbare Antwort gerade keine Zeit habe. Dann ist die Frage aber nicht mehr "neu" und ich vergesse das evtl. Kann passieren. Sollte sonst keiner Antworten ist ein "push" durchaus akzeptabel. Du bist mir nämlich hier wirklich durch die Lappen gegangen.

Zenerid hat geschrieben:Zuerst einmal die Frage wann man denn eigentlich Speicher für einen Pointer freigeben muss:
Immer dann, wenn Du Speicher mit malloc alloziiert hast oder eine Funktion dazu beauftragt hast, Dir Speicher zu alloziieren (die dann eben malloc nutzt).

In beiden Fällen bekommst Du einen Zeiger zurück. C besitzt keine Kennzeichnung zur Verantwortlichkeit des Zeigers. Du musst also wissen, welche Funktionen Dir neuen Speicher zurück geben und welche Funktionen einfach einen Zeiger zurückgeben auf Speicher, denen Du ihnen vorher übergeben hast.

strrchr sucht so beispielsweise nach einem Zeichen in einem übergebenen String und gibt Dir die Adresse des Zeichens zurück - also eine Adresse in Deinem String. strdup hingegen kopiert einen String - legt also neuen Speicher an.
Zenerid hat geschrieben:Zuletzt noch eine Frage und zwar was passiert wenn ich einen Pointer an eine Methode übergeben, also so:

Code: Alles auswählen

char *temp;
str_to_upper(temp);

Code: Alles auswählen

int str_to_upper(char * buffer) {
    while ( *buffer ) {
	*buffer = toupper(*buffer);
	++buffer;
    }
    return 0;
}
Dann ist das doch kein Call by reference, sondern einfach nur ein Call by Value oder nicht? Der ursprüngliche pointer wird doch dann nicht verändert, es sei denn ich füge das & Zeichen bei dem Methodenaufruf mit ein, sprich er soll das an der Speicheradresse speichern?
str_to_upper(&temp);[/code]
Es gibt in C kein "Call-By-Reference", ganz einfach weil es in C keine Referenzen gibt. Es gibt Pointer. Pointer sind Werte und die werden kopiert: Call-By-Value. Weil es Pointer sind, kann man sie aber als Referenz missbrauchen. Der &-Operator gibt Dir die Adresse von einem Wert zurück, was dann eben ein "Zeiger auf Datentyp des Wertes" ist und keine Referenz.
Hier gilt es also nicht nur ein & vor den Parameter zu setzen, sondern auch einen Zeiger auf den Wert zu erwarten.

Referenzen und Pointer sind praktisch das gleiche, aber sie sind in der Theorie nicht dasselbe. :)

=call&s[]=by&s[]=value]Call By Value

Zenerid hat geschrieben:Wäre es eigentlich auch möglich einen char * an eine Methode zu übergeben und diesen dann wieder an mehrere Methoden zu übergeben und dann auch so, dass der Buffer so bleibt, wie er in der Methode ist, also weiterhin auf die selbe Stelle zeigt?

Code: Alles auswählen

void myFunction(char *ptr) {
    myFunction2(ptr);
    myFunction3(ptr);
    myFunction4(ptr);
    myFunction5(ptr);
    // usw ...
}
Da ptr ein Value ist, wird er an die Funktionen kopiert. In myFunction bleibt er unverändert. Das muss aber nicht für den Wert gelten, auf den er zeigt.
Zenerid hat geschrieben:oder wäre das so nicht möglich, ohne die Variable ptr vorher in einem char * zu speichern, also so:

Code: Alles auswählen

void myFunction(char *ptr) {
    char *_ptr = ptr;
    ...
}
Geht das überhaupt?
Gehen schon, macht aber keinen Sinn, da ptr außerhalb der Funktion nicht verändert werden kann, außer Du übergibst einen Pointer auf den Pointer per &ptr;
Zenerid hat geschrieben:Ich habe das bei mir nämlich mal versucht, weil ich mich halt weiter mit Pointern beschäftigen wollte aber selbst wenn ich dann den Pointer mit &_ptr übergebe, scheint der Pointer trotzdem immer noch am Anfang zu stehen, obwohl ich mich in den Methoden myFunction mit

Code: Alles auswählen

ptr++ 
oder auch

Code: Alles auswählen

ptr += was auch immer
weiter bewege. Den Stand würde ich halt gerne auch an die andeen Methoden weiter geben. Geht das?
Hier verstehe ich die Frage nicht. ^^
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Zenerid
Beiträge: 38
Registriert: Do Feb 05, 2015 4:15 pm

Re: Verständisfrage zu Pointern und char[]

Beitrag von Zenerid » So Mai 29, 2016 1:48 pm

Gut das dass mit dem push okay ist. Eigentlich mache ich sowas auch nicht gerne und ich bin auch nicht ungeduldig aber einen push nach einer Woche+ finde ich eigentlich wohl vertretbar. :)

@cloidnerux
Hmm .. du hast doch jetzt aber auch in der Funktion selbst schon ptr += 5 gemacht, anstatt das in einer anderen Funktion zu machen, wie ich das vorhatte. So hatte ich das ja auch erst gemacht aber wenn ich das in der Funktion myFunction2 mache, dann steht der Pointer bei der Übergabe an myFunction3 nicht mehr da, wo er vorher war, also ebend wo er in myFunction2 war. Wenn dann, dann wollte ich das schon so haben:

Code: Alles auswählen

void myFunction(char *ptr) {
    myFunction2(ptr); 
    myFunction3(ptr); // Hier steht der Pointer schon nicht mehr da, wo er in myFunction2 war
    myFunction4(ptr);
    myFunction5(ptr);
    // usw ...
}
Dsa habe ich vorher durchaus schon so getestet und bei mir hat es so auf jeden Fall nicht funktioniert. Mit & hat es aber auch nicht funktioniert.

@Xin
Das mit dem wann man wann Speicher allozieren muss und wann nicht habe ich jetzt verstanden, denke ich. Bei strchr hat man ja dann auch echt nur den Zeiger auf die Stelle und wenn man wirklich etwas speichern will, also neuen Inhalt oder wie bei strdup Funktion dann alloziert man sich halt Speicher.

Mit der letzten Frage meinte ich eigentlich das, was ich vorher auch schon gemeint habe. Ich habe diesen Pointer ptr wie oben im Code-Beispiel gezeigt auch so an die Funktion übergeben und dann einfach in der Funktion myFunction2 sowas wie

Code: Alles auswählen

ptr += 5
gemacht. Wenn ich dann aber myFunction3(ptr) aufgerufen habe, dann war der Pointer ebend wieder am Anfang, statt wie z.B bei "Hallo Welt" mit ptr += 5 auf "Welt", ebend auf "Hallo". So wollte ich das ebend haben. ;)
Das war meine Frage.

Auch noch einmal eine Frage anhand eines Beispiels. Wenn ich diese Funktion hier habe:

Code: Alles auswählen

void chrrep(char* str, char chr, char repChar) {
	for (; *str; str++) {
		if (*str == chr)
			*str = repChar;
	}
}
Dann sage ich ja ststr++ aber ist das nicht auch eigentlich gefährlich oder achtet c da auch auf die Grenze? Kann ich mich so durch den gefahrlos durch den Inhalt eines Pointers bewegen (vorausgesetzt der Pointer ist != NULL, was ja in der Funktion nicht überprüft wird)? Ich habe die Funktion auch mal getestet und es funktioniert auch anscheinend aber weiß c dann in dem Fall, wann str++ nicht mehr geht, also wo die Speicheradrese zuende ist oder wie kann man das sagen?
Da wird der str bzw. der Inalt des Pointers? ja auch verändert und ebend der Inhalt an der Stelle *str mit dem char ersetzt, den man der Funktion übergibt, obwohl man da den Pointer ja nicht mit & übergibt.

Zenerid
Beiträge: 38
Registriert: Do Feb 05, 2015 4:15 pm

Re: Verständisfrage zu Pointern und char[]

Beitrag von Zenerid » Di Jun 14, 2016 8:35 am

Es ist mir wieder ein wenig unangenehm ...
push ...

Benutzeravatar
cloidnerux
Moderator
Beiträge: 3123
Registriert: Fr Sep 26, 2008 4:37 pm
Wohnort: Ram (Gibts wirklich)

Re: Verständisfrage zu Pointern und char[]

Beitrag von cloidnerux » Di Jun 14, 2016 8:49 am

Es ist mir wieder ein wenig unangenehm ...
Muss es nicht.
Wenn ich dann aber myFunction3(ptr) aufgerufen habe, dann war der Pointer ebend wieder am Anfang, statt wie z.B bei "Hallo Welt" mit ptr += 5 auf "Welt", ebend auf "Hallo". So wollte ich das ebend haben. ;)
Und ich habe schon erklärt, warum es nicht funktioniert. Parameter die an eine Funktion übergeben werden, werden kopiert. Der Pointer mit dem deine myFunctionX arbeiten ist eine Kopie von "ptr". Dementsprechend wirkt sich eine Änderungen auf diese Kopien nicht auf deinen Pointer "ptr" aus.
Wenn du direkt deinen Pointer manipulieren willst, musst du einen Pointer auf deinen Pointer "ptr" übergeben.

Code: Alles auswählen

void myFunc(char * ptr)
{
   myFunc2(&ptr);
}
void myFunc2(char ** ptr)
{
    (*ptr) += 5;
    char * data = *ptr;
    printf("%s", data);
}
Die Funktion mxFunc2 erhält nun einen Zeiger auf eine Speicherstelle, die wiederum einen Zeiger beinhaltet, der auf einen char-String zeigt. Der Zeiger auf den &ptr zeigt ist eben die Speicherstelle in dem ptr gespeichert ist.

Oder alternativ: Es ist immer unschön wenn Funktionen sich implizit auf deine Variablen auswirken. Stattdessen kann deine Funktionen einen Offset zurück geben, den du auf deinen Pointer addierst:

Code: Alles auswählen

void myFunc(char * ptr)
{
    ptr += myFunc2(ptr);
    ptr += myFunc3(ptr);
}

int myFunc2(char * ptr)
{
    //do something
    return index;
}
Redundanz macht wiederholen unnötig.
quod erat expectandum

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8858
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Verständisfrage zu Pointern und char[]

Beitrag von Xin » Di Jun 14, 2016 9:19 am

Zenerid hat geschrieben:Es ist mir wieder ein wenig unangenehm ...
push ...
Schließe mich cloidnerux an: Du stellst keine idiotischen Fragen, mir ist Deine Rückfrage nur durchgerutscht. War keine Absicht.
Zenerid hat geschrieben:@Xin
Das mit dem wann man wann Speicher allozieren muss und wann nicht habe ich jetzt verstanden, denke ich. Bei strchr hat man ja dann auch echt nur den Zeiger auf die Stelle und wenn man wirklich etwas speichern will, also neuen Inhalt oder wie bei strdup Funktion dann alloziert man sich halt Speicher.
Yepp.

Mit der letzten Frage meinte ich eigentlich das, was ich vorher auch schon gemeint habe. Ich habe diesen Pointer ptr wie oben im Code-Beispiel gezeigt auch so an die Funktion übergeben und dann einfach in der Funktion myFunction2 sowas wie

Code: Alles auswählen

ptr += 5
gemacht. Wenn ich dann aber myFunction3(ptr) aufgerufen habe, dann war der Pointer ebend wieder am Anfang, statt wie z.B bei "Hallo Welt" mit ptr += 5 auf "Welt", ebend auf "Hallo". So wollte ich das ebend haben. ;)
Das war meine Frage.[/quote]
Vielleicht mal ganz grundsätzlich als allgemeines Verständnisproblem: Ein Identifier (z.B. der Name einer Variable) gilt immer im lokalen Namensraum, zum Beispiel innerhalb einer Funktion. Ein Identifier spricht immer eine Speicherstelle an. Ein "ptr" in Funktion 1 ist dabei aber eben nicht das gleiche wie "ptr" in Funktion 2. "ptr" in Funktion 2 ist beispielsweise Parameter1, dann beedutet "ptr", dass Du die Speicherstelle für Parameter1 meinst. In Funktion1 hingegen ist es eine lokale Variable, dann meint "ptr" dort, dass Du die lokale Variable meinst.

cloidnerux beschreibt das mit einem Pointer-auf-Pointer (char **). Hier steht in der Speicherstelle des Parameters (Typ char **) der Zeiger auf eine Speicherstelle mit Typ (char*), die Du in einer anderen Funktion ebenfalls mit "ptr" ansprichst. Weil die Datentypen unterschiedlich sind, zeigt sich hier aber auch klarer, dass "ptr" in beiden Fällen unterschiedliche Variablen sein müssen.
Zenerid hat geschrieben: Auch noch einmal eine Frage anhand eines Beispiels. Wenn ich diese Funktion hier habe:

Code: Alles auswählen

void chrrep(char* str, char chr, char repChar) {
	for (; *str; str++) {
		if (*str == chr)
			*str = repChar;
	}
}
Dann sage ich ja ststr++ aber ist das nicht auch eigentlich gefährlich oder achtet c da auch auf die Grenze? Kann ich mich so durch den gefahrlos durch den Inhalt eines Pointers bewegen (vorausgesetzt der Pointer ist != NULL, was ja in der Funktion nicht überprüft wird)?
Die Funktion geht in der For-Schleife davon aus, dass str mit einem Nullbyte endet (siehe zweiter Parameter von for).

C achtet aus Prinzip niemals auf Grenzen, außer Du programmierst das - und das ist hier geschehen mit dem 2. Parameter von for.
Zenerid hat geschrieben:Ich habe die Funktion auch mal getestet und es funktioniert auch anscheinend aber weiß c dann in dem Fall, wann str++ nicht mehr geht, also wo die Speicheradrese zuende ist oder wie kann man das sagen?
Da wird der str bzw. der Inalt des Pointers? ja auch verändert und ebend der Inhalt an der Stelle *str mit dem char ersetzt, den man der Funktion übergibt, obwohl man da den Pointer ja nicht mit & übergibt.
Der Pointer wird str kommt als Kopie in die Funktion. Die Kopie wird verändert. Das Original (also die Variable, die Du beim Aufruf von chrrep "übergibst" (korrekteres Wort "kopierst"!), bleibt unverändert.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Antworten