2012-04-08 18 views
1

私はこれらの二つの文があります。これら2つのステートメントの違いは何ですか?

printf("%u",a+1); 

printf("%u",(int *)a+1); 

私はこの混乱に出くわしたとき、実は私はこのコードに取り組んでいたが。上記のプログラムの出力を理解するために

#include<stdio.h> 

int main() 
{ 
    int a[2][2]={1,2,3,4}; 
    int i,j; 
    int *p[] = { (int*)a, (int*)a+1, (int*)a+2 }; 
    for(i=0; i<2; i++){ 
    for(j=0; j<2; j++){ 
     printf("%d %d %d %d",* (*(p+i)+j), *(*(j+p)+i), *(*(i+p)+j), *(*(p+j)+i)); 
    } 
    } 
    return 0; 
} 

Output: 

1 1 1 1 
2 2 2 2 
2 2 2 2 
3 3 3 3 

私はこの出力を作っているの違いは、私は上記の二つの文の違いを知っていれば解決することができることを知っているようになりました。

私の現在の理解: (a+1)は、私に配列の2番目の要素のアドレスを与えます。この場合、2-dアレイは、それぞれが2つの要素を有する2 -dアレイとして視覚化することができる。だから(a+1)は私にa[1][0]のアドレスを与えますが、なぜ(int *)a+1に私にa[0][1]のアドレスを与えていますか?

プログラムの違いと出力を説明してください。

ありがとうございました。

+1

あなたのコードに 'printf("%u "、a + 1)'のようなものはありません。 –

答えて

3

イディオム(int*)a+1((int*)a) + 1)として解釈されます。つまり、キャストは加算よりも優先されます。したがって、これは(int*) a)と評価されます。これは、ptr-to-int型の配列のアドレスです。オフセットは1で、配列の2番目の要素(2)を返します。

プログラミングの2つの重要なルール:

ルール1:あなたはレイアウトが機能性を反映させる、コードを書く
ルール2:コードを読むときは、レイアウトではなく機能をお読みください。 (結果:コードをデバッグし、コメントをデバッグしないでください。あなたは

int a[2][2]={1,2,3,4}; 

を宣言)

概念的には、次のような2次元配列思い描く:

1 2 
    3 4 

をしかし、Cは、実際にこのように、メモリの連続ブロックにデータを格納します。

1 2 3 4 

データが「2」を表していることを意味します。× 2 arraインデックスを計算するときはyです。しかし、aを元の型からint *にキャストすると、コンパイラは元の宣言を忘れて、効果的に2次元性を失い、intの単純なベクトルになります。あなたはpは、ベクトルの1次元配列であることが確認でき、このことから

int *p[] = { (int*) a, (int*) a+1,  (int*) a+2 };  // As written 
int *p[] = { (int*) a, ((int*) a) + 1, ((int*) a) + 2 }; // As interpreted 
int *p[] = { &a[0][0], &a[0][1],  &a[1][0] };  // Resulting values 

はここpの宣言を理解する方法ですあなたが(p+i) == (i+p)ことを認識した場合

p[0] = { 1, 2, 3 } 
p[1] = { 2, 3 } 
p[2] = { 3 } 

、最後の2つの項目は、行の最初の2つと同じです。

printf("%d %d %d %d\n",* (*(p+i)+j), *(*(j+p)+i), *(*(i+p)+j), *(*(p+j)+i)); 
01これと同等です

printf("%d %d %d %d\n", p[i+j], p[j+i], p[i+j], p[j+i]); 

次はすべて同じですので、それを注意することは興味深いです:

a[i] 
*(a+i) 
*(i+a) 

それは同じ値を表すためにi[a]を書くために完全に合法です。言い換えれば、コンパイラはあなたがもちろん

printf("%d %d %d %d\n", p[i], i[p], p[1], 1[p]); 

書き込むことができます、あなたのハイテクリードはないあなたはそれを書くことができたほうが良いです。あなたが私のグループにそれを書いたら、あなたは解雇されます。 ;-)

+1

ありがとう、私は今それを得た。キーコンセプトは、キャストよりも優先されます。 –

2

なし、どちらも未定義の動作です。ポインタ値を出力する正しい形式は%pです。 printfに送信するときは、ポインタをvoid*にキャストしてください。

+0

彼は決してポインタ値を印刷しません。それらはすべて2度間接参照されます。 –

+0

@Adam、彼は決して 'printf'中の' a'値が何を表しているかは言いませんでした。彼のコードで宣言されている変数 'a'は配列です。そして、 'a + 1'が表すものを' int * 'にキャストしているので、彼は2番目の場合にポインタ値を出力します。 –

+0

ああ - あなたは質問の最初の部分を指していました。私は実際のコードを参照していました。私たちが混乱したのも不思議ではない。問題をデバッグするには、最初にデバッグを要求している人をデバッグする必要があります。 :-) –

0

多次元C配列は、隣り合って配置された1次元配列のように動作します。したがって、a(通常は(int **))を(int *)に設定すると、a[0]と同じことになります。従って(int *) a + 1&a[0][1]である。そうでなければ、あなたの理解は正しいので、を得る理由はa + 1です。

(この動作は、標準で指定される;しかし、それはそれは良いプログラミング習慣がありません)

+1

'int [M] [N]'は* int *ではなく、実際は全く異なった動作をします。 – interjay

+0

私はそれを取得していないよ。(int *)aは[0]と同じことを私に与えることができますか?少し詳しく説明できますか? –

関連する問題