Was sagt denn dein C-Buch zu dem Thema?
Was macht der Operator ++ ?
Was macht der Operator * ?
Welche Warnungen zeigt dir der Compiler? Und warum?
Und, last but not least, was findest du per google zu dem Thema?
Fragen über Fragen...
Oliver
Das *p_string mit oder ohne ++ dahinter besagt, das du auf den Pointer
zugreifen möchstest und das willst, wo der Pointer hinzeigt.
Anhand printf siehst du das auch. jedesmal wenn du ++ ausführst, zeigt
printf ein Zeichen später an.
das
*p_string(++) macht erst mit einer expliziten Zuweisung Sinn. zB sowas:
UDR = *p_string++;
Hier wird erst auf den Pointer zugegriffen (*p_string) und danach dann
der Pointer selbst um ein Element erhöht (++)..
beliebt ist das beim Ausgeben von Zeichenketten zB über die UART:
Matthias Lipinsky schrieb:> p_string = p_string + sizeof(*p_string);
Vorsicht. Das ist nur zulässig, wenn sizeof hier 1 liefert.
Wäre das beispielsweise ein int-Array, würde das nicht das gleiche
machen:
1
intarray[]={0,1,2,3,4,5,6,7,8};
2
3
int*p=array;
4
5
printf("Wert %d\n",*p);
6
7
// ergibt 0
8
9
p++;
10
11
printf("Wert %d\n",*p);
12
13
// ergibt 1
14
15
p=p+1;
16
17
printf("Wert %d\n",*p);
18
19
// ergibt 2
20
21
p=p+sizeof(*p);
22
23
printf("Wert %d\n",*p);
24
25
// ergibt 4 oder 6!
Die unterschiedlichen Möglichkeiten im letzten Schritt sind auf
unterschiedliche Größen von int zurückzuführen - auf einem
16-Bit-System ist sizeof (int) = 2, auf einem 32-Bit-System ist sizeof
(int) = 4.
Pointer-Missversteher schrieb:> würde ich eigentlich XBCDE in der Ausgabe erwarten. Stattdessen wird wie> im vorherigen Fall ABCDE ausgegeben.
Das ist nicht zulässig und das Ergebnis abhängig von deinem System.
Grund: "ABCDE" ist eine Stringkonstante, die du gar nicht ändern darfst.
>Das ist nicht zulässig und das Ergebnis abhängig von deinem System.>Grund: "ABCDE" ist eine Stringkonstante, die du gar nicht ändern darfst.
Stringkonstante. Das erklärt einiges.
Pointer-Missversteher schrieb:> , mit nem Array geht das natürlich.> Aber wieso geht es nicht mit einem String?
Weil wie erwähnt, Konstante. Würdest Du das auf einem Linux System
machen bekommst Du direkt ein Core File.
Grüsse,
René
>Matthias Lipinsky schrieb:>> p_string = p_string + sizeof(*p_string);>Vorsicht. Das ist nur zulässig, wenn sizeof hier 1 liefert.
Du hast recht. Aber es sollte ja eins liefern, da der Zeiger als Zeiger
auf char definiert ist. Aber das sollte doch auch funktionieren:
1
uint32_tau32Value[..]={...};
2
uint32_t*pu32Ptr;
3
-----
4
pu32Ptr=&au32Value;
5
for(...)
6
{
7
...=*pu32Ptr++
8
}
Das x = x + sizeof(*x) hab ich von "meinem" SPS Programmierungen. Da ist
das der Weg, den Zeiger auf das nächste Element zu schieben. Dort
liefert sizeof(pointer-dereferenziert) immer die Länge des Elementes in
Bytes. aber ein pointer++ berücksichtigt das ja vom Compiler her
automatisch.
Matthias Lipinsky schrieb:> Bytes. aber ein pointer++ berücksichtigt das ja vom Compiler her> automatisch.
Genau.
Und wenn man daher die Operation durch andere C-Operationen nachbilden
will, muss man das ebenfalls berücksichtigen.
1
p_string=((char*)p_string)+sizeof(*p_string);
der Cast ist genau aus diesem Grunde notwendig, damit nicht der Compiler
seinerseits bei der Addition nochmal die sizeof mit einrechnet. Denn
sizeof char ist per Definition 1.
Jetzt stimmt es immer.
um nochmal auf seine ursprüngliche frage einzugehen:
Die Antwort die er vermutlich hören sollte, ist: ++ bindet stärker als *
*string++ ist also dasselbe wie *(string++)
und nicht wie man vielleicht annehmen könnte, (*string)++
Der Compiler sollte eine Warnung "value computed is not used" werfen,
weil das Ergebnis zwar berechnet wird, (nämlich der Inhalt von *string),
danach wird der Pointer erhöht, das Ergebnis selbst aber nie verwendet.
>++ bindet stärker als *
Ich sag mal so: in diesem 'speziellen' oberen Fall 'bindet' es überhaupt
nicht... denn ich hab mich gefragt wie ich das Element um ein erhöhen
(verändern) könnte - was wie sich nun herausgestellt hat, innerhalb
eines Strings gar nicht geht.
Pointer-Missversteher schrieb:>>++ bindet stärker als *> Ich sag mal so: in diesem 'speziellen' oberen Fall 'bindet' es überhaupt> nicht... denn ich hab mich gefragt wie ich das Element um ein erhöhen> (verändern) könnte - was wie sich nun herausgestellt hat, innerhalb> eines Strings gar nicht geht.
Es bindet schon, und wenn der String keine Konstante wäre, täte es (mit
der "anderen" Klammerung (*string)++ ) auch den Inhalt des Strings
ändern.
Pointer-Missversteher schrieb:>>++ bindet stärker als *> Ich sag mal so: in diesem 'speziellen' oberen Fall 'bindet' es überhaupt> nicht...
Doch das tut es.
> denn ich hab mich gefragt wie ich das Element um ein erhöhen> (verändern) könnte - was wie sich nun herausgestellt hat, innerhalb> eines Strings gar nicht geht.
'nicht geht' ist ein gar grauslich Wort.
Die C-Sprachdefinition lässt die Frage ob "geht oder nicht geht" offen,
indem sie die Operation in diesem speziellen Fall (versuchte Veränderung
eines String-Literals) zu einer undefinierten Operation erklärt. Alles
ist möglich - inklusive einem Verhalten, das dem Erwarteten entspricht
(was immer du auch erwartet hast). Das man auf undefiniertem Verhalten
natürlich keine zuverlässigen Programme aufbauen kann, sollte auch klar
sein.
Matthias Lipinsky schrieb:> aber ein pointer++ berücksichtigt das ja vom Compiler her> automatisch.
Das geschieht bei jeder Pointerarithmetik.
Also auch bei
pointer += Wert
und natürlich auch bei
pointer = pointer + Wert
> Das x = x + sizeof(*x) hab ich von "meinem" SPS Programmierungen. Da ist> das der Weg, den Zeiger auf das nächste Element zu schieben.
Wenn das C oder C++ sein soll, ist das eine Fehlerquelle. Denn es ist
nur für den Sonderfall, daß sizeof 1 liefert, korrekt.
Sieh Dir mein Beispiel nochmal genau an.
Dazu folgende Frage:
16Bit => 2 und 32bit => 4.
logisch.
Aber sollte dann nicht auch das Array
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
so im Speicher liegen:
1
Byteadresse 0 1 2 3 4 5 6 7 8 9 ...
2
16bit 0 0 1 0 2 0 3 0 4 0
3
32bit 0 0 0 0 1 0 0 0 2 0
4
??
Ansonsten bedeutet das ja, das im C das p von hier:
int* p = array;
ja eigentlich keine "Byte"adresse sein kann??
Matthias Lipinsky schrieb:> Dazu folgende Frage:> 16Bit => 2 und 32bit => 4.> logisch.> Aber sollte dann nicht auch das Array> int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };> so im Speicher liegen:>
1
> Byteadresse 0 1 2 3 4 5 6 7 8 9 ...
2
> 16bit 0 0 1 0 2 0 3 0 4 0
3
> 32bit 0 0 0 0 1 0 0 0 2 0
4
> ??
5
>
Genau das tut es auch. (Ich lass jetzt mal die ganze Problematik über
Endianess weg, denn deine Frage zielt ja ganz klar nicht darauf ab).
Also: die einzelnen Elemente liegen bytemässig direkt hintereinander,
wobei jedes Element genau so viele Bytes braucht wie eben der
sizeof(*array) aussagt.
> Ansonsten bedeutet das ja, das im C das p von hier:> int* p = array;> ja eigentlich keine "Byte"adresse sein kann??
nochmal.
Wenn du Pointer Arithmetik machst (egal welche), dann wird vom Compiler
IMMER die sizeof des zugrunde liegenden Datentyps mit eingerechnet. Das
ist so definiert und es gibt nichts was man dagegen tun kann (ausser mit
einem cast eingreifen und sein eigenes Süppchen kochen).
1
ptr++ <==> ptr += 1 <==> ptr = ptr + 1
das das worauf der ptr zeigt unterschiedliche sizeof haben kann, braucht
dich als C-Programmierer nicht kümmern, das erledigt der Compiler wenn
der die Addition umsetzt. Deswegen definierst du ja auch nicht einfach
nur einen Pointer, sondern du definierst eine Pointervariable als
'Pointer auf int' oder 'Pointer auf double' oder ....
wenn du schreibst
1
int*ptr=(int*)0x100;
2
3
ptr++;
und auf deinem System ist sizeof(int) gleich 2, dann ist der numerische
Wert des Pointers nach der ++ Operation nicht 0x101, sondern 0x102.
Wäre die sizeof(int) gleich 4, dann wäre der numerische Wert des
Pointers 0x104, obwohl du in beiden Fällen lediglich einen immer
gleichen ++ angewendet hast.
das ist der entscheidene Satz:
>dann wird vom Compiler IMMER die sizeof des zugrunde liegenden Datentyps >mit
eingerechnet.
Die SPS Compiler machen das eben nicht. Kurzschreibweisen a la p++ gibt
es hier nicht. das heisst immer p:= p + offset. Und Offset bestimmt man
hier zwangsläufig mit sizeof(). Der liefert immer die Länge des
Datentypes, wo der Pointer hinzeigt. Ok. Kapiert. Ich bleib einfach bei
p++ ;-)
Matthias Lipinsky schrieb:> das ist der entscheidene Satz:>>dann wird vom Compiler IMMER die sizeof des zugrunde liegenden Datentyps >mit> eingerechnet.
Eine andere Sache, an der sich dieses Konzept durchschlägt, ist der sog.
Pointer-Array Dualismus.
Die Array-Index Operation ist in C als Variante der Pointer Arithmetik
definiert.
1
array[index] <==> *(array + index)
genau deswegen kann man das hier machen
1
inta[3]={0,1,2};
2
3
intj=*(a+2);
4
intk=a[2];
5
6
// -> j == k
aber aus demselben Grund kann man auch das hier machen
1
int*ptr=malloc(5*sizoef(int));
2
3
ptr[3]=8;
Also einen Pointer wie ein Array auffassen und mit Indexoperationen
zugreifen.
Und nicht zuletzt spielt das ganze dann ja auch in die berühmte C
'Anomalie' mit rein, nach der Arrays an Funktionen übergeben werden,
indem man die Startadresse des Arrays übergibt
1
voidfoo(int*a)
2
{
3
a[4]=3;
4
}
5
6
intmain()
7
{
8
intb[5];
9
foo(b);
10
}
Die Funktion bekommt einen Pointer. Was mich aber nicht daran hindert,
Indexoperationen damit zu betreiben.
bei all diesen Dingen ist der Array-Pointer Dualismus im Spiel und die
simple Definition, wonach Array Indizierung nichts anders als eine
andere Schreibweise für eine bestimmte Pointer-Arithmetik ist und der
Compiler bei Pointer-Arithmetik immer die sizeof des Datentyps mit
einrechnen muss. Sonst würde obiges nämlich alles nicht funktionieren.
Zumindest nicht so.
Matthias Lipinsky schrieb:> Die SPS Compiler machen das eben nicht.
Es ist natürlich ausgesprochen dämlich, wenn jemand für eine andere
Programmiersprache offenbar zumindest Teile der C-Syntax benutzt,
aber nicht die gleiche Semantik wie in C dann damit implementiert.
interpretiere ich so: Die Funktion bekommt einen Zeiger auf EINEN int.
Das da jetzt im Speicher weitere ints dahinter stehen, ist nur durch die
Deklaration als Array gegeben, aber der Funktion nicht bekannt. Das
sollte doch stimmen, denn die Funktions selbst weiss ja nicht, wie lang
das array ist..? Denn das:
a[4] = 3;
wird ja lt deiner Erklärung zu *(a+4) = 3. Egal ob diese Speicherzelle
noch zum Array gehört oder nicht.
Richtig?
>Es ist natürlich ausgesprochen dämlich, wenn jemand für eine andere>Programmiersprache offenbar zumindest Teile der C-Syntax benutzt,>aber nicht die gleiche Semantik wie in C dann damit implementiert.
Richtig. Es war unklug von mir, das nicht eindeutig zu kennzeichnen.
Matthias Lipinsky schrieb:> interpretiere ich so: Die Funktion bekommt einen Zeiger auf EINEN int.
Nein. Sie bekommt einen Zeiger auf int. Ob das einer ist, oder ob das
ein Array ist (also im Speicher mehrere hintereinander angeordnet sind),
ist für die Funktion (und auch in der Handhabung) nicht unterscheidbar.
Der Aufrufer einer solchen Funktion muss genau wissen, was er tut, oder
das Programmdesign muss dahingehend angepasst werden, daß der Funktion
zusätzlich zum Pointer auch noch eine Größeninformation (Anzahl der
Elemente) mitgeliefert wird.
Matthias Lipinsky schrieb:> Das sollte doch stimmen, denn die Funktions selbst weiss ja nicht, wie> lang das array ist..?
Ja, so ist es. Daher kann die aufgerufene Funktion in C ja auch
keinen array bounds check machen.
Ein Moderator sagt nein, der andere ja. Aber ich denke, ich weiss was
ihr meint und ich habe soweit recht und das verstanden. Sinnvoll wäre
sozusagen das:
> interpretiere ich so: Die Funktion bekommt einen Zeiger auf EINEN int.
Du musst das EINEN nicht groß schreiben.
> Richtig?
Alles richtig.
Einigen wir uns auf: Die Funktion bekommt einen Zeiger und weiß nicht
auf wieviele hintereinanderliegende int dieser Zeiger zeigt.
Dieses Wissen steckt beim Programmierer und der muss dafür sorgen, dass
alles mit rechten Dingen vor sich geht. Nur mit dem Zeiger alleine ist
es der Funktion unmöglich, das auf eigene Faust herauszufinden.
Das wird übrigens auch nicht dadurch besser, dass es eine alternative
Schreibweise gibt
1
voidfoo(inta[])
2
{
3
...
hier sieht der Programmierer besser, dass die Funktion ein Array
erwartet. Aber das ist lediglich 'syntactic sugar'. Es unterscheidet
sich in nichts von der Pointer Schreibweise.