1

最初と最後のprintfステートメントの出力を説明してください。私は彼らが同じ出力を与えるべきだと思います。

int main()
{
   char arr[5][7][6];
   char (*p)[5][7][6] = &arr;

   printf("%d\n", (&arr + 1) - &arr);
   printf("%d\n", (char *)(&arr + 1) - (char *)&arr);
   printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);
   printf("%d\n", (unsigned)(p + 1) - (unsigned)p);

   return 0;
}

出力:

1
210
42
210
4

4 に答える 4

4

最初にメモリ レイアウトを見てみましょう。

char arr[5][7][6];これarrは配列の配列の配列です。

次のようにメモリに配置されます。

+--------------+ 
|              | arr[0]
+--------------+
|              | arr[1]
+--------------+
|              | arr[2]
+--------------+
|              | arr[3]
+--------------+

etc.

の配列arr[i]の配列ですchar

のようa[i]になります

+--------------+  a[i][0]
|              |
+--------------+
|              |  a[i][1]
+--------------+
|              |  a[i][2]
+--------------+
|              |  a[i][3]
+--------------+

etc

arr[i][j]は の配列ですchars

そう

+--------------+ 
|              | arr[i][j][0]
+--------------+
|              | arr[i][j][1]
+--------------+ 
|              | arr[i][j][2]
+--------------+

etc.

コンパイラは、最初のブロックの名前arrとアドレスを使用してシンボル テーブルにエントリを作成し、合計サイズ (5*6*7 = 210 バイト) も追跡します。

これで式

printf("%d\n", (&arr + 1) - &arr);

ポインター演算です。したがって、すべてのシンボルの型にバインドされます。

これを実際に見てみましょう。

(gdb) p &arr
$1 = (char (*)[5][7][6]) 0x7fffffffe160

arris ポインターの型が表示されますchar (*)[5][6][7]

つまり、配列の配列の配列へのポインターです。ポインター演算は、実際には、ポインターが指している型に関連しています。そのため、型のサイズが重要です。

(gdb) p sizeof(char [5][7][6])
$2 = 210

したがって、型へのポインターはchar [5][6][7]次のようにインクリメントまたはデクリメントされます。

&arr+1 => 0x7fffffffe160 +0xd2 => 0x7fffffffe232

(&arr + 1) - &arr => 0x7fffffffe232 - 0x7fffffffe160=> 0xd2

これで、実際には0xd2が返されます。しかし、ポインター演算の場合、それは1*sizeof(char [5][7][6]) => 1

ポインター演算は、number of sizeof(type)実際のバイト オフセットではなく を返します。

あなたは正しい結果を得ています

printf("%d\n", (char *)(&arr + 1) - (char *)&arr);

キャストのため、char ポインターにしています。したがって、ポインター演算sizeof(char)では、1 バイト サイズの単位が使用されます。したがって、出力は 210 になります。

printf("%d\n", (unsigned)(arr + 1) - (unsigned)arr);

ここarrで、式は型に減衰しchar (*)[7][6]ます。つまり、2 次元配列へのポインターです。指している型のサイズは 6*7 = 42 です。それが結果として得られるものです。

printf("%d\n", (符号なし)(p + 1) - (符号なし)p);

ここでp+1 - pは、ポインタ演算になります1 * sizeof(char(*)[5][6][7])。したがって、ポインター演算では 1 を返す必要があります。ただし、の結果を unsigned にキャストしたため、ポインター演算を放棄し、整数演算を使用します。整数演算を使用しているため、大きな数値のポインター値が処理されるため、実際のバイト オフセットが取得されます。

于 2012-08-10T14:22:43.487 に答える
2

それらがポインターとして扱われた場合、それらは同じ結果を出力しprintfますが、最後に、キャストによって符号なし整数として扱われるように強制しています。したがって、p + 1pは、ポインターの算術規則とは対照的に、整数の算術規則に従って減算されます。

編集

物事をもう少し明確にするために:

  • 2 つのポインターを減算すると、結果はそれらの間の要素の数になります。あなたの場合、それらの間に1つの要素があります
  • ポインターをキャストするunsignedと、コンパイラーに「これらは単なる数字であり、ここには何も表示されません」と伝えられます。そのため、コンパイラはアドレスを数値として扱い、単に減算します。
于 2012-08-10T12:09:33.477 に答える
0

最初に のアドレスをarr取得して 1 を加算し、次にアドレスを減算します。結果は明らかに 1 です。

ただし、最後のものpは へのポインターchar [5][7][7]であり、 using(*p)[x][y][z]は as と見なすことができますp[0][x][y][z]。したがって、 から 210 ( ) バイト離れた(p + 1)と考えることができます。p[1]5 * 7 * 6p

もしそうなら(((unsigned) p) + 1) - ((unsigned) p)、それは1.

于 2012-08-10T12:13:39.057 に答える
0

アドレス間の距離は 1 要素または 210 バイトです

最初の出力は要素の数を出力します最後 - バイト数

于 2012-08-10T12:14:25.603 に答える