sizeof pointer/array
-
Hallo,
ich würde nur eben wissen wollen, woher der compiler weiß, was der Unterschied bzw. dass es einen Unterschied zwischen einem beispielsweise char-array und char-pointer gibt.
char cArray[] = "Hallo"; char* cLiteral = "Hallo";
Wenn ich mir die Typen von beiden ausgeben lassen, dann sind sowohl cArray als auch cLiteral "char "'s. Also pointer zu char.
Allerdings gibt es ja hier einen Unterschied, nicht nur, dass das eine ein Literal ist, sondern auch, dass z.B. der typ von&cArray
char ()[5] ist und der Typ von&cLiteral
char **.
Genauso wiesizeof(cArray)
tatsächlich die Array-Größe berücksichtigt, abersizeof(cLiteral)
nur die des Pointers.Verstehe nicht, wie sich das unterschiedlich verhalten kann, wenn doch beide (cArray und cLiteral) eigentlich vom gleichen Typen sind?
Macht der compiler da intern Magie, dadurch, dass die beiden Variablen unterschiedlich definiert wurden, oder wie genau darf ich das verstehen?
-
&cArray is natürlich vom Typ char (*)[6] nicht 5, da Null-Terminierung.
-
Um kurz klarzustellen, warum ich denke, dass cArray vom Typ "char *" ist:
Ich hab dazu einfach die warnings des compilers benutzt (MinGW), alaprintf("%d", cArray)
- compiler sagt dann, cArray ist vom Typ "char *".
-
SZE schrieb:
ich würde nur eben wissen wollen, woher der compiler weiß, was der Unterschied bzw. dass es einen Unterschied zwischen einem beispielsweise char-array und char-pointer gibt.
...
Verstehe nicht, wie sich das unterschiedlich verhalten kann, wenn doch beide (cArray und cLiteral) eigentlich vom gleichen Typen sind?
Macht der compiler da intern Magie, dadurch, dass die beiden Variablen unterschiedlich definiert wurden, oder wie genau darf ich das verstehen?Das weiß der Compiler nur dann, wenn er direkt die Deklaration des Objektes sehen kann:
#include <stdio.h> void func_arr(char arg[]) { printf("func_arr: %zu\n",sizeof(arg)); } void func_ptr(char*arg) { printf("func_ptr: %zu\n",sizeof(arg)); } int main(void) { char arr[] = "Hallo"; char*ptr = "Hallo"; printf("main arr: %zu\n",sizeof(arr)); printf("main ptr: %zu\n",sizeof(ptr)); func_arr(arr); func_ptr(ptr); return 0; }
Ausgabe:
main arr: 6 main ptr: 8 func_arr: 8 func_ptr: 8
Nur in
main
hat der Compiler Zugriff aufarr
und kann sehen, dass es sich um ein Array handelt. Infunc_arr
kann er das nicht mehr, obwohl das Argument als Array deklariert wurde. Selbst wenn du stattdessenvoid func_arr(char arg[200]
verwendest, wird er dir immer noch "8" als Größe ausgeben. Ansonsten ist das nämlich ein Zeiger wie jeder andere auch.
-
SZE schrieb:
...wenn doch beide (cArray und cLiteral) eigentlich vom gleichen Typen sind?...
Woher hast du diese Weisheit?
Was heißt bei dir "eigentlich"?
In C ist vieles implizit und (deutlich) weniger offensichtlich und noch weniger ist selbstverständlich.
Liegt daran, dass C von Profis für Profis erschaffen wurde und deswegen eben nicht großer Wert auf möglichst leichte Erlernbarkeit gelegt wurde.
-
@dachschaden
Sehr interessant, das merke ich mir. Mich interessiert der Unterschied zwischen diesen Zwei Dingen und die Erklärung hilft mir, ein paar grundsätzliche Dinge festzustellen.
Danke!@Wutz
Wie ich im 3. Posting geschrieben habe, hab ich den Compiler per Warning dazu gebracht, mir zu verraten, für was er den Typen hält.
Und das war eben in beiden Fällen char *.Ich weiß gar nicht genau was ich wissen will oder was mich stört, aber ich denke ich bin einfach etwas im Unklaren darüber, wie ich char* und char[] miteinander vermische etc. pp.
Was ich auch nicht so wirklich verstehe, ist, dass cArray z.B. wohl vom Typen char * ist, &cArray aber dann plötzlich vom Typen char ()[6].
Im 1. Fall (cArray ist char ) sieht es so aus als wäre die Array-Schreibweise tatsächlich nur Syntax-sugar (mit ein paar Sonderheiten) gegenüber char, intern wäre es aber das gleiche und wenn man Typen betrachtet gibt es nur char.
Im 2. Fall (&cArray ist char (*)[6]) taucht aber auf einmal wieder die Array-Schreibweise im Typen auf und es scheint doch wieder was anderes zu sein.Ich weiß nicht, ob ich mir diese Unterschiede einfach so merken soll, oder ob ich daraus irgendetwas wichtiges verstehen muss und irgendeine wichtige Erkenntnis haben sollte.
-
Ein Array ist kein Zeiger, ein Zeiger ist kein Array.
Zumindest nicht immer und überall.
Wann und wo genau - das zu wissen unterscheidet eine C Profi von einem C Anfänger.
Das gilt auch für deinen "Test", den Compiler den Typ anzeigen zu lassen.
Auch dabei gelten Promotions (interne Typumwandlungen).
-
SZE schrieb:
Ich weiß gar nicht genau was ich wissen will oder was mich stört, aber ich denke ich bin einfach etwas im Unklaren darüber, wie ich char* und char[] miteinander vermische etc. pp.
Array <=> Liste von Objekten.
Zeiger <=> Adresse eines Objektes.Dein Array
cArray
wird auf dem Stack erstellt und erhält eine Kopie des Strings "Hallo". Und weil der Compiler das Array einsehen kann, gibtsizeof
darauf auch die Länge des Objektes. Weil es sich um eine Kopie handelt, hast du keine Probleme damit, den String zu modifizieren.
Dein ZeigercLiteral
wird wird ebenfalls auf dem Stack erstellt, bekommt aber keine Kopie, sondern zeigt direkt auf den Speicher, in dem der Compiler "Hallo" abspeichert. Und ein paar Systeme und Architekturen (Linux und Windows auf x86/x64) definieren solche Datenbereiche als RO (read-only) - wenn du versuchst, die zu modifizieren, bekommst du einen Laufzeitfehler reingedrückt (Segfault/Access Violation).Such mal nach
c pointer decay
, da bekommst du mehr Informationen zu, als dir lieb ist.
-
Alles klar, ich denke damit kann ich die Thematik für mich abschließen.
Danke an Euch beide!