C の面接の質問をいくつか読んでいると、「sizeof 演算子を使用せずに C で配列のサイズを見つけるにはどうすればよいですか?」という質問と、次のような解決法が見つかりました。 うまく機能するのですが、なぜそうなるのか理解できません。
#include <stdio.h>
int main() {
int a[] = {100, 200, 300, 400, 500};
int size = 0;
size = *(&a + 1) - a;
printf("%d\n", size);
return 0;
}
予想通り、5 が返されます。
編集:指摘されたこれ答えは、構文が少し異なります。つまり、インデックスの付け方です。
size = (&arr)[1] - arr;
したがって、どちらの質問も有効であり、問題に対するアプローチが少し異なると思います。皆様の多大なご協力と詳細な説明に感謝します。
ベストアンサー1
ポインタに1を加えると、その結果は、指し示された型のオブジェクトのシーケンス(つまり、配列)内の次のオブジェクトの位置になります。 がp
オブジェクトを指している場合int
、 はシーケンス内のp + 1
次のオブジェクトを指します。が5要素の配列(この場合は式)を指している場合、 は次のオブジェクトを指します。int
p
int
&a
p + 1
5要素の配列int
順番に。
2 つのポインタを減算すると (両方が同じ配列オブジェクトを指している場合、または一方が配列の最後の要素を超えた位置を指している場合)、その 2 つのポインタ間のオブジェクト (配列要素) の数が得られます。
式は&a
のアドレスを生成しa
、型はint (*)[5]
( の 5 要素配列へのポインタint
) です。 式はに続く&a + 1
の次の 5 要素配列のアドレスを生成し、型も です。 式はの結果を逆参照し、の最後の要素に続く最初の のアドレスを生成し、型は で、このコンテキストでは型 の式に「減少」します。int
a
int (*)[5]
*(&a + 1)
&a + 1
int
a
int [5]
int *
同様に、式はa
配列の最初の要素へのポインターに「減少」し、型は になりますint *
。
写真が役に立つかもしれません:
int [5] int (*)[5] int int *
+---+ +---+
| | <- &a | | <- a
| - | +---+
| | | | <- a + 1
| - | +---+
| | | |
| - | +---+
| | | |
| - | +---+
| | | |
+---+ +---+
| | <- &a + 1 | | <- *(&a + 1)
| - | +---+
| | | |
| - | +---+
| | | |
| - | +---+
| | | |
| - | +---+
| | | |
+---+ +---+
これは同じストレージの 2 つのビューです。左側では、 の 5 要素配列のシーケンスとして表示されint
、右側では、 のシーケンスとして表示されていますint
。また、さまざまな式とその型も示しています。
注意してください、この表現*(&a + 1)
は未定義の動作:
...
結果が配列オブジェクトの最後の要素の 1 つ後を指す場合、評価される単項 * 演算子のオペランドとして使用してはなりません。
C 2011 オンラインドラフト、6.5.6/9