Zeiger in C: Wann werden das kaufmännische Und und das Sternchen verwendet?

Lesezeit: 12 Minuten

Benutzeravatar von Pieter
Peter

Ich fange gerade erst mit Zeigern an und bin etwas verwirrt. Ich weiss & bedeutet die Adresse einer Variablen und das * kann vor einer Zeigervariablen verwendet werden, um den Wert des Objekts zu erhalten, auf das der Zeiger zeigt. Aber die Dinge funktionieren anders, wenn Sie mit Arrays, Strings arbeiten oder wenn Sie Funktionen mit einer Zeigerkopie einer Variablen aufrufen. Es ist schwierig, in all dem ein logisches Muster zu erkennen.

Wann sollte ich verwenden & und *?

  • Bitte veranschaulichen Sie, wie Sie sehen, dass die Dinge manchmal anders funktionieren. Andernfalls müssen wir raten, was Sie verwirrt.

    – Drew Dormann

    19. Januar 2010 um 15:46 Uhr


  • Stimme Neil Butterworth zu. Wahrscheinlich werde ich viel mehr Informationen bekommen, wenn ich es aus erster Hand aus einem Buch bekomme, und die K & R-Erklärung ist ziemlich klar.

    – Tom

    19. Januar 2010 um 15:55 Uhr

  • Ich stimme nicht mit allen überein, die sagen, dass es keine gute Idee ist, diese Art von Fragen zu SO zu stellen. SO ist die Ressource Nummer 1 bei der Suche auf Google geworden. Sie geben diesen Antworten nicht genug Anerkennung. Lesen Sie die Antwort von Dan Olson. Diese Antwort ist wirklich aufschlussreich und unglaublich hilfreich für Neulinge. RTFM ist nicht hilfreich und ehrlich gesagt sehr unhöflich. Wenn Sie keine Zeit zum Antworten haben, dann seien Sie respektvoll gegenüber denen, die sich die Zeit nehmen, diese Fragen zu beantworten. Ich wünschte, ich könnte das @anon an „anon“ senden, aber offensichtlich hat er/sie nicht die Zeit, einen sinnvollen Beitrag zu leisten.

    – SSH Dies

    28. Januar 2014 um 16:48 Uhr


  • Was SSH gesagt hat, ist absolut wahr. Manche Leute schreien „Just Google it“, aber heutzutage ist es umgekehrt: „Schau einfach auf StackOverflow.“ Diese Frage ist für viele Menschen nützlich. (Daher die Upvotes und keine Downvotes.)

    – MC Kaiser

    18. Dezember 2015 um 15:08 Uhr

  • beej.us/blog/data/c-pointers

    – MmmHmm

    9. November 2017 um 19:04 Uhr

Benutzeravatar von Dan Olson
Dan Olson

Sie haben Hinweise und Werte:

int* p; // variable p is pointer to integer type
int i; // integer value

Mit wandeln Sie einen Zeiger in einen Wert um *:

int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to

Mit wandeln Sie einen Wert in einen Zeiger um &:

int* p2 = &i; // pointer p2 will point to the address of integer i

Bearbeiten: Im Fall von Arrays werden sie sehr ähnlich wie Zeiger behandelt. Wenn Sie sie als Zeiger betrachten, verwenden Sie * um an die darin enthaltenen Werte heranzukommen, wie oben erklärt, aber es gibt auch eine andere, gebräuchlichere Art, die zu verwenden [] Operator:

int a[2];  // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element

So erhalten Sie das zweite Element:

int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element

Also die [] Der Indizierungsoperator ist eine Sonderform des * Operator, und es funktioniert so:

a[i] == *(a + i);  // these two statements are the same thing

  • Wie kommt es, dass das nicht funktioniert? int aX[] = {3, 4}; int *bX = &aX;

    – Peter

    19. Januar 2010 um 18:19 Uhr

  • Arrays sind etwas Besonderes und können transparent in Zeiger umgewandelt werden. Dies zeigt eine andere Möglichkeit, von einem Zeiger zu einem Wert zu gelangen, ich werde es der obigen Erklärung hinzufügen.

    – Dan Olson

    19. Januar 2010 um 18:58 Uhr

  • Wenn ich das richtig verstehe … das Beispiel int *bX = &aX; geht nicht weil die aX gibt bereits die Adresse von zurück aX[0] (dh &aX[0]), Also &aX würde die Adresse einer Adresse bekommen, die keinen Sinn macht. Ist das richtig?

    – Peter

    19. Januar 2010 um 19:23 Uhr

  • Sie haben Recht, obwohl es Fälle gibt, in denen Sie möglicherweise tatsächlich die Adresse der Adresse möchten. In diesem Fall würden Sie es als int** bX = &aX deklarieren, aber dies ist ein fortgeschritteneres Thema.

    – Dan Olson

    19. Januar 2010 um 20:02 Uhr

  • @Dan, gegeben int aX[] = {3,4};, int **bX = &aX; ist ein Fehler. &aX ist vom Typ “Zeiger auf Array [2] von int“, nicht “Zeiger auf Zeiger auf int“. Insbesondere wird der Name eines Arrays nicht als Zeiger auf sein erstes Element für unär behandelt &. Du kannst tun: int (*bX)[2] = &aX;

    – Alok Singhal

    20. Januar 2010 um 3:13 Uhr


Benutzeravatar von John Bode
Johannes Bode

Beim Umgang mit Arrays und Funktionen gibt es ein Muster; es ist anfangs nur etwas schwer zu erkennen.

Beim Umgang mit Arrays ist es hilfreich, sich an Folgendes zu erinnern: Wenn ein Array-Ausdruck in den meisten Kontexten auftritt, wird der Typ des Ausdrucks implizit von „N-Element-Array von T“ in „Zeiger auf T“ konvertiert und sein Wert gesetzt auf das erste Element im Array zeigen. Die Ausnahmen von dieser Regel sind, wenn der Array-Ausdruck als Operand von entweder erscheint & oder sizeof -Operatoren oder wenn es sich um ein Zeichenfolgenliteral handelt, das als Initialisierer in einer Deklaration verwendet wird.

Wenn Sie also eine Funktion mit einem Array-Ausdruck als Argument aufrufen, erhält die Funktion einen Zeiger, kein Array:

int arr[10];
...
foo(arr);
...

void foo(int *arr) { ... }

Deshalb Sie nicht benutze die & Operator für Argumente entsprechend “%s” in scanf():

char str[STRING_LENGTH];
...
scanf("%s", str);

Wegen der impliziten Konvertierung scanf() erhält ein char * Wert, der auf den Anfang des zeigt str Reihe. Dies gilt für jede Funktion, die mit einem Array-Ausdruck als Argument aufgerufen wird (so ziemlich jede der str* Funktionen, *scanf und *printf Funktionen usw.).

In der Praxis werden Sie wahrscheinlich nie eine Funktion mit einem Array-Ausdruck mithilfe von aufrufen & Betreiber, wie in:

int arr[N];
...
foo(&arr);

void foo(int (*p)[N]) {...}

Solcher Code ist nicht sehr verbreitet; Sie müssen die Größe des Arrays in der Funktionsdeklaration kennen, und die Funktion arbeitet nur mit Zeigern auf Arrays bestimmter Größe (ein Zeiger auf ein 10-Elemente-Array von T hat einen anderen Typ als ein Zeiger auf ein 11-Elemente-Array von T).

Wenn ein Array-Ausdruck als Operand für die erscheint & -Operator ist der Typ des resultierenden Ausdrucks “Zeiger auf N-Element-Array von T” oder T (*)[N]was sich von einem Array von Zeigern unterscheidet (T *[N]) und einen Zeiger auf den Basistyp (T *).

Beim Umgang mit Funktionen und Zeigern gilt folgende Regel: Wenn Sie den Wert eines Arguments ändern und ihn im aufrufenden Code widerspiegeln möchten, müssen Sie einen Zeiger auf das Objekt übergeben, das Sie ändern möchten. Auch hier werfen Arrays einen kleinen Schraubenschlüssel in die Arbeit, aber wir werden uns zuerst mit den normalen Fällen befassen.

Denken Sie daran, dass C besteht alle Funktionsargumente nach Wert; Der Formalparameter erhält eine Kopie des Werts im Aktualparameter, und alle Änderungen am Formalparameter werden nicht im Aktualparameter widergespiegelt. Das übliche Beispiel ist eine Swap-Funktion:

void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);

Sie erhalten die folgende Ausgabe:

before swap: a = 1, b = 2
after swap: a = 1, b = 2

Die formalen Parameter x und y sind unterschiedliche Objekte aus a und bändert sich also zu x und y spiegeln sich nicht darin wider a und b. Da wir die Werte von ändern wollen a und bmüssen wir passieren Zeiger zu ihnen auf die Swap-Funktion:

void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);

Jetzt wird Ihre Ausgabe sein

before swap: a = 1, b = 2
after swap: a = 2, b = 1

Beachten Sie, dass wir in der Swap-Funktion die Werte von nicht ändern x und yaber die Werte von was x und y zeigen auf. Schreiben an *x unterscheidet sich vom Schreiben zu x; Wir aktualisieren den Wert nicht in x selbst erhalten wir einen Standort von x und aktualisieren Sie den Wert an dieser Stelle.

Dies gilt auch, wenn wir einen Zeigerwert ändern möchten; wenn wir schreiben

int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);

dann ändern wir den Wert des Eingabeparameters streamnicht was stream verweist aufalso wechselnd stream hat keinen Einfluss auf den Wert von in; Damit dies funktioniert, müssen wir einen Zeiger an den Zeiger übergeben:

int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);

Auch hier werfen Arrays einen kleinen Schraubenschlüssel in die Arbeit. Wenn Sie einen Array-Ausdruck an eine Funktion übergeben, erhält die Funktion einen Zeiger. Aufgrund der Definition der Subskription von Arrays können Sie einen Indexoperator für einen Zeiger genauso verwenden wie für ein Array:

int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}

Beachten Sie, dass Array-Objekte möglicherweise nicht zugewiesen werden; dh Sie können so etwas nicht tun

int a[10], b[10];
...
a = b;

Sie sollten also vorsichtig sein, wenn Sie mit Zeigern auf Arrays arbeiten. etwas wie

void (int (*foo)[N])
{
  ...
  *foo = ...;
}

wird nicht funktionieren.

Benutzeravatar von t0mm13b
t0mm13b

Einfach ausgedrückt

  • & Bedeutet die Adresse vonwerden Sie sehen, dass in Platzhaltern für Funktionen zum Ändern der Parametervariablen wie in C Parametervariablen als Wert übergeben werden, wobei das kaufmännische Und-Zeichen verwendet wird, um als Referenz zu übergeben.
  • * Bedeutet die Dereferenzierung einer Zeigervariablen, was bedeutet, den Wert dieser Zeigervariablen zu erhalten.
int foo(int *x){
   *x++;
}

int main(int argc, char **argv){
   int y = 5;
   foo(&y);  // Now y is incremented and in scope here
   printf("value of y = %d\n", y); // output is 6
   /* ... */
}

Das obige Beispiel veranschaulicht, wie eine Funktion aufgerufen wird foo B. durch Verwendung von Pass-by-Reference, damit vergleichen

int foo(int x){
   x++;
}

int main(int argc, char **argv){
   int y = 5;
   foo(y);  // Now y is still 5
   printf("value of y = %d\n", y); // output is 5
   /* ... */
}

Hier ist eine Illustration zur Verwendung von a Dereferenzierung

int main(int argc, char **argv){
   int y = 5;
   int *p = NULL;
   p = &y;
   printf("value of *p = %d\n", *p); // output is 5
}

Das Obige zeigt, wie wir das bekommen haben Adresse von y und der Zeigervariablen zugewiesen p. Dann wir Dereferenzierung p durch Anhängen der * an die Vorderseite, um den Wert von zu erhalten pdh *p.

smerlins Benutzeravatar
Smerlin

Ja, das kann ziemlich kompliziert sein, da die * wird in C/C++ für viele verschiedene Zwecke verwendet.

Wenn * vor einer bereits deklarierten Variable/Funktion steht, bedeutet dies entweder:

  • a) * gibt Zugriff auf den Wert dieser Variablen (wenn der Typ dieser Variablen ein Zeigertyp ist oder die * Operator).
  • b) * hat die Bedeutung des Multiplikationsoperators, in diesem Fall muss links von der eine weitere Variable stehen *

Wenn * in einer Variablen- oder Funktionsdeklaration erscheint, bedeutet dies, dass diese Variable ein Zeiger ist:

int int_value = 1;
int * int_ptr; //can point to another int variable
int   int_array1[10]; //can contain up to 10 int values, basically int_array1 is an pointer as well which points to the first int of the array
//int   int_array2[]; //illegal, without initializer list..
int int_array3[] = {1,2,3,4,5};  // these two
int int_array4[5] = {1,2,3,4,5}; // are identical

void func_takes_int_ptr1(int *int_ptr){} // these two are identical
void func_takes_int_ptr2(int int_ptr[]){}// and legal

Wenn & in einer Variablen- oder Funktionsdeklaration erscheint, bedeutet dies im Allgemeinen, dass diese Variable eine Referenz auf eine Variable dieses Typs ist.

Wenn & vor einer bereits deklarierten Variablen erscheint, gibt es die Adresse dieser Variablen zurück

Außerdem sollten Sie wissen, dass Sie beim Übergeben eines Arrays an eine Funktion immer auch die Arraygröße dieses Arrays übergeben müssen, außer wenn das Array so etwas wie ein 0-terminierter Cstring (Char-Array) ist.

Ich habe all die wortreichen Erklärungen durchgesehen, also habe ich mich stattdessen einem Rettungsvideo der University of New South Wales zugewandt. Hier ist die einfache Erklärung: Wenn wir eine Zelle haben, die eine Adresse hat x und Wert 7der indirekte Weg, um nach einer Wertadresse zu fragen 7 ist &7 und der indirekte Weg, um den Wert an der Adresse zu erfragen x ist *x.So (cell: x , value: 7) == (cell: &7 , value: *x) .Eine andere Möglichkeit, es zu untersuchen: John sitzt, gesessen 7th seat.Das *7th seat wird darauf hinweisen John und &John wird geben address/Standort der 7th seat. Diese einfache Erklärung hat mir geholfen und hoffe, dass sie auch anderen helfen wird. Hier der Link zu dem tollen Video: Klick hier.

Hier ist ein weiteres Beispiel:

#include <stdio.h>

int main()
{ 
    int x;            /* A normal integer*/
    int *p;           /* A pointer to an integer ("*p" is an integer, so p
                       must be a pointer to an integer) */

    p = &x;           /* Read it, "assign the address of x to p" */
    scanf( "%d", &x );          /* Put a value in x, we could also use p here */
    printf( "%d\n", *p ); /* Note the use of the * to get the value */
    getchar();
}

Erweiterung: Initialisieren Sie den Zeiger immer, bevor Sie ihn verwenden. Andernfalls zeigt der Zeiger auf irgendetwas, was zum Absturz des Programms führen kann, da das Betriebssystem Sie daran hindert, auf den Speicher zuzugreifen, von dem es weiß, dass Sie es nicht besitzen. Aber einfach setzen p = &x;weisen wir dem Zeiger einen bestimmten Ort zu.

Ich glaube du bist etwas verwirrt. Sie sollten ein gutes Tutorial/Buch über Zeiger lesen.

Dies Tutorial ist sehr gut für den Anfang (erklärt deutlich, was & und * sind). Und ja, vergiss nicht, das Buch zu lesen Zeiger in C von Kenneth Reek.

Der Unterschied zwischen & und * ist sehr klar.

Beispiel:

#include <stdio.h>

int main(){
  int x, *p;

  p = &x;         /* initialise pointer(take the address of x) */
  *p = 0;         /* set x to zero */
  printf("x is %d\n", x);
  printf("*p is %d\n", *p);

  *p += 1;        /* increment what p points to i.e x */
  printf("x is %d\n", x);

  (*p)++;         /* increment what p points to i.e x */
  printf("x is %d\n", x);

  return 0;
}

Benutzeravatar von Jay Conrod
Jay Conrod

Wenn Sie eine Zeigervariable oder einen Funktionsparameter deklarieren, verwenden Sie das *:

int *x = NULL;
int *y = malloc(sizeof(int)), *z = NULL;
int* f(int *x) {
    ...
}

NB: Jede deklarierte Variable benötigt ihre eigene *.

Wenn Sie die Adresse eines Werts übernehmen möchten, verwenden Sie &. Wenn Sie den Wert in einem Zeiger lesen oder schreiben möchten, verwenden Sie *.

int a;
int *b;
b = f(&a);
a = *b;

a = *f(&a);

Arrays werden normalerweise nur wie Zeiger behandelt. Wenn Sie einen Array-Parameter in einer Funktion deklarieren, können Sie ihn genauso einfach als Zeiger deklarieren (das bedeutet dasselbe). Wenn Sie ein Array an eine Funktion übergeben, übergeben Sie tatsächlich einen Zeiger auf das erste Element.

Funktionszeiger sind die einzigen Dinge, die den Regeln nicht ganz folgen. Sie können die Adresse einer Funktion nehmen, ohne & zu verwenden, und Sie können einen Funktionszeiger aufrufen, ohne * zu verwenden.

1427570cookie-checkZeiger in C: Wann werden das kaufmännische Und und das Sternchen verwendet?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy