2017-01-15 14 views
1

argv []がchar *として定義されています。次のprintfステートメントを使用してください: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]); // 

これは私がわからない最後のものです。 *argv[1]を印刷するとはどういう意味ですか?なぜそれが*argv[1][0]と同じではないのですか?printf("%s\n",*argv[1]);をどうやって印刷できないのですか?また、なぜ&*argv[1]が別のアドレスで&argv[1]と異なるのですか?

+0

['char *'タグページ](http://stackoverflow.com/tags/char-pointer/info)を読むのに役立つかもしれません。おそらくまた[argc]と 'argv'に関する[この質問](http://stackoverflow.com/questions/3024197/what-does-int-argc-char-argv-mean)。 – einpoklum

+1

char *しかしポインタの理解に問題はありません – user3655463

+0

@ user3655463:OPがどのように 'argv [1] [0]'を逆参照したいのかを見て、私は同意しません。 – einpoklum

答えて

3

配列添字操作a[i]*(a + i)として定義される - アドレスaを与え、そのアドレスから、その結果間接参照i要素(ないバイト)をオフセット。したがって、ポインタpを指定すると、*pはに相当する*(p + 0)に相当します。

argvのタイプはchar **です。次のすべてに該当する、ことを考える:

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 

argv[i][j]のタイプはcharあるので、*argv[i][j]は有効な式ではありません。ここで

argvシーケンスの悪い可視化です:

 +---+    +---+           +---+ 
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] | | 
                +---+ 

これは、異なる式の結果を説明するのに役立つことがあります。

4
char *argv[] 

argvアレイ(1)CHARポインタのです。したがって、配列の各要素がポインタであるのは通常の配列です。 argv[0]はポインタ、argv[1]など

argv[0] - 配列の最初の要素です。配列の各要素はcharポインタなので、この値もcharポインタです(すでに述べたように)。

*argv[1] - ここでargv[1]は上記の配列の2番目の要素ですが、argv[1]もcharポインタです。 *を適用するとポインタが逆参照され、argv[1]が指す文字列の最初の文字が取得されます。 これは単なる文字なので、%cを使用してください。

argv[1][0]はすでに配列の2番目の文字列の最初の文字です。つまり、逆参照する余地はもうありません。これは本質的に以前と同じです。厳密に言って強調されているように


は、(1)それは、ポインタへのポインタですが、多分あなたはポインタの配列としての「考える」ことができます。ここではそれについてとにかく詳細:https://stackoverflow.com/a/39096006/3963067

+2

厳密に言うと、 'argv'は配列ではなく、ポインタです。 – HolyBlackCat

+0

@HolyBlackCatがよさそうですか? –

+0

うん、修正していただきありがとうございます。 – HolyBlackCat

2

最後の行printf("%c\n",*argv[1]);は両方argvを逆参照し、配列インデックス1にアクセスしています。つまり、配列の添字アクセス[1]は、逆参照演算子(*)よりhigher precedenceを持つため、これは前の行と同様にargv[1][0]を実行しています。あなたが最初に処理される間接参照演算子を作るための最後の行に式を括弧した場合

しかし、あなたはこれを行うだろう:

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

を今のあなたがプログラムを実行し、最後の行を[1][0]の代わりにargv[0][1]になります。つまり、プログラムを実行するために使用するコマンドラインの2番目の文字です。

3

argv[1]た場合は、その後*argv[1]逆参照ポインタ、charへのポインタで、あなたにargv[1]での文字列の最初の文字を取得し、それがargv[1][0]と同じだと"%c"書式指定子が印刷されています。

argv[1][0]は、ポインタではなくcharです。そのため、参照できません。

+0

ところで、 "dereferensable"の正しいスペルはどういうものか分かりません。 "dereferencable"は醜く見えますが、macOS autocorrectでは間違っているように見えますが、 "dereferensable"は下線が引かれています。誰がスペルが正しいか知っていますか? – ForceBru

2
  1. これはchar *に特定ではありません。
  2. * ptrとptr [0]の違いは何ですか?
  3. + 0が役に立たないので、ptr [0]が*(ptr + 0)または* ptrの砂糖なので違いはありません。

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

%p指定子は、通常の場合にはCの自動void *にあなたのポインタを促進しかしprintf()可変引数リストを使用し、void *を期待していますので。これについて多くのルールがありますが、私はあなたが必要ならばdocを読むことができます。しかし、char *void *に昇格しないでください。printf()を除いてvoid *を除いて、自分でキャストしなければ未定義の動作をします。

+0

なぜ間違っていますか? – DCR

+0

@GovindParmar互換性のあるポインタ型を保証するには、キャストが必要です。 "** p **引数はvoidへのポインタでなければなりません" C11dr§7.21.6.18 – chux

+0

(void *)&argv [1]または&argv [1]を使用するかどうかは同じです。 – DCR

関連する問題