2011-09-08 7 views
18
#include<stdio.h> 
main() 
{ int x[3][5]={{1,2,10,4,5},{6,7,1,9,10},{11,12,13,14,15}}; 


printf("%d\n",x); 
printf("%d\n",*x); } 

ここで最初のprintfは最初の要素のアドレスを出力します。 なぜ、2番目のprintfがアドレスxの値、つまり最初の値を出力しないのでしょうか。 値を印刷するには、** xを書く必要があります。Cのポインタのあいまいさを教えてください。

+0

を、あなたは最初のprintfがアドレスではなく、値を出力しますよろしいです? –

答えて

26

ポインタの場合、x[0]は、と同じです。このことから、*x[0]**xと同じです。

*x[0]において:

x式で使用する場合int(*)[5]に変換されるint[3][5]、です。したがって、x [0]はint[5](最初の5要素の「行」)の左辺値で、もう一度int*に変換され、最初の要素に参照解除されます。最初の間接参照を(インデックス付けとは対照的に)、およびNO第間接参照が存在しないアスタリスクで行われる以外

*x

は、同じラインに沿って評価されるので、我々は printfに渡されるタイプ int[5]の左辺値、で終わりますその最初の要素へのポインタとして。

+0

ええと、しかし、私は "x"を印刷するときにアドレスを取得するので、私は操作を* xするとそのアドレスに格納された値を取得する必要があります... – dejavu

+0

はい、いいえ。あなたは実際にアドレスに格納された値を取得します。これは、「int [5] '型の左辺値」です。しかし、配列はCのファーストクラスではなく、最初の要素へのポインタとして関数に渡されます。したがって、 'printf'は、' x'の最初の要素のアドレスと同じアドレスを持つ5の最初の 'int'へのポインタを取得します。 IOW、 '(void *)x ==(void *)* x'そしてあなたが見るものです。 – jpalecek

+0

私は質問を編集しました。これは私の疑問でした...それは誤植でした.. – dejavu

-1

2次元配列は、配列の各要素が別の配列の最初の要素を指すポインタの配列として考えてください。 xを逆参照すると、xが指すメモリ位置にある値が得られます。intの配列の最初のintへのポインタ。そのポインタを逆参照すると、最初の要素が取得されます。

+3

これは正確ではありません。あなたは確かにポインタの配列を持つことで効果的な2-dギザギザの配列を持つことができますが、実際の記憶域は行ごとに順番に並び、逆参照は乗算によって行われます。 – Yuliy

+0

@Yuliy:それはそれがどのように実装されているのか理解していますが、なぜ2度間接参照する必要があるのか​​を理解する簡単な方法です。 – Daniel

+1

@ダニエル:ユリのポイントは立つ。これについてCの初心者にはすでに十分な混乱があり、ポインタの配列として「2次元配列」を割り当てることはあまりにも多く、この誤解を助長するリスクは避けなければなりません。 –

4

配列は、関数の引数として使用すると、配列の最初の要素へのポインタに減衰します。つまり、xが崩壊するオブジェクトのタイプは、intの配列へのポインタである最初のサブアレイへのポインタ、または基本的にはint (*)[5]です。 printf("%d\n",*x)を呼び出すときは、整数値をprintfに渡すのではなく、最初のサブアレイへのポインタをxにします。そのサブアレイは最初のサブアレイの要素へのポインタにも崩壊するので、**xを実行して、その後続のポインタを逆参照し、最初のサブアレイの最初の要素であるxを得ることができます。これは実質的に*x[0]と同じです。演算子の優先順位によって、最初のサブアレイxにインデックスが付けられ、最初のサブアレイが崩壊する最初のサブアレイの要素への参照が参照解除されます。

0

タイプが*xであるため、 '5のintの配列へのポインタ'です。だから、あなたは最初の要素に

PS得るためにもう一つの間接参照が必要になります。

#include <typeinfo> 
#include <iostream> 

typedef int arr[5]; // can't compile if put arr[4] here 
void foo(arr& x) 
{ 
} 

int main() 
{ 
    int x[3][5]={{1,2,10,4,5},{6,7,1,9,10},{11,12,13,14,15}}; 

    std::cout << typeid(*x).name() << std::endl;// output: int [5] 

    foo(x[0]); 
    return 0; 
} 

+0

'* x'の型は' 'int''(' int * ')へのポインタです。配列型が式の中のポインタに崩壊した後、それは 'x'自体であり、その型は" 5の配列のポインタ 'int's"です。 –

+0

Erm、 '* x'の型は" 5 intsの配列 "なので、やや間違っていました。ほとんどの文脈で、それは "intへのポインタ"をタイプするために減衰します。どのような解釈でも、 "5 intsの配列へのポインタ"型はありません。 –

+0

はい、元のメッセージを変更していくつかの「証拠」を追加しました。 – qehgt

関連する問題