このコードは、sizeof() を使用せずに配列のサイズをどのように決定するのでしょうか? 質問する

このコードは、sizeof() を使用せずに配列のサイズをどのように決定するのでしょうか? 質問する

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要素の配列(この場合は式)を指している場合、 は次のオブジェクトを指します。intpint&ap + 15要素の配列int順番に。

2 つのポインタを減算すると (両方が同じ配列オブジェクトを指している場合、または一方が配列の最後の要素を超えた位置を指している場合)、その 2 つのポインタ間のオブジェクト (配列要素) の数が得られます。

式は&aのアドレスを生成しa、型はint (*)[5]( の 5 要素配列へのポインタint) です。 式はに続く&a + 1の次の 5 要素配列のアドレスを生成し、型も です。 式はの結果を逆参照し、の最後の要素に続く最初の のアドレスを生成し、型は で、このコンテキストでは型 の式に「減少」します。intaint (*)[5]*(&a + 1)&a + 1intaint [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

おすすめ記事