Hallo zusammen, ich verstehe gerade nicht die Rangordnung von C operatorn: Laut Wikipedia (und andere) hat '[]' vor dem '->' Vorrang. Wie weise ich z.B. die Zahl 12 im Beispiel richtig zu? ---------------- struct TS { int a[10]; } ... // Pointer auf TS; TS* p_TS; ... // Variante a (so habe ich es immer gemacht p_TS->a[2] = 12; // Variante b (p_TS->a)[2] = 12; ------------------ Beides funktioniert. Logisch Sinn macht vermutlich auch beides, da "[]" ohne Bezug keinen Sinn macht. Variante b ist laut Wiki richtig. Was sagt der Compiler? Grüße Circe
C_NonExpert schrieb: > Laut Wikipedia (und andere) hat '[]' vor dem '->' Vorrang. Konkrete Belege? Soweit mir bekannt sind sie in der gleichen Vorranggruppe, daher gilt die Assoziativität, und die sagt "links vor rechts".
C_NonExpert schrieb: > Was sagt der Compiler? Ich denke, in diesem Fall ist es egal. TS->a[2] macht ja nix anderes, als die Adresse des Pointers + Offest zur Variable a in der Struktur + Index im Array zusammenzurechnen. Was jetzt zuerst zusammengerechnet wird, spielt meiner Meinung nach keine Rolle. So denke ich mir es jedenfalls. :-)
Floh schrieb: >> Was sagt der Compiler? > Ich denke, in diesem Fall ist es egal. Ist es nicht. Hätte [] wirklich Vorrang, dann würde "a" der Bezug zur struct fehlen und der Name würde nicht als struct member sondern als normale lokale oder globale Variable verstanden, erst das Resultat des [] Operators wäre dann die rechte Seite des -> Operators. Etwas mit dem der Compiler nichts anfangen könnte. Eine nette Illustration hierfür ist die etwas ungebräuchliche Kommutativität des [] Operators, denn a[i] ist per Definition des [] Operators als *(a+i) identisch mit i[a].
C_NonExpert schrieb: > // Pointer auf TS; > TS* p_TS; > ... > // Variante a (so habe ich es immer gemacht > p_TS->a[2] = 12; Ähem.. sollte es nicht eher so heißen: struct TS* p_TS; Und deine Version a p_TS->a[2] = 12; halte ich als einzige Schreibversion für richtig und gut. Mag ja sein, daß man das Ganze auch verquer hinschreiben kann und trotzdem zufällig das Richtige bei herauskommt, aber alles Andere wäre unleserlich. A. K. schrieb: > Eine nette Illustration hierfür.. denn a[i] ist per Definition des [] Operators als *(a+i) identisch mit i[a] Bitte? Wenn man es schon per Pointerconstruct ausdrücken will, so doch eher so: a[i] entspräche dann *(a + i*sizeof(a)) Immerhin soll a[i] ja das i'te Element von a bezeichnen und hier ist nichts über die Größe bzw. Datenart von a gesagt. Gelle? W.S.
W.S. schrieb: > Wenn man es schon per Pointerconstruct ausdrücken will, so doch eher so: > a[i] entspräche dann *(a + i*sizeof(a)) > Immerhin soll a[i] ja das i'te Element von a bezeichnen und hier ist > nichts über die Größe bzw. Datenart von a gesagt. Gelle? Unsinn. Du hast offenbar Nachholbedarf beim Thema "Pointer-Arithmetik". Schlag es nach.
Stefan Ernst schrieb: > Unsinn. Ach ja? Anstatt hier nur herumzumotzen hättest du besser eine sachliche Erklärung oder Widerlegung abgeben können. Solange das fehlt, ist dein Beitrag nur heiße Luft. W.S.
C99 sagt: "The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))."
Fakt ist, dass [i] nicht die Bytes hochzählt sondern in Strukturgrößen denkt. *(a+i) Kann deshalb nicht ganz passen. *(a + i*sizeof(a)) sieht für mich sinnvoller aus.
Thomas Decker schrieb: > *(a+i) Kann deshalb nicht ganz passen. Doch, und zwar genau deswegen. Wenn man *(a+i) als C Ausdruck versteht, nicht als Rechenvorschrift in Maschinenadressen. a+1 zeigt auf das 2. Element, nicht auf das 2. Byte. Solche Pointer-Arithmetik multipliziert - auf Maschinenebene betrachtet - mit der Elementgrösse. Die Arbeitsweise des Index-Operators ist somit eine direkte Folge der Pointer-Arithmetik.
Oder vielleicht nochmal in etwas anderer Kurzform: Wenn a ein Pointer ist, dann zeigt a+1 auf das nächste Objekt seines Zieltyps, unabhängig davon, wie groß dieser Zieltyp konkret ist.
Thomas Decker schrieb: > *sizeof(a) Ja, das ist ganz unten auf Maschinenebene exakt so, aber da der Compiler ja weiß, was man eigentlich meint, fügt er diesen Term "unter der Decke" von sich aus hinzu, so daß am Ende das Richtige dabei herauskommt. Man würde also (a+3) schreiben, aber im Grunde (a+3*sizeof(Typ von a)) meinen, da man ja das 4. Element, also a[3] tatsächlich meint. Logisch ist das Mumpitz, da eine Integervariable i nicht addierbar ist zu einem Array a, obwohl der Ausdruck "a+i" für sich genommen völlig legal ist. Stattdessen ist all dieses eben eine Konvention, also eine Festlegung, die man beachten muß. C ist voll davon, allein die verschiedenen Bedeutungen des Zeichens * in verschiedenen Kontexten füllen ganze Bibeln... Dies ist wieder mal ein Beispiel dafür, daß in C das, was man hinschreiben muß eben nicht mit dem übereinstimmt, was man eigentlich gemeint hat. Natürlich kann man sich so sehr an C gewöhnen, daß einem der innere Widersinn all dieser Konstrukte nicht mehr auffällt, man also quasi betriebsblind wird. Aber: Ist das wirklich gut? W.S.
W.S. schrieb: > Dies ist wieder mal ein Beispiel dafür, daß in C das, was man > hinschreiben muß eben nicht mit dem übereinstimmt, was man eigentlich > gemeint hat. Also ich bin fast geneigt, das wieder mit einem "Unsinn" zu beantworten. ;-) Gerade bei der Pointer-Arithmetik stimmt doch das Verhalten in der überwiegenden Mehrzahl der Fälle genau mit dem überein, was auch tatsächlich gewollt/gemeint ist. Wer ptr++ schreibt, will damit zum nächsten Element und nicht zum nächsten Byte (in der Regel).
W.S. schrieb: > Dies ist wieder mal ein Beispiel dafür, daß in C das, was man > hinschreiben muß eben nicht mit dem übereinstimmt, was man eigentlich > gemeint hat. Natürlich kann man sich so sehr an C gewöhnen, daß einem > der innere Widersinn all dieser Konstrukte nicht mehr auffällt, man also > quasi betriebsblind wird. Aber: Ist das wirklich gut? Es wäre in erster Linie gut, C nicht mit Halbwissen und Trial&Error zu erlernen, sondern von Anfang an in ein Buch zu schauen. Wenn man zum Beispiel begreift, dass Zeiger keine Speicheradressen auf Maschinenebene oder im Arbeitsspeicher sind, dann sehen die ganzen 'unlogischen' Konstrukte auf einmal ziemlich durchdacht aus. Also bitte nicht etwas verurteilen, was man (noch) nicht ganz durchschaut und/oder begriffen hat. Das soll kein Vorwurf sein, ich bin auch wunderbar mit Trial&Error aufs Maul gefallen. Wenn du Mumpitz möchtest, dann geh doch mal zu C# oder Java oder irgendeiner Sprache, die keine Zeiger kennt, sondern stattdessen alles mit (möglicherweise sogar transparenten -> Java) Objektreferenzen vergewaltigt. Da hast du dann allen Grund, dir jedes Mal aufs Neue das Gehirn zu zerknoten, ob und wie und warum ein Objekt nun kopiert wird oder nicht... :-}
1 | putchar("abcde"[2]); |
W.S. schrieb: > Dies ist wieder mal ein Beispiel dafür, daß in C das, was man > hinschreiben muß eben nicht mit dem übereinstimmt, was man eigentlich > gemeint hat. Nur wenn du eigentlich in Assembler programmieren wolltest, aber versehentlich den C Compiler erwischt hast. Als die Sprache C definiert wurde, da wurden in vielen Maschinen keine Bytes adressiert, sondern Maschinenworte. Was immer das war. Bytes waren dann Teile eines einzelnen Wortes. Infolgedessen waren dann die Adressen und damit die Pointer in ihrer Darstellung abhängig vom darauf zeigenden Datentyp (gibts wohl auch heute noch, im MaxQ2000). Deine Vorstellung hätte Pointer-Arithmetik dermassen maschinenabhängig gemacht, dass eine Portierung auf eine Maschine mit anderer Wort- und/oder Integer-Grösse fast unmöglich geworden wäre. Man kann nun trefflich darüber streiten, ob der sehr freizügige Umgang von C mit Pointern eher nützlich oder eher Tretmine ist, aber wenn man mal akzeptiert, dass es sie gibt, dann ist diese Arithmetik durchaus sinnvoll definiert. Denn sie stellt genau die minimale Abstraktion dar, ohne die Programme vollständig zu strukturiertem Assembler mutiert wären. Es könnte sich vielleicht lohnen, dafür mal in die Vorgängersprachen B und BCPL reinzusehen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.