Stimmt diese Aussage? Kann irgendein "TYP" des Zeigers auf irgendeinen anderen Typ zeigen? Weil ich das glaube, habe noch Zweifel.
Warum werden Zeiger für bestimmte Typen deklariert? Z.B. int
oder char
?
Die einzige Erklärung, die ich bekommen konnte, war: Wenn ein Zeiger vom Typ int
auf ein char
-Array zeigte, dann springt der Zeiger bei der Inkrementierung des Zeigers von der 0-Position zur 2-Position und überspringt dabei 1 Position zwischen (weil int size = 2).
Und vielleicht, weil ein Zeiger nur die Adresse eines Wertes enthält, nicht den Wert selbst, d. h. int
oder double
.
Habe ich mich geirrt? War diese Aussage richtig?
Zeiger können austauschbar sein, sind aber nicht erforderlich.
Insbesondere müssen auf bestimmten Plattformen bestimmte Typen an bestimmte Bytegrenzen angepasst werden.
Während also ein char
irgendwo im Speicher sein kann, muss sich ein int
möglicherweise auf einer 4-Byte-Grenze befinden.
Ein weiterer wichtiger potenzieller Unterschied besteht in Funktionszeigern.
Pointer zu Funktionen sind möglicherweise nicht mit Zeigern zu Datentypen auf vielen Plattformen austauschbar.
Es muss wiederholt werden: Dies ist plattformspezifisch .
Ich glaube, Intel x86-Architekturen behandeln alle Zeiger gleich.
Aber möglicherweise begegnen Sie anderen Plattformen, wo das nicht stimmt.
Jeder Zeiger hat einen bestimmten Typ. Es gibt einen speziellen generischen Zeigertyp void*
, der auf alles zeigen kann, aber Sie müssen ein void*
in einen bestimmten Zeigertyp konvertieren, bevor Sie es dereferenzieren können.
Sie können einen Zeigerwert von einem Zeigertyp in einen anderen konvertieren. In den meisten Fällen wird die Konvertierung eines Zeigers von foo*
nach bar*
und zurück nach foo*
den ursprünglichen Wert ergeben - aber das ist nicht immer in allen Fällen garantiert.
Sie können bewirken, dass ein Zeiger vom Typ foo*
auf ein Objekt vom Typ bar
zeigt, aber (a) ist es normalerweise eine schlechte Idee und (b) in einigen Fällen sogar funktioniert möglicherweise nicht (wenn die Zieltypen foo
und bar
unterschiedliche Größen oder Ausrichtungsanforderungen haben).
Du kannst mit Dingen wie:
durchkommen %Vor% was bewirkt, dass p
auf n
zeigt - aber dann gibt *p
Ihnen nicht den Wert von n
, es gibt Ihnen den Wert des ersten Bytes von n
als char
.
Das unterschiedliche Verhalten der Zeigerarithmetik ist nur ein Teil des Grundes für unterschiedliche Zeigertypen. Es geht hauptsächlich um Typ Sicherheit . Wenn Sie einen Zeiger vom Typ int*
haben, können Sie einigermaßen sicher sein (es sei denn, Sie haben etwas unsicher gemacht), dass er tatsächlich auf ein int
-Objekt zeigt. Und wenn Sie versuchen, es als ein Objekt eines anderen Typs zu behandeln, wird der Compiler wahrscheinlich darüber beschweren.
Im Grunde haben wir verschiedene Zeigertypen aus denselben Gründen, aus denen wir andere eindeutige Typen haben: So können wir mit Hilfe des Compilers verfolgen, welche Art von Wert in jedem Objekt gespeichert ist.
(Es gab Sprachen, die nur generische Zeiger nicht typisiert haben. In einer solchen Sprache ist es schwieriger, Typfehler zu vermeiden, wie das Speichern eines Wertes eines Typs und den versehentlichen Zugriff auf einen anderen Typ.)
Jeder Zeiger kann sich auf einen beliebigen Ort im Speicher beziehen, also ist die Aussage technisch korrekt. Wenn Sie das sagen, müssen Sie bei der Neuinterpretation von Zeigertypen vorsichtig sein.
Ein Zeiger hat grundsätzlich zwei Informationen: einen Speicherort und den Typ, den erwartet , um ihn zu finden. Der Speicherort könnte alles sein. Es könnte der Ort sein, an dem ein Objekt oder Wert gespeichert wird; es könnte in der Mitte einer Textzeile stehen; oder es könnte einfach ein willkürlicher Block nicht initialisierten Speichers sein.
Die Typinformation in einem Zeiger ist jedoch wichtig. Die Array- und Zeigerarithmetikerklärung in Ihrer Frage ist korrekt - wenn Sie versuchen, Daten im Speicher mit einem Zeiger zu durchlaufen, muss der Typ korrekt sein, andernfalls können Sie nicht korrekt iterieren. Dies liegt daran, dass verschiedene Typen unterschiedliche Größen haben und möglicherweise anders ausgerichtet sind.
Der Typ ist auch wichtig in Bezug darauf, wie Daten in Ihrem Programm gehandhabt werden. Wenn Sie beispielsweise int
im Speicher gespeichert haben, aber Sie darauf zugreifen, indem Sie einen float*
-Zeiger dereferenzieren, erhalten Sie wahrscheinlich nutzlose Ergebnisse (es sei denn, Sie haben es aus einem bestimmten Grund so programmiert). Dies liegt daran, dass ein int
im Speicher anders gespeichert wird als ein float
.
Kann irgendein "TYPE" des Zeigers auf irgendeinen anderen Typ zeigen?
Im Allgemeinen keine. Die Typen müssen verwandt sein.
Es ist möglich, reinterpret_cast
zu verwenden, um einen Zeiger von einem Typ auf einen anderen zu übertragen, aber wenn diese Zeiger nicht mit einem static_cast
legal konvertiert werden können, ist reinterpret_cast
ungültig. Daher können Sie Foo* foo = ...; Bar* bar = (Bar*)foo;
nicht verwenden, außer Foo
und Bar
sind tatsächlich verwandt.
Sie können auch reinterpret_cast
verwenden, um von einem Objektzeiger auf ein void*
zu casten und umgekehrt, und in diesem Sinne kann void*
auf alles zeigen - aber das ist nicht das, wonach Sie zu fragen scheinen.
Außerdem können Sie reinterpret_cast
vom Objektzeiger zum Integralwert und umgekehrt, aber wiederum nicht das, was Sie zu fragen scheinen.
Schließlich wird eine spezielle Ausnahme für char*
gemacht. Sie können eine char*
-Variable mit der Adresse eines anderen Typs initialisieren und eine Zeigermathematik für den resultierenden Zeiger ausführen. Du kannst immer noch nicht durch den Zeiger dereferenzieren, wenn das Ding, auf das gezeigt wird, nicht tatsächlich ein char
ist, aber es kann dann wieder auf den tatsächlichen Typ zurückgeworfen und auf diese Weise verwendet werden.
Bedenken Sie auch, dass Sie jedes Mal, wenn Sie reinterpret_cast
in einem Kontext verwenden, am Abgrund einer Klippe tanzen. Dereferenzieren eines Zeigers auf ein Foo
, wenn das Ding, auf das es tatsächlich zeigt, ein Bar
ist, liefert Undefined Behavior, wenn die Typen nicht verwandt sind. Sie würden gut tun, um diese Arten von Güssen um jeden Preis zu vermeiden.