403 Stimmen

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

Ich fange gerade erst an, mit Zeigern zu arbeiten, und bin etwas verwirrt. Ich weiß & die Adresse einer Variablen bedeutet und dass * kann vor einer Zeigervariablen verwendet werden, um den Wert des Objekts zu erhalten, auf das der Zeiger zeigt. Anders sieht es aus, wenn Sie mit Arrays oder 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 die & y * ?

738voto

Dan Olson Punkte 21991

Sie haben Zeiger und Werte:

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

Sie verwandeln einen Zeiger in einen Wert mit * :

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

Sie verwandeln einen Wert in einen Zeiger mit & :

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

Bearbeiten: Im Falle von Arrays werden sie sehr ähnlich wie Zeiger behandelt. Wenn Sie sie als Zeiger betrachten, werden Sie mit * um auf die Werte darin zuzugreifen, wie oben erklärt, aber es gibt auch einen anderen, gebräuchlicheren Weg, indem man die [] Betreiber:

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

Um das zweite Element zu erhalten:

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 [] Indexierungsoperator ist eine spezielle Form des * Operator, und das funktioniert so:

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

40voto

John Bode Punkte 112486

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

Beim Umgang mit Arrays ist es nützlich, sich an Folgendes zu erinnern: Wenn ein Array-Ausdruck in den meisten Kontexten auftaucht, wird der Typ des Ausdrucks implizit von "N-Element-Array von T" in "Zeiger auf T" umgewandelt, und sein Wert wird so gesetzt, dass er auf das erste Element im Array zeigt. Die Ausnahmen von dieser Regel sind, wenn der Array-Ausdruck als Operand von entweder der & ou sizeof Operatoren oder wenn es sich um ein Zeichenkettenliteral 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 und nicht ein Array:

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

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

Aus diesem Grund müssen Sie nicht verwenden Sie die & Operator für Argumente, die "%s" entsprechen, in scanf() :

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

Wegen der impliziten Umwandlung, scanf() erhält eine char * Wert, der auf den Anfang der Datei str Array. Dies gilt für jede Funktion, die mit einem Array-Ausdruck als Argument aufgerufen wird (so gut wie jede der str* Funktionen, *scanf y *printf Funktionen, usw.).

In der Praxis werden Sie wahrscheinlich nie eine Funktion mit einem Array-Ausdruck aufrufen, indem Sie die & Operator, wie in:

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

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

Solcher Code ist nicht sehr gebräuchlich; Sie müssen die Größe des Arrays in der Funktionsdeklaration kennen, und die Funktion funktioniert nur mit Zeigern auf Arrays bestimmter Größen (ein Zeiger auf ein 10-Elemente-Array von T ist ein anderer Typ als ein Zeiger auf ein 11-Elemente-Array von T).

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

Im Umgang mit Funktionen und Zeigern gilt die folgende Regel: Wenn Sie den Wert eines Arguments ändern wollen und dies im aufrufenden Code widergespiegelt werden soll, müssen Sie einen Zeiger auf das zu ändernde Objekt übergeben. Auch hier machen Arrays die Sache etwas komplizierter, aber wir werden uns zuerst mit den normalen Fällen beschäftigen.

Denken Sie daran, dass C die todos Funktionsargumente nach Wert; der formale Parameter erhält eine Kopie des Wertes im aktuellen Parameter, und alle Änderungen am formalen Parameter werden nicht im aktuellen Parameter berücksichtigt. Das gängige 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 werden die folgende Ausgabe erhalten:

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

Die formalen Parameter x y y sind unterschiedliche Objekte von a y b , also Änderungen an x y y werden nicht reflektiert in a y b . Da wir die Werte von a y b müssen wir passieren Zeiger zu ihnen in 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);

Ihre Ausgabe wird nun sein

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

Beachten Sie, dass wir in der Swap-Funktion nicht die Werte von x y y sondern die Werte dessen, was x y y zeigen auf . Schreiben an *x ist anders als das Schreiben an x ; wir aktualisieren nicht den Wert 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 wollen; wenn wir schreiben

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

dann ändern wir den Wert des Eingabeparameters stream nicht das, was stream zeigt auf so ändern stream hat keinen Einfluss auf den Wert von in Damit dies funktioniert, müssen wir einen Zeiger auf den Zeiger übergeben:

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

Auch hier bringen Arrays ein wenig Unruhe ins Spiel. Wenn Sie einen Array-Ausdruck an eine Funktion übergeben, erhält die Funktion einen Zeiger. Aufgrund der Definition von Array Subscripting können Sie einen Subscript-Operator für einen Zeiger auf die gleiche Weise 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 nicht zugewiesen werden dürfen, d.h. Sie können nicht etwas tun wie

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.

32voto

t0mm13b Punkte 33393

Einfach ausgedrückt

  • & bedeutet die Adresse von Sie werden sehen, dass in Platzhaltern für Funktionen zum Ändern der Parametervariablen wie in C, Parametervariablen als Wert übergeben werden, wobei das kaufmännische Und bedeutet, dass sie als Referenz übergeben werden.
  • * bedeutet die Dereferenzierung einer Zeigervariablen, d.h. um 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 zeigt, wie man eine Funktion aufruft foo durch die Verwendung von pass-by-reference, vgl.

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 der Verwendung einer 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
}

Die obige Darstellung zeigt, wie wir die Adresse von y und wies es der Zeigervariablen p . Dann haben wir Dereferenzierung p durch Anbringen der * vorangestellt, um den Wert von p である、すなわち。 *p .

20voto

smerlin Punkte 6156

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

Si * vor einer bereits deklarierten Variablen/Funktion erscheint, bedeutet dies entweder, dass:

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

Si * 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

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

Si & vor einer bereits deklarierten Variablen steht, gibt sie die Adresse dieser Variablen zurück

Außerdem sollten Sie wissen, dass Sie bei der Übergabe eines Arrays an eine Funktion immer auch die Array-Größe des Arrays übergeben müssen, es sei denn, das Array ist ein 0-terminierter cstring (char-Array).

10voto

Ich habe mich durch all die wortreichen Erklärungen gewühlt und mich stattdessen an ein Video der University of New South Wales gewandt, um es zu retten, und hier ist die einfache Erklärung: Wenn wir eine Zelle haben, die die Adresse x und Wert 7 die indirekte Art, nach einer Adresse von Wert zu fragen 7 es &7 und der indirekte Weg, den Wert an der Adresse zu erfragen x es *x .also (cell: x , value: 7) == (cell: &7 , value: *x) Eine andere Art, sich damit zu befassen: John sitzt bei 7th seat Die *7th seat zeigt auf John y &John wird geben address /Standort des 7th seat . Diese einfache Erklärung hat mir geholfen und ich hoffe, sie hilft auch anderen. Hier ist der Link zu dem hervorragenden Video: klicken Sie hier.

Hier 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();
}

Add-on: Andernfalls zeigt der Zeiger auf irgendetwas, was zum Absturz des Programms führen kann, weil das Betriebssystem den Zugriff auf den Speicher verhindert, von dem es weiß, dass er Ihnen nicht gehört. p = &x; weisen wir dem Zeiger einen bestimmten Ort zu.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X