char*-Zeiger Arithmetik
-
Hallo,
es ist ein wenig her, dass ich mit C gearbeitet habe. Ich habe eine Frage bzgl. Pointerarithmetik.
Wenn ich mir dieses Beispiel angucke:
/* strrchr example */ #include <stdio.h> #include <string.h> int main () { char str[] = "This is a sample string"; char * pch; pch=strrchr(str,'s'); printf ("Last occurence of 's' found at %d \n",pch-str+1); return 0; }
Dann wird in der Ausgabe die Adresse des gefunden Zeichens die Adresse des ersten Zeichens des Strings abgezogen, damit die Position bestimmt werden kann. (Das +1 vernachlässige ich mal. Ist irrelevant).
Ich habe etwas ähnliches programmiert, das mir etwas aus dem String ausschneidet -z.b. "sample".
Nur das wesentliche beschrieben:
char* ptr1; // start substring char* ptr2; // ende substring int start; // start substring int end; // ende substring int length; char tmp[200]; strcpy(tmp, "C:\temp\bla\mylog.txt"); ptr1 = (char*) strrchr(tmp, '\\'); ptr2 = (char*) strrchr(tmp, '.'); start = ptr1 - tmp +1; end = ptr2 - tmp; length = end - start;
Jetzt habe ich die Länge von "mylog".
Jetzt möchte ich aber den ersten Teil, also "C:\temp\bla\", haben.
Wenn ich jetzt start = tmp; mache, haut das nicht hin - "illegal types". Klar, ist ja ein char-Pointer und start ein integer. Also start = &tmp, damit ich die Adresse des ersten Zeichens bekomme. Dann habe ich aber anscheinend "pointer to pointer char". Wieso haut letzteres nicht hin, wenn ich ihm die Adresse gebe?! Funktioniert doch im ersten Beispiel auch.Danke für eure Hilfe!
MfG
Sdy
-
Lass dir doch mal start und end ausgeben.
-
Hat sich schon erledigt.
Wie man die Länge von "C:\temp\bla" zu bekommen, ist ja schon im Beispiel beschrieben. (Hatte Brett vorm Kopf).
Und um die Adresse des ersten Zeichens der int-Variablen zuzuweisen, hat mir ein cast geholfen:
int start = (int)&tmp; // = (int)&tmp[0]
Wenn ich etwas falsches beschrieben habe, dann gerne berichtigen
Mfg
Sdy
-
Im ersten Beispiel ist aber auch kein &. tmp ist vom Typ char[200]. Ein Array ist kein Zeiger! Entsprechend ist &tmp ein Zeiger auf char[200], kein Zeiger auf char. Aber Arrays haben die Eigenschaft in fast jedem Kontext (der Adressoperator ist eine der wenigen Ausnahmen) sich wie ein Zeiger auf ihr erstes Element zu verhalten, das heißt tmp selber verhält sich wie &tmp[0]. Das ist auch das, was im ersten Beispiel passiert. Also den Adressoperator einfach weglassen.
Der Formatspezifizierer für Pointer bei printf ist %p, nicht %d.
Die Casts sind total unnötig und vertuschen eventuelle Fehler. Dies ist schließlich nicht C++, du brauchst void* nicht umzucasten (und in C++ würdest du niemals so wie hier vorgehen). strchr gibt aber sowieso schon den passenden Pointertyp zurück, daher sind die Casts sogar doppelt falsch.
-
sheddy schrieb:
Und um die Adresse des ersten Zeichens der int-Variablen zuzuweisen, hat mir ein cast geholfen:
int start = (int)&tmp; // = (int)&tmp[0]
Das ist fast so schlimm wie das Ausgeben von Pointern mittels %d. Das fliegt dir in üblichen 64-Bit Systemen um die Ohren. Mit Pointern kannst du wunderbar Differenzen berechnen, die dann einen arithmetischen Wert haben. Warum willst du also vorher den Pointer selbst in einen arithmetischen Wert umwandeln? (Falls, du unbedingt einen Zahlenwert zu einem Pointer braucht, und das sollte eigentlich nicht vorkommen, dann nimm intptr_t aus stdint.h).
Ein Cast in C heißt für den Compiler immer "Halt die Fresse, auch wenn es falsch aussieht, ich, der Programmierer, dein Gott, weiß es besser". Du benutzt sehr viele Casts. Weißt du wirklich alles besser als dein Compiler?
-
SeppJ schrieb:
tmp ist vom Typ char[200]. Ein Array ist kein Zeiger! Entsprechend ist &tmp ein Zeiger auf char[200], kein Zeiger auf char.
Jein, denn ein
char *z = tmp + 1;
funktioniert wie ein char* und nicht wie bei einem char[200] zu erwarten wäre.
Ciao MM
-
sheddy schrieb:
Jetzt möchte ich aber den ersten Teil, also "C:\temp\bla\", haben.
Was heisst denn 'haben' für Dich? Den String? Die Länge?
Wenn Du ein
*ptr1++ = '\0'; printf( "Pfad: %s\nDatei: %s\n", tmp, ptr1 );
schreibt, teilst Du in Pfad und Dateiname. Aber Du machst den tmp-absoluten Dateipfad damit 'kaputt'.
Ciao MM
-
Danke für die Antworten. Jetzt meine Begründungen zu meinem Vorgehen.
1. Ich habe doch nie einen Pointer mit printf() ausgegeben. Um die Adresse auszugeben, würde ich selbstverständlich %p verwenden. In dem Beispiel aus der C++-Referenz geben sie doch m.E. auch nicht die Adresse, sondern die genaue Position (in der menschlichen Zählweise, also von 1 an) im String an.
2. Zu dem Cast und doppelt falsch von strrchr. Ich habe in der Referenz gesehen, dass ein char* zurückgegeben wird. Jedoch bekomme ich bei
char* ptr = strrchr("\\");
einen "operands of = have illegal types `pointer to char' and `int'" Fehler. Erst der Cast ermöglicht mir die richtige Verwendung, wie es sein soll.
3. Zeiger auf Array bzw. Arrays sind keine Zeiger
Mitint start = (int)&tmp; // = (int)&tmp[0]
wollte ich eigentlich nur den Anfang des Strings haben. Was ich jedoch schon mit ptr1-tmp (die Adresse des gefundenen Zeichens durch strrchr minus die Adresse des ersten Elements des Strings).
Vielleicht habe ich mich auch falsch ausgedrückt. Der Fehler war einfach, dass ich die Position des Zeichens mit der Adresse verwechselt habe.Mein Verständnis von Zeigern und Arrays ist:
int nums[] = {1,2,3,4,5,6}; int* ptr; ptr =& nums[0]; // gleichbedeutend zu ptr=element
Die Frage, die sich mich stellt, ist jedoch:
Warum kann ich folgendes machen?
end = ptr2 - tmp;
Es ist eine doch Adressendifferenz und wird einem integer zugewiesen, wie es im Beispiel gemacht wird. Wieso kann ich dann nicht einfach
end = tmp; // bezogen auf das obere Zahlenbeispiel ("gleichbedeutend...")
machen?
Einerseits ist es klar: Ich versuche ein char-Array einem integer zuzuweisen. Andererseits weise ich wie in dem Beispiel der C++-Referenz dem integer auch nur eine Adresse zu. Nur, dass ich nun keine Pointerarithmetik habe. Wo habe ich da meinen Denkfehler?
Viele Dank für deine Mühe
-
Martiniclan schrieb:
SeppJ schrieb:
tmp ist vom Typ char[200]. Ein Array ist kein Zeiger! Entsprechend ist &tmp ein Zeiger auf char[200], kein Zeiger auf char.
Jein
Bitte aufmerksam lesen.
SeppJ schrieb:
Aber Arrays haben die Eigenschaft in fast jedem Kontext [...] sich wie ein Zeiger auf ihr erstes Element zu verhalten, das heißt tmp selber verhält sich wie &tmp[0]
sheddy schrieb:
2. Zu dem Cast und doppelt falsch von strrchr. Ich habe in der Referenz gesehen, dass ein char* zurückgegeben wird. Jedoch bekomme ich bei
char* ptr = strrchr("\\");
einen "operands of = have illegal types `pointer to char' and `int'" Fehler. Erst der Cast ermöglicht mir die richtige Verwendung, wie es sein soll.
Das ist genau das was ich meinte, mit Fehler vertuschen. Du hast string.h nicht eingebunden. Der Cast verdeckt diesen Fehler. Wehe dir, wenn ein Pointer nicht die gleiche Größe wie ein int haben sollte (was auf 64 Bit Systemen fast immer so ist). Dann macht es Bumm!
Daher nochmal: Lass sinnlose Casts sein! Der Compiler weiß es besser als du!
Die Frage, die sich mich stellt, ist jedoch:
Warum kann ich folgendes machen?
end = ptr2 - tmp;
Es ist eine doch Adressendifferenz und wird einem integer zugewiesen, wie es im Beispiel gemacht wird. Wieso kann ich dann nicht einfach
end = tmp; // bezogen auf das obere Zahlenbeispiel ("gleichbedeutend...")
machen?
Weil tmp ein Pointer ist und keine Pointerdifferenz. Eine Pointerdifferenz ist selber kein Pointer, sondern eine Zahl.
-
Die Position vom ersten Zeichen im Array ist 0 (Null), da Arrays immer bei 0 anfangen.
Alsoint start = 0;
Wenn du allerdings die Adresse im Speicher wissen willst, brauchst du ein Zeiger auf char (char*) und kein int.