1. ホーム
  2. c

[解決済み] sizeof()を使用せずに配列のサイズを決定する方法は?

2022-06-23 16:22:38

質問

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を返します。

edit: 人々が指摘した これ という回答がありましたが、構文が少し違っています。

size = (&arr)[1] - arr;

ということで、どちらの質問も有効で、問題に対するアプローチが少し違うのだと思います。皆さん、絶大な助けと丁寧な説明をありがとうございました!

どのように解決するのですか?

ポインタに1を足すと、その結果は、指された型のオブジェクトのシーケンス(つまり、配列)の次のオブジェクトの位置になります。 もし p を指している場合 int オブジェクトを指定すると p + 1 は次の int を指します。 もし p が5要素の配列を指している場合 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 の 5 要素の配列のシーケンスとして、一方右側では int . また、様々な表現とその種類も示している。

注意することは、式 *(&a + 1) の結果は 未定義の動作 :

...

結果が配列オブジェクトの最後の要素の1つ前を指している場合,その配列オブジェクトは は,評価される単項演算子のオペランドとして使用してはならない。

C 2011 オンラインドラフト , 6.5.6/9