it-swarm.com.de

Wie kann man den Zeigerstern * in C verstehen?

Ich habe Probleme mit dem Zeigerzeichen *. Ich finde es sehr verwirrend, wie es in Deklarationen und Ausdrücken verwendet wird.

Zum Beispiel: 

int *i; // i is a pointer to an int

Aber was ist die Logik hinter der Syntax? Was bedeutet das * vor dem ich meine? Nehmen wir das folgende Beispiel. Bitte korrigieren Sie mich, wo ich falsch liege:

char **s;
char *(*s); // added parentheses to highlight precedence

Und hier verliere ich den Überblick. Das * s zwischen den Klammern bedeutet: s ist ein Zeiger? Aber ein Hinweis auf was? Und was bedeutet das * außerhalb der Klammern: Ein Zeiger auf was zeigt?

Die Bedeutung davon ist also: Der Zeiger, der auf zeigt, was zeigt, ist ein Zeiger auf ein Zeichen?

Ich bin ratlos. Wird das Zeichen * in Deklarationen und Ausdrücken unterschiedlich interpretiert? Wenn ja, wie wird es anders interpretiert? Wohin gehe ich falsch?

31
Jeffrey

Die Deklarationsregel in c lautet: Sie erklären sie so, wie Sie sie verwenden.

char *p bedeutet, dass Sie *p benötigen, um das Zeichen zu erhalten.

char **p bedeutet, dass Sie **p benötigen, um das Zeichen zu erhalten.

21
burningice

Nimm es so:

int *i bedeutet, dass der Wert, auf den i zeigt, eine ganze Zahl ist.

char **p bedeutet, dass p ein Zeiger ist, der selbst ein Zeiger auf ein Zeichen ist.enter image description here

62
pradeepchhetri
int i; //i is an int.
int *i; //i is a pointer to an int
int **i;//i is a pointer to a pointer to an int.

Wird das Zeichen * in Deklarationen und Ausdrücken unterschiedlich interpretiert?

Ja. Sie sind völlig verschieden. In einer Deklaration wird * verwendet, um Zeiger zu deklarieren. In einem Ausdruck unary * wird ein Zeiger (oder als binärer Multiplikationsoperator) dereferenziert.

Einige Beispiele:

int i = 10; //i is an int, it has allocated storage to store an int.
int *k; // k is an uninitialized pointer to an int. 
        //It does not store an int, but a pointer to one.
k = &i; // make k point to i. We take the address of i and store it in k
int j = *k; //here we dereference the k pointer to get at the int value it points
            //to. As it points to i, *k will get the value 10 and store it in j
48
nos

Deklarationen in C sind ausdruckszentrisch, was bedeutet, dass die Form der Deklaration mit der Form des Ausdrucks im ausführbaren Code übereinstimmen sollte.

Angenommen, wir haben einen Zeiger auf eine Ganzzahl mit dem Namen p. Wir möchten auf den ganzzahligen Wert zugreifen, auf den p zeigt, so dass wir dereference den Zeiger wie folgt:

x = *p; 

Der Typ des Ausdrucks *p ist int; Daher hat die Deklaration von p die Form

int *p;

In dieser Deklaration ist int der Typbezeichner und *p der Deklarator . Der Deklarator führt den Namen des zu deklarierenden Objekts (p) zusammen mit zusätzlichen Typinformationen ein, die nicht vom Typbezeichner bereitgestellt werden. In diesem Fall ist die zusätzliche Typinformation, dass p ein Zeigertyp ist. Die Deklaration kann gelesen werden als entweder "p ist vom Typzeiger auf int" oder "p ist ein Zeiger auf den Typ int". Ich bevorzuge die zweite Form, andere bevorzugen die erste. 

Es ist ein Zufall der C- und C++ - Syntax, dass Sie diese Deklaration entweder als int *p; oder int* p; schreiben können. In beiden Fällen wird es als int (*p); analysiert, dh * ist immer mit dem Variablennamen verknüpft, nicht mit dem Typbezeichner. 

Nehmen wir nun an, wir haben ein Array von Zeigern auf int und möchten auf den Wert zugreifen, auf den das i'te Element des Arrays zeigt. Wir subskribieren in das Array und dereferenzieren das Ergebnis wie folgt:

x = *ap[i]; // parsed as *(ap[i]), since subscript has higher precedence
            // than dereference.

Der Typ des Ausdrucks *ap[i] ist wiederum int, also die Deklaration von ap

int *ap[N];

der Deklarator *ap[N] gibt an, dass ap ein Array von Zeigern auf int ist. 

Um den Punkt nach Hause zu fahren, nehmen wir an, wir haben einen Zeiger auf einen Zeiger auf int und möchten auf diesen Wert zugreifen. Wir weisen erneut auf den Zeiger hin und dereferenzieren dann dieses Ergebnis, um den ganzzahligen Wert zu erhalten:

x = **pp; // *pp deferences pp, then **pp dereferences the result of *pp

Da der Typ des Ausdrucks **ppint ist, lautet die Deklaration

int **pp;

Der Deklarator **pp zeigt an, dass pp ein Zeiger auf einen anderen Zeiger auf eine int ist. 

Doppelte Indirektion wird häufig angezeigt, normalerweise, wenn Sie einen Zeigerwert ändern möchten, den Sie an eine Funktion übergeben, z.

void openAndInit(FILE **p)
{
  *p = fopen("AFile.txt", "r");
  // do other stuff
}

int main(void)
{
  FILE *f = NULL;
  ...
  openAndInit(&f);
  ...
}

In diesem Fall möchten wir, dass die Funktion den Wert von f aktualisiert. Dazu müssen wir einen Zeiger auf f übergeben. Da f bereits ein Zeigertyp (FILE *) ist, bedeutet dies, dass wir einen Zeiger auf einen FILE * übergeben, daher die Deklaration von p als FILE **p. Denken Sie daran, dass der Ausdruck *p in openAndInit auf dasselbe Objekt verweist wie der Ausdruck f in main

Sowohl in Deklarationen als auch in Ausdrücken haben sowohl [] als auch () eine höhere Priorität als unäre *. Beispielsweise wird *ap[i] als *(ap[i]) interpretiert. Der Ausdruck ap[i] ist ein Zeigertyp und der * dereferenziert diesen Zeiger. ap ist also ein Array von Zeigern . Wenn Sie einen Zeiger für ein Array deklarieren möchten, müssen Sie den * explizit mit dem Arraynamen gruppieren, wie folgt:

int (*pa)[N]; // pa is a pointer to an N-element array of int

und wenn Sie auf einen Wert im Array zugreifen möchten, müssen Sie pa vor dem Anwenden des Indexes Vorrang einräumen:

x = (*pa)[i];

Ähnlich bei Funktionen:

int *f(); // f is a function that returns a pointer to int
...
x = *f(); // we must dereference the result of f() to get the int value

int (*f)(); // f is a pointer to a function that returns an int
...
x = (*f)(); // we must dereference f and execute the result to get the int value
10
John Bode

Meine Lieblingsmethode, um komplizierte Deklaratoren zu analysieren, ist die Rechtsdrehungsregel .

Grundsätzlich beginnt man mit dem Bezeichner und folgt einer Spirale im Uhrzeigersinn. Sehen Sie den Link, um genau zu erfahren, wie er verwendet wird.

Zwei Dinge, die der Artikel nicht erwähnt:

1- Sie sollten den Typbezeichner (int, char usw.) vom Deklarator trennen, den Deklarator analysieren und dann den Typbezeichner hinzufügen.

2- Wenn Sie auf eckige Klammern stoßen, die ein Array kennzeichnen, lesen Sie auch die folgenden eckigen Klammern (falls vorhanden).

9
tiftik

int * i bedeutet, dass i ein Zeiger auf int ist (rückwärts lesen, * als Zeiger lesen) .char **p und char *(*p) bezeichnen einen Zeiger auf einen Zeiger auf char. 

Hier sind einige andere Beispiele

int* a[3] // a ist ein Array von 3 Zeigern auf int

int (*a)[3] // a ist ein Zeiger auf ein Array von 3 Ints

5
Armen Tsirunyan

Sie haben die Antwort in Ihren Fragen.

In der Tat wird ein Doppelstern verwendet, um den Zeiger auf den Zeiger anzuzeigen.

2
Shamim Hafiz

Die In-Deklaration bedeutet, dass die Variable ein Zeiger auf eine andere Variable/Konstante ist. Das heißt, es kann die Adresse einer Variablen des Typs enthalten. Beispiel: char *c; bedeutet, dass c die Adresse für ein beliebiges Zeichen enthalten kann, während int *b bedeutet, dass b die Adresse eines bestimmten int enthalten kann. Der Typ der Referenz ist wichtig, da pointer + 1 in der Zeigerarithmetik tatsächlich pointer + (1 * sizeof(*pointer)) ist.

Der * in-Ausdruck bedeutet "der in der Adresse gespeicherte Wert". Wenn also c ein Zeiger auf ein beliebiges Zeichen ist, ist *c das spezifische Zeichen.

char *(*s); bedeutet, dass s ein Zeiger auf einen Zeiger auf char ist, also enthält s nicht die Adresse eines char, sondern die Adresse einer Variablen, die die Adresse eines char enthält.

1
MByD

Die Deklaration von &a bedeutet, dass es auf *i verweist. Immerhin ist es ein Zeiger auf *int. Eine Ganzzahl soll *i zeigen. Wenn jedoch j = *k der Zeiger auf den Zeiger ist, bedeutet dies, dass &k der Wert von k ist und k einen Zeiger auf *int hat.

0

hier ist ein bisschen Information

         variable    pointer
declaring     &a           p

reading/      a            *p

processing
0
Akshatha