2017-01-15 7 views
1

verstehen Ich habe argv [] als char * definiert. Verwenden Sie die folgenden printf-Anweisungen:Die tiefgründigen Operatoren Dereferenzierung, Adressierung und Array in C

 printf("%s\n",argv[1]); // prints out the entire string 
    printf("%p\n",&argv[1]); // & -> gets the address 
    printf("%c\n",argv[1][0]);// prints out the first char of second var 
    printf("%c\n",*argv[1]); // 

Es ist das letzte, das ich nicht verstehe. Was bedeutet es, *argv[1] zu drucken? Warum ist das nicht dasselbe wie *argv[1][0] und wie kommt es, dass Sie printf("%s\n",*argv[1]); nicht ausdrucken können. Auch, warum ist &*argv[1] eine andere Adresse als &argv[1]?

+0

Es kann Ihnen helfen, die ['char *' Tag-Seite] (http://stackoverflow.com/tags/char-pointer/info) zu lesen. Vielleicht auch [diese Frage] (http://stackoverflow.com/questions/3024197/what-does-int-argc-char-argv-mean) bezüglich 'argc' und' argv'. – einpoklum

+1

Es ist kein Problem mit dem Verständnis char *, sondern Zeiger – user3655463

+0

@ user3655463: Sehen, wie OP dereferenzieren wollte 'argv [1] [0] ', stimme ich nicht zu. – einpoklum

Antwort

3

Der Array-Index Betrieb a[i] als *(a + i) definiert wird - angesichts der a Adresse, Offset- i Elemente (nicht Bytes) von dieser Adresse und dereferenzieren das Ergebnis. Bei einem Zeiger entspricht also *p*(p + 0), was p[0] entspricht.

Der Typ argv ist char **; gegeben, dass alle folgenden Bedingungen erfüllt sind: char die Art der argv[i][j] ist

Expression   Type   Value 
    ----------   ----   ----- 
      argv   char **   Pointer to a sequence of strings 
     *argv   char *   Equivalent to argv[0] 
     **argv   char   Equivalent to argv[0][0] 
     argv[i]   char *   Pointer to a single string 
     *argv[i]   char   Same as argv[i][0] 
    argv[i][j]   char   j'th character of i'th string 
     &argv[i]   char **   Address of the pointer to the i'th string 

Da *argv[i][j] ist kein gültiger Ausdruck.

Hier ist eine schlechte Visualisierung der argv Sequenz:

 +---+    +---+           +---+ 
argv | | ---> argv[0] | | ---------------------------> argv[0][0] | | 
    +---+    +---+      +---+    +---+ 
       argv[1] | | -------> argv[1][0] | | argv[0][1] | | 
         +---+      +---+    +---+ 
         ...   argv[1][1] | |    ... 
         +---+      +---+    +---+ 
      argv[argc] | | ---|||    ... argv[0][n-1] | | 
         +---+      +---+    +---+ 
            argv[1][m-1] | | 
                +---+ 

Dies kann helfen, die Ergebnisse der verschiedenen Ausdrücke zu erklären.

4
char *argv[] 

argv ist Array (1) von char Zeigern. Es ist also normal Array, nur jedes Element des Arrays ist ein Zeiger. argv[0] ist ein Zeiger, argv[1], usw.

argv[0] - erstes Element im Array. Da jedes Element im Array ein char-Zeiger ist, ist der Wert auch ein char-Zeiger (wie bereits oben erwähnt).

*argv[1] - Jetzt hier argv[1] ist zweites Element in der obigen Array, aber argv[1] ist auch ein Char-Zeiger. Das Anwenden von * dereferenziert einfach den Zeiger und Sie erhalten das erste Zeichen in der Zeichenfolge, auf die argv[1] verweist. Sie sollten %c verwenden, um es zu drucken, da dies nur ein Zeichen ist.

argv[1][0] ist bereits das erste Zeichen der zweiten Zeichenfolge im Array - also kein Platz mehr für Dereferenzierung. Dies ist im Wesentlichen das Gleiche wie zuvor.


(1) streng hervorgehoben sagen, es ist Zeiger auf Zeiger, aber vielleicht können Sie „denken“ es als Array von Zeigern. Auf jeden Fall weitere Informationen über es hier: https://stackoverflow.com/a/39096006/3963067

+2

Streng gesagt ist "argv" kein Array, sondern ein Zeiger. – HolyBlackCat

+0

@HolyBlackCat sieht besser aus? –

+0

Ja, danke für die Lösung. – HolyBlackCat

2

Die letzte Zeile printf("%c\n",*argv[1]); ist dereferencing sowohl argv und den Zugriff auf Array-Index 1. Mit anderen Worten, dies geschieht argv[1][0], genau wie die vorherige Zeile, weil der Array-Indexzugriff [1] einen higher precedence als den Dereferenzierungsoperator (*) hat.

Wenn Sie jedoch den Ausdruck in der letzten Zeile klammern sind den Dereferenzierungsoperator zu machen zuerst verarbeitet werden, würden Sie dies tun:

printf("%c\n", (*argv)[1]); 

Nun, wenn Sie das Programm ausführen, die letzte Zeile Ausgabe wäre argv[0][1] anstelle von [1][0], dh das zweite Zeichen in der Befehlszeile, die Sie verwenden, um das Programm auszuführen.

3

Wenn argv[1] ist ein Zeiger auf char, dann *argv[1] Dereferenzierungen dass Zeiger und bringt Sie das erste Zeichen der Zeichenfolge an argv[1], so ist es das gleiche wie argv[1][0] und mit dem "%c" Formatspezifizierer gedruckt.

argv[1][0] ist ein char selbst, kein Zeiger, so dass es nicht dereferentierbar ist.

+0

BTW, ich bin nicht ganz sicher, was ist die richtige Schreibweise für "dereferensable" als "dereferencable" sieht hässlich aus und ist durch macOS autocorrect als falsch unterstrichen, aber "dereferensable" fühlt sich besser an, obwohl auch unterstrichen wird. Weiß jemand, welche Rechtschreibung richtig ist? – ForceBru

2
  1. Dies ist nicht spezifisch für char *.
  2. Sie können vereinfachen, was ist der Unterschied zwischen * ptr und ptr [0].
  3. Es gibt keinen Unterschied, weil ptr [0] ein Zucker für * (ptr + 0) oder * ptr ist, weil + 0 nutzlos ist.

// printf("%p\n", &argv[1]); is wrong you must cast to (void *) 
printf("%p\n", (void *)&argv[1]); 

Da %p Spezifizierer ein void * im Normalfall C auto fördern Sie den Mauszeiger in void * aber printf() Verwendung variable Argumentliste erwarten. Es gibt eine Menge Regel darüber, ich lasse Sie die doc lesen, wenn Sie möchten. Aber char * wiil nicht zu void * fördern und wie ich sage printf() außer void * so haben Sie ein undefiniertes Verhalten, wenn Sie es nicht selbst zu werfen.

+0

Warum ist es falsch? Es wird eine Adresse ausgegeben – DCR

+0

@GovindParmar Die Besetzung wird benötigt, um einen kompatiblen Zeigertyp zu gewährleisten. "** p ** Das Argument soll ein Zeiger auf void sein." C11dr §7.21.6.1 8 – chux

+0

Ich bekomme die gleiche Adresse, ob ich (void *) & argv [1] oder & argv [1] – DCR