Da Sie gerade C lernen, empfehle ich Ihnen, zuerst wirklich zu versuchen, die Unterschiede zwischen Arrays und Zeigern zu verstehen, anstatt die üblichen Dinge.
Im Bereich der Parameter und Arrays gibt es einige verwirrende Regeln, die klar sein sollten, bevor Sie fortfahren. Zunächst wird das, was Sie in einer Parameterliste deklarieren, als besonders behandelt. Es gibt solche Situationen, in denen Dinge als Funktionsparameter in C keinen Sinn ergeben
- Funktioniert als Parameter
- Arrays als Parameter
Arrays als Parameter
Der zweite ist vielleicht nicht sofort klar. Wenn Sie jedoch berücksichtigen, dass die Größe einer Array-Dimension Teil des Typs in C ist (und ein Array, dessen Dimensionsgröße nicht angegeben ist, hat einen unvollständigen Typ), wird dies deutlich. Wenn Sie also eine Funktion erstellen würden, die einen Array-Nachwert annimmt (eine Kopie erhält), könnte dies nur für eine Größe möglich sein! Außerdem können Arrays groß werden, und C versucht, so schnell wie möglich zu sein.
In C sind aus diesen Gründen keine Array-Werte vorhanden. Wenn Sie den Wert eines Arrays abrufen möchten, erhalten Sie stattdessen einen Zeiger auf das erste Element dieses Arrays. Und hier liegt eigentlich schon die Lösung. Anstatt einen ungültigen Array-Parameter im Voraus zu zeichnen, transformiert ein C-Compiler den Typ des jeweiligen Parameters in einen Zeiger. Denken Sie daran, es ist sehr wichtig. Der Parameter ist kein Array, sondern ein Zeiger auf den jeweiligen Elementtyp.
Wenn Sie nun versuchen, ein Array zu übergeben, wird stattdessen ein Zeiger auf das erste Element des Arrays übergeben.
Exkursion: Funktioniert als Parameter
Lassen Sie uns zur Vervollständigung und weil ich denke, dass dies Ihnen helfen wird, die Angelegenheit besser zu verstehen, schauen, wie der Stand der Dinge ist, wenn Sie versuchen, eine Funktion als Parameter zu haben. In der Tat wird es zunächst keinen Sinn ergeben. Wie kann ein Parameter eine Funktion sein? Huh, wir wollen natürlich eine Variable an diesem Ort! In diesem Fall wandelt der Compiler die Funktion erneut in einen Funktionszeiger um . Beim Versuch, eine Funktion zu übergeben, wird stattdessen ein Zeiger auf die jeweilige Funktion übergeben. Das Folgende ist also dasselbe (analog zum Array-Beispiel):
void f(void g(void));
void f(void (*g)(void));
Beachten Sie, dass Klammern *g
erforderlich sind. Andernfalls würde eine zurückgegebene Funktion void*
anstelle eines Zeigers auf eine zurückgegebene Funktion angegeben void
.
Zurück zu den Arrays
Jetzt habe ich am Anfang gesagt, dass Arrays einen unvollständigen Typ haben können - was passiert, wenn Sie noch keine Größe angeben. Da wir bereits festgestellt haben, dass ein Array-Parameter nicht vorhanden ist, sondern ein Array-Parameter ein Zeiger ist, spielt die Größe des Arrays keine Rolle. Das heißt, der Compiler übersetzt alle folgenden Elemente und alle sind dasselbe:
int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);
Natürlich macht es nicht viel Sinn, eine beliebige Größe hineinstecken zu können, und es wird einfach weggeworfen. Aus diesem Grund hat C99 eine neue Bedeutung für diese Zahlen entwickelt und lässt andere Dinge in Klammern erscheinen:
// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory.
int main(int c, char *argv[static 5]);
// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);
// says the same as the previous one
int main(int c, char ** const argv);
Die letzten beiden Zeilen besagen, dass Sie "argv" innerhalb der Funktion nicht ändern können - es ist ein konstanter Zeiger geworden. Nur wenige C-Compiler unterstützen diese C99-Funktionen. Diese Funktionen machen jedoch deutlich, dass das "Array" eigentlich keines ist. Es ist ein Zeiger.
Ein Wort der Warnung
Beachten Sie, dass alles, was ich oben gesagt habe, nur wahr ist, wenn Sie ein Array als Parameter einer Funktion haben. Wenn Sie mit lokalen Arrays arbeiten, ist ein Array kein Zeiger. Es verhält sich wie ein Zeiger, da ein Array, wie bereits erläutert, beim Lesen seines Werts in einen Zeiger konvertiert wird. Es sollte aber nicht mit Zeigern verwechselt werden.
Ein klassisches Beispiel ist das Folgende:
char c[10];
char **c = &c; // does not work.
typedef char array[10];
array *pc = &c; // *does* work.
// same without typedef. Parens needed, because [...] has
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;