2017-06-01 3 views
0

Ich habe ein sehr seltsames Beispiel für Zeiger, die Ihre freundliche Hilfe erfordert. Im Allgemeinen werden Zeiger verwendet, um auf eine Variable zu zeigen (siehe erstes Beispiel unten), aber wenn sie auf ein Array zeigt. Ich verstehe nicht, warum es nicht mehr deferencing erfordert das Array zu erhalten (siehe zweites Beispiel unten)Subtile Konzept von Zeigern und Array

printf("TEST: %i\n", x[i]);// I expect this should be *x[i] 

Dies ist in der Tat sehr seltsam. Ist es nur eine C-Konvention oder wie erklärst du das?

EDIT:: Da viele eine klare Antwort geliefert haben, möchte ich eine weitere kleine Follow-up-Frage, wie Sie alle erwähnt x [i] = * (x + i), was ist mit x [i] [j] für ein zweidimensionales Array? Was ist das? Benötigt es Dereferenzierung?

Bei einer normalen Variable

int j = 4; 
int* pointerj=&j;//pointerj holds address of j or points to j 
printf("%d",*pointerj); returns the value that pointer j points to 

Mit einem Array:

#include <stdio.h> 
#include <stdlib.h> 

int *function(unsigned int tags) { 
    int i; 
    int *var; 

    var = (int*)malloc(sizeof(int)*tags); // malloc is casted to int* type , allocated dynamical memory, it returns a pointer! 
    //so now var holds the address to a dynamical array. 

    for (i = 0; i < tags; i++) { 
     var[i] = i; 
    } 

    return var; 
} 

int main() { 
    int *x; 
    int i; 

    x = function(10); 
    for (i = 0; i < 10; i++) { 
     printf("TEST: %i\n", x[i]);// I expect this should be *x[i] 
    } 

    free(x); x = NULL; 

    return 0; 
} 
+0

'x [i]' ist äquivalent zu '* (x + i)'. In der Tat bedeutet das, dass man '* x' als' x [0] 'schreiben könnte. –

+0

Sie möchten vielleicht überprüfen [this] (https://stackoverflow.com/questions/381542/with-arrays-why-is-it-the-case-that-a5-5a) – Badda

+0

@OliverCharlesworth Oh! Als Python-Programmierer wurde ich durch diese Konvention völlig in die Irre geführt !! Prost –

Antwort

3

verstehe nicht, warum es nicht. mehr erfordert dereferencing das Array (Element)

Gut zu erhalten, Sie sind dereferencing, es ist nur nicht mit der dereferen ce Betreiber *.

Der Array Subscripting Operator [] dient hier als Dereferenzierungsaufgabe. C11 zitiert, Kapitel §6.5.2.1

A Postfix Ausdruck durch einen Ausdruck in eckigen Klammern [] ist eine indizierte Bezeichnung eines Elements eines Arrays Objekts. Die Definition des tiefgestellten Operators [] ist, dass E1[E2] identisch mit (*((E1)+(E2))) ist. Aufgrund der Konvertierungsregeln, die auf den binären + Operator anzuwenden , wenn E1 ist ein Array-Objekt (äquivalent, ein Zeiger auf das Anfangs- Element eines Array-Objekts) und E2 eine ganze Zahl ist, bezeichnet das E1[E2]E2 -te Element E1 (von Null ausgehend).

Es ist ein syntaktischer Zucker. Die Ausdrücke x[i] und *(x+i) sind äquivalent. Letzteres erfüllt Ihre Erwartungen, während der erste den Dereferenzierungsoperator tarnt, aber genau die gleiche Aufgabe erfüllt, die Sie erwartet haben.


Das gesagt, auch folgen Sie dem Datentyp eng. Was Sie erwartet haben, wäre etwas auf der Linie von *x[i] einfach ungültig, da es auf etwas wie '( (x + i)) läuft. Nun

  • x ist vom Typ int [] (Integer-Array, das auf einen Zeiger auf integer zerfällt)
  • x+i gibt Ihnen einen Zeiger auf int Typ Ergebnis.
  • der interne Dereferenzierungsoperator wird darauf angewendet, was zu einem int führt.
  • Die äußerte *, wird nun versuchen, auf einem Operanden vom Typ int (keinen Zeiger) zu arbeiten, und wird diese Operation ein syntaktischer Fehler sein, da, sagt die Einschränkung für Dereferenzierungsoperator,

Der Operand des unären Operators * soll einen Zeigertyp haben.

in C11, Kapitel §6.5.3.2.


die zusätzliche Frage zu beantworten:

Lassen Sie mich das Angebot nutzen, noch einmal, dieses irgendjemandes von Absatz 2, Kapitel §6.5.2.1

Sukzessive Index Betreiber bezeichnen ein Element eines mehrdimensionalen Array-Objekts. E Wenn ein n -dimensionalen Array (n ≥ 2) mit Abmessungen i × j × . . . × k, dann E (verwendet als andere als ein L-Wert) wird mit j × . . . × k Abmessungen auf einen Zeiger auf eine (n − 1) -dimensionalen Array umgewandelt. Wenn der unäre Operator * explizit auf diesen Zeiger oder implizit als Folge von Subskribierung angewendet wird, ist das Ergebnis das referenzierte Array (n − 1)-dimensional , das selbst in einen Zeiger konvertiert wird, wenn es anders als ein Lvalue verwendet wird. Daraus folgt , dass Arrays in Reihe-Haupt-Reihenfolge gespeichert werden (letzter Index variiert am schnellsten).

das Array-Objekt Betrachten durch die Erklärung definiert

int x[3][5]; 

x Hier ist eine Anordnung von 3 × 5int s; genauer gesagt ist x ein Array von drei Elementobjekten, von denen jedes ein Array von fünf Ints ist. In dem Ausdruck x[i], der äquivalent zu (*((x)+(i))) ist, wird x zuerst in einen Zeiger auf das anfängliche Array von fünf Ints konvertiert. Dann wird i gemäß dem Typ von x eingestellt, was konzeptuell das Multiplizieren von i mit der Größe des Objekts, auf das der Zeiger zeigt, nämlich ein Array von fünf Objekten umfasst. Die Ergebnisse werden hinzugefügt, und die Indirektion wird angewendet, um ein Array von fünf Ints zu erhalten. Wenn dieses Array in dem Ausdruck x[i][j] verwendet wird, wird dieses Array wiederum in einen Zeiger auf das erste der Ints konvertiert, so dass x[i][j] einen int ergibt.

+0

Es tut mir sehr leid, könnten Sie das in einfacheren Worten für diesen Teil erklären? Ausgehend von wird x zuerst in einen Zeiger auf das anfängliche Array von fünf Ints konvertiert. Ich bin verloren .. –

+0

@elpsyCongroo Ich werde es sicherlich versuchen, bitte erlauben Sie mir etwas Zeit, ich bin ein wenig beschäftigt, jetzt werde ich mit einer non-formalen Erklärung zurückkommen. Das macht Sinn? –

1

Das ist ok. Nicht hier.

Wenn Sie Zeiger int *a haben, die Anordnung von gültigen Datenpunkten, zum Beispiel:

int *a; 
int arr[5] = {1, 2, 3, 4, 5]; 
a = arr; 

von a[0] verwenden Sie bereits dereferencing Zeiger und * ist nicht erforderlich, da a[0] die gleiche wie *(a + 0) ist.


Sie können weiter gehen und noch komplizierter Code für Leser.

Sie können i[x] in Ihrem Beispiel anstelle von x[i] verwenden. Warum? x[i] gleich *(x + i) aber es ist auch gleichbedeutend mit *(i + x) das ist, was Arrays sind in C.

Es funktioniert sogar mit Zahlen, wie x[3] oder 3[x] geben Sie das gleiche Ergebnis.

1

In C ist das Ausführen von x [i] äquivalent (ja, ich weiß) bei i [x]. Ihr Compiler kompiliert dies, indem Sie:

* (x + i), wo Sie Ihre Lieblings-Symbol abrufen.

x + i ist ein Zeiger, bei dem Sie von x aus beginnen und mit i fortfahren. Das Ergebnis berücksichtigt den Typ des Zeigers (0xff ist nicht die gleiche Adresse für ein Zeichen * als für ein int *).

+0

was ist das: * yeah ich weiß *? – tilz0R

+0

Nur um zu zeigen, dass ich [x] mache, ist seltsam, aber funktioniert. – Gaulois94

+0

@ Gaulois94 Entschuldigung, was bedeutet ich [x]? Es verwirrt mich jetzt .. Wie kann ein Index außerhalb des Arrays gehen? Ich bin der Index des Elements des Arrays, oder? –

1

Sie haben missverstanden, wie Arrays funktionieren. Wenn nämlich eine Variable wie int verwenden, sollten Sie es Adresse zugreifen, indem

int x; int *p2x = &x

aber wenn Array, dann ist es ein bisschen anders. int y[SOME_SIZE]; ist ein Stück von Bytes im Speicher, und *y wird Sie zum ersten Element in diesem Speicherort führen, und es dereferenzieren. y[0] wird das gleiche tun. *y[0] wird zuerst den Wert in y[0] nehmen und dann versuchen, es zu dereferenzieren ...nicht das, was Sie in der Regel :(wollen

1

die einfache Antwort auf Ihre Frage ist, dass:

Der Name des Arrays ist Zeiger auf das erste Element des Arrays

+1

Nicht wirklich, Sie haben nichts als eine Faustregel erklärt ... –

+1

@elpsyCongroo sicher ist es wahr. Wenn Sie die Variable direkt verwenden, wird der Zeiger auf das erste Element verwendet. – tilz0R

+0

Bitte lesen Sie [Wie schreibe ich eine gute Antwort?] (Http://stackoverflow.com/help/how-to-answer), bevor Sie weitere Fragen beantworten. –