Das verwirrende char in C/C++
-
Habt ihr sonst noch Probleme? Ein char ist ein einzelnes Zeichen vom Typ Byte oder Integer. Ein array wie char string[10] macht damit einen String für mehrere Zeichen. Ein Pointer kann benutzt werden, um indizierte Zugriffe wie sting[i] zu vermeiden. Wenn man sich mit Pointern (noch) nicht sicher auskennt, benutzt man einfach Indizes.
Zu beachten ist nur, dass ein String ein abschliessenden Nullzeichen zwingend braucht. Das machen aber die String-Funktionen von C strcpy, strcat, ... von allein!
Was bitte ist beim Programmieren Zucker, kann es nicht auch Pfeffer oder Paprika sein?
-
berniebutt schrieb:
[blabla]
Was bitte ist beim Programmieren Zucker, kann es nicht auch Pfeffer oder Paprika sein?
-
Bashar schrieb:
berniebutt schrieb:
[blabla]
Was bitte ist beim Programmieren Zucker, kann es nicht auch Pfeffer oder Paprika sein?Wobei beim mir der erste Treffer die deutsche Wikiseite ist und auch diesen Quatsch enthält:
...Ein Beispiel für syntaktischen Zucker ist die Behandlung von Feldern in der Programmiersprache C. C unterscheidet streng genommen nicht zwischen Zeigern auf Objekte und Felder von Objekten...
Das kann man da so eigentlich nicht stehen lassen. Die englische Version macht da schon einen viel besseren Eindruck:
In the C programming language arrays are constructed as blocks of memory, accessed via an offset from the array's starting point in memory. Since some pointer operations are hard to write and understand when expressed in terms of pointer arithmetic, C also provides the A *syntax for what would otherwise be written as (A + i). Similarly A[i][j] is more readable than (A + Li + j), L being A's first dimension.
Mit diesem Text verstehe ich auch, worauf !r!r wahrscheinlich hinaus wollte. Aber mit Arrays hat das weniger zu tun. Passender kann man sagen, dass der [i]Index-Operator* syntaktischer Zucker für Zeigerarithmetik ist. Seit Operatorüberladung in C++ müsste man diesen Satz aber noch etwas einschränken.
-
Bashar und Sugar Baby kennen sich da pefekt aus. Ist kein [blabla] mehr zu ergänzen. daddeldu! :p
-
krümelkacker schrieb:
Und die Bedeutung dieser Aussage ist wahrscheinlich vielen nicht klar. Ich kann damit auch echt nichts anfangen. Höchstens, dass Du glaubst, dass man Arrays auch ohne Arrays mit Zeigern hinbekommt.
Man braucht keine Arrays um Speicher statisch oder dynamisch auf dem Stack zu reservieren. Das Verhalten von Arrays auf dem Stack bekommt man auf einem UNIX auch mit alloca() und Zeigern hin. Der Vorteil von arrays besteht darin, daß man mehr dimensionale Arrays anlegen kann, sich also das manuelle Berechnen der korrekten Speicheradresse erspart, und man sich nicht explizit um die Speicherbereitstellung kümmern muß.
Folgendes Programm zeigt wie man mit einem struct Speicher entsprechender Größe anfordert. Es könnte in grauer Theorie Probleme mit dem Padding geben, aber das soll kein richtiges Programm sein, sondern nur verdeutlichen was beim Array eigentlich passiert. Daher erspare ich mir jetzt nachzusehen, ob bei Typen gleicher Größe in einem struct Padding auftreten könnte. Wichtig ist nur, daß der struct mindestens 5*int an Speicher bereitstellt, und ich das so nie in einem richtigem Programm verwenden würde.
#include <stdlib.h> #include <stdio.h> int main () { struct array { int a0,a1,a2,a3,a4,a5; }; struct array a = {0,1,2,3,4}; int* p = &a.a0; for (size_t i = 0; i != 5; ++i) { printf("%i\n",p[i]); } }
krümelkacker schrieb:
Irgendo muss doch der Speicher herkommen. Wenn ich Speicher für 5 ints reservieren will, schreibe ich
int arr[5]
. Wie soll das bitte mit Zeigern funktionieren?
Nachfolgendes Programm ist UNIX only, es soll aber nur das Prinzip erläutern.
Variante 1int my_function (size_t s) { int* p = alloca(sizeof(int)*s); for (size_t i = 0; i != s; i++) { p[i] = i; } } // hier wird der Speicher auf den p verweist freigegeben
Variante 2
int my_function (size_t s) { int p[s]; for (size_t i = 0; i != s; i++) { p[i] = i; } } // hier wird der Speicher von p freigegeben
Das sieht nun wirklich nicht mehr sehr unterschiedlich aus.
-
dem te ist mit der diskussion sicher nicht geholfen
-
Eines interessiert mich jetzt aber doch noch. Wie soll alloca() funktionieren?
Folgendes:
1. Die Rücksprungadresse von alloca() sowie der Integer wird auf den Stack gelegt und der Stack-Pointer inkrementiert.
2. alloca() legt den Wert des Stack-Pointers oder den Wert des Stack-Pointers minus 8 oder ähnliches irgendwo bei der Rückgabe ab.
3. alloca() kehrt zurück und der Stackpointer wird wieder dekrementiert.
4. Der Rückgabewert wird in die Variable kopiert.
5. Der Stack-Pointer muss inkrementiert werden, damit er hinter den allozierten Stack-Speicher zeigt, aber wie? Das könnte höchstens durch eine Calling-Convention gehen, bei der die Rücksprungadresse in einem Register liegt und alloca() daher selbst den Stack-Speicher inkrementieren kann, so dass dieser nur bis zum endgültigen Wert wieder dekrementiert wird.
6. Wer sagt dem Programm, dass hier mehr Stack-Speicher alloziert wurde und der Stack-Pointer weiter dekrementiert werden muss als gedacht??
-
It's magic! delete[] kennt auch die größe vom array...
-
da magican! schrieb:
It's magic! delete[] kennt auch die größe vom array...
Da kann es aber Konvention sein, dass new[] die Größe des Arrays in die vier Bytes vor dem Speicher schreibt.
-
wxSkip schrieb:
Eines interessiert mich jetzt aber doch noch. Wie soll alloca() funktionieren?
intrinsic.
alloca ist afaik nur ein anderer name für __builtin_alloca und das sagt ja schon alles
-
Aha... Compiler-Magik hatte ich schon erwartet
.
-
Also für mich sind Lambdas ja heiß aufgekochter Syntaxzucker und damit Syntaxkaramel!
Ps: Also ich stelle mir die NAMEN der Arrays immer als Zeiger vor, bei denen der Compiler noch ein gewisses Zugriffsschema mitschleift, eben wie bei ganz normalen typisierten Zeigern auch.
-
#include <iostream> bool isAnArrayAPointer() { return sizeof(int[10]) == sizeof(void*); } bool isTheNameOfAnArrayAPointer() { int temp[10]; return sizeof(temp) == sizeof(void*); } int main() { std::cout << std::boolalpha << isAnArrayAPointer() << std::endl; std::cout << std::boolalpha << isTheNameOfAnArrayAPointer() << std::endl; }
Frage beantwortet?
Grüssli
-
Das weiß ich nicht, kommt auf die Frage an! Welche Frage meinst du?
-
Decimad schrieb:
Das weiß ich nicht, kommt auf die Frage an! Welche Frage meinst du?
Lies die Funktionsnamen.
Grüssli
-
Boah, ich hab jetzt echt keine Lust hier groß auszuholen, warum ich mir das so vorstelle. Mir reicht jetzt hier zu betonen, dass eine Vorstellung nicht der Wirklichkeit entsprechen muss.
-
Irgendwo hier im Forum hatte ich zu einem ähnlichen Thema gelesen, dass ein Byte auf unterschiedlichen Maschinen nicht gleich groß sein soll.
Wie auch immer, man könnte coden:
char Weihnachtskalender[24]
irritierenderweise könnte man aber auch coden:
char *Weihnachskalender[24]
Das ist beides nicht das gleiche, das erste eher ein der Weihnchtskalender selbst (vorerst eine Bastelarbeit, noch keine Schokolade drin
) - das letztere gleicht eher dem Kind, welches auf den Kalender guckt, und sieht: Ah, heut ist der 22. also mach ich Tür 22 auf - nur das es im Moment noch schläft, und noch gar nicht weiß, was für ein Tag heute ist...;)
...hm und um die Verwirrung noch etwas anzuheizen, könnte man ja meinen, der Kalender selber heisst i++ ...und nicht etwa ++*gierigegrabbelhand - dann eher vielleicht ++*datum
-
Das Hauptptoblem hier ist doch wie Dravere schon gezeigt hat, das aneinander vorbei geredet wird. Ein Array ist ein Array und ein Pointer ist ein Pointer. Aber ein Array kann durch Pointersyntax angesprochen werden, das ist doch alles...
-
Dravere schrieb:
#include <iostream> bool isAnArrayAPointer() { return sizeof(int[10]) == sizeof(void*); } bool isTheNameOfAnArrayAPointer() { int temp[10]; return sizeof(temp) == sizeof(void*); } int main() { std::cout << std::boolalpha << isAnArrayAPointer() << std::endl; std::cout << std::boolalpha << isTheNameOfAnArrayAPointer() << std::endl; }
Frage beantwortet?
Grüssli
Das macht doch 0 Sinn, mein Pointer verbraucht doch nicht mehr Speicher wenn er auf eine größere Datenstruktur zeigt, insofern trägt der Vergleich ob sizeof(array) == sizeof(pointer) Null zur Diskussion bei, egal welcher Meinung man auch sein mag.
-
gastantwort schrieb:
Das macht doch 0 Sinn, mein Pointer verbraucht doch nicht mehr Speicher wenn er auf eine größere Datenstruktur zeigt, insofern trägt der Vergleich ob sizeof(array) == sizeof(pointer) Null zur Diskussion bei, egal welcher Meinung man auch sein mag.
Es zeigt den Unterschied Array <-> Zeiger.
Und das ein Array eben kein Zeiger ist.Beide Vergleiche sind btw unwahr.
PS:
Es geht hier nicht um Meinung. Dass ein Array kein Zeiger ist, ist einfach ein Fakt.