3

a次のシナリオでは、ポインターを介して配列のサイズ (3) を取得するにはどうすればよいcですか? この種の問題を解決するためのパターンは何ですか?

struct struct_point {
  int x;
  int y;
  int z;
};

typedef struct struct_point point;

int test_void_pointer () {
  point a[3] = {{1, 1, 1}, {2, 2, 2}};
  void * b;
  point * c;
  b = a;
  c = b;
  /* get_size_p (c) */
}
4

3 に答える 3

7

できません。ポインターは単なるアドレス、数値であり、その型を除いて、ポインターが指すデータに関する情報は保持しません。


補足: 「配列はポインターに減衰する」と言うのはそのためです。ポインターは本質的に配列に比べて保持する情報が少ないため、それらは「崩壊」します。

配列を関数に渡すときに nims がコメントで指摘しているように、配列は最初の要素へのポインターに自動的に減衰しsizeof、関数で実行しても期待される結果が得られません。ちなみに、これに関するC FAQもあります。

于 2013-10-04T16:35:29.670 に答える
4

C では、配列のサイズに関する情報は配列と共に格納されません。安全に作業するには、その大きさを知る必要があります。

これを回避するためのテクニックがいくつかあります。配列が現在のスコープで静的に宣言されている場合、サイズは次のように決定できます。

size_t size = (sizeof(a) / sizeof(a[0]);

これは、要素を追加するたびにサイズを更新する必要がない場合に便利です。

struct point a[] = {{1, 1, 1}, {2, 2, 2}};
size_t size = (sizeof(a) / sizeof(a[0));

ただし、別の場所から渡された、または例のようにポインターに変換された任意の配列がある場合は、そのサイズを決定する何らかの方法が必要になります。これを行う通常の方法は、サイズを配列とともに (別のパラメーターとして、または配列を含む構造体として) 渡すか、配列がセンチネル値 (の値) を含むことができる型である場合です。指定された型が無効である場合)、配列の最後にセンチネルを追加する必要があるよりも 1 つ大きい配列を割り当て、それを使用して最後に到達した時期を判断できます。

別の引数として長さを渡す方法は次のとおりです。

struct point myfunction(struct point array[], size_t n) {
    for (size_t i = 0; i < n; ++i) {
        struct point p = array[i];
        // do something with p ...
    }
}

または、長さを含む構造として:

struct point_array {
    size_t n;
    struct point elems[];
}
struct point myfunction(struct point_array a) {
    for (size_t i = 0; i < a.n; ++i) {
        struct point p = a.elems[i];
        // do something with p ...
    }
}

センチネル値を配列で直接使用するのはおそらく難しいでしょう。これはstruct point、同じ型である明らかな無効な値がないためです。 NULL ポインターで終了するポインターの数。ポインタを配列にインラインで格納するのではなく、構造体へのポインタを格納することで、それを使用できます。char'\0'struct point

struct point *myfunction(struct point *a[]) {
    for (size_t i = 0; a[i] != NULL; ++i) {
        struct point *p = a[i];
        // do something with p ...
    }
}
于 2013-10-04T17:03:35.257 に答える