LoginSignup
0
0

More than 3 years have passed since last update.

【C言語】C言語に配列型はあるのか?

Last updated at Posted at 2021-01-21

配列とは...

まずC言語での話以前に、ほとんどすべてのプログラミング言語(以下、言語)においてどのような形であれ実装されている「配列」とはどのようなものか。

an array data structure, or simply an array, is a data structure...

(『Array data structure』 en.wikipedia.org)

配列とは、複数のデータを連続的に並べたデータ構造。各データをその配列の要素といい、自然数などの添字インデックス)で識別される。

(『配列』, e-words.jp)

つまり配列とは、要素を連続的に並べインデックスを用いて各要素にアクセスするようなデータ構造のこと。ほとんどすべての言語においてそのようなデータ構造は実装されている。またそのようなデータ構造の実装の一つとして次のようなものがある。

配列 は、同じデータ型のオブジェクトのコレクションであり、メモリー内に連続して割り振られます。 配列内の個々のオブジェクト elements は、配列内のそれらの位置を基にしてアクセスされます。

(4章『配列』, IBM i 7.1 ILE C/C++ 解説書)

要素をメモリー内に連続して割り振り、同じデータ型すなわち同じサイズとすることによって配列内のそれらの相対位置を基にしてアクセスできるようにし、インデックスでの識別を可能にしている。すべての言語において上記のようなもの1
が配列の実装として存在しているとは言い切れないが、少なくともC言語においては上記のように実装されている。

配列型とは...

− 配列型(array type)は,要素型(element type)と呼ぶ特定のメンバオブジェクト型をもつ空でないオブジェクトの集合を連続して割り付けたものを表す(36)。

(P26, JIS X 3010:2003)

— An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.

(§ 6.2.5 ISO/IEC 9899:2017)

An array is a data structure that lets you store one or more elements consecutively in memory.

(§ 2.5 The GNU C Reference Manual)

これがC言語(ANSI C)での配列型の定義である。ではその配列型はどのように宣言すればよいのだろうか?

宣言とは...

宣言とは、与えられたidentifiers(識別子)の解釈を指定します。サイズ、スコープなど。宣言は、declaration-specifiers と任意の init-declarator-list からなります。そこでそれぞれを次のように置き換えます。

declaration-specifiers --> T

init-declarator-list --> D1, ...

Tには次のようなものが当てはまります。

int
char
extern float
const int
long int
long long int
unsigned char
auto int
inline
struct a
typedef b

D1には次のようなものが当てはまります。

* ptr
* const ptr
* const * ptr
** ptr
num

配列型の宣言

If in the declaration T D1, D1 has the form D[ expression_opt ] or D[*], then the contained identifier has type “array of T.”

(§ 7.7.3, sgi1999c.pdf, C Language Reference Manual)

つまり、宣言T D1において、D1が、D[式]もしくはD[*]の場合Dに含まれるその識別子はTの配列型を持ちます。また、

You declare an array by specifying the data type for its elements, its name, and the number of elements it can store. Here is an example that declares an array that can store ten integers:

​ int my_array[10];

For standard C code, the number of elements in an array must be positive.

(§ 2.5.1 The GNU C Reference Manual)

また、

A declarator may have the form

​ D[constant-expression]

or

​ D[ ]

In the first case the constant expression is an expression whose value is determinable at compile time, and whose type is int . in the second the constant 1 is used. (Constant expressions are defined precisely in §15.) Such a declarator makes the contained identifier have type ‘‘array.’

(§ 8.4, Dennis M. Ritchie, C Reference Manual)

とあります。つまり、簡単に言うと配列型は、D[]またはD[constant-expression]または...の、array declarator-配列宣言子[]を用いて宣言されたものであるということです。

malloc()

しかし、配列はポインタ型の仕組みを用いて実装されています。

Every time an identifier of array type appears in an expression, it is converted into a pointer to the first member of the array. Because of this conversion, arrays are not lvalues. By definition, the subscript operator [] is interpreted in such a way that ‘‘E1[E2]’’ is identical to ‘‘*( ( E1) + (E2 ) )’’. Because of the conversion rules which apply to +, if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1. Therefore, despite its asymmetric appearance, subscripting is a commutative operation.

(§ 14.3, Dennis M. Ritchie, C Reference Manual)

つまりsubscript operator-サブスクリプト演算子(またはindexing operator-インデクシング演算子)[]はポインタ型に対して定義されて、

int array[3];

== 1 ==  --> == 2 ==
array[1] --> *(array+1) 

== 1 ==の時点でarrayの型はArray of intからPointer of intに変換されています。そして[]演算子は== 2 ==として定義されています。また、

A parameter declared to have array or function type is adjusted to have a pointer type as described in 6.9.1.

(§ 6.5.2 ISO/IEC 9899:2017)

In either case, the type of each parameter is adjusted as described in 6.7.6.3 for a parameter type list; the resulting type shall be a complete object type.

(§ 6.9.1 ISO/IEC 9899:2017)

A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation.

(§ 6.7.6.3 ISO/IEC 9899:2017)

つまり、関数の実引数にTの配列型が指定された場合、そのTの配列型はTのポインタ型に変換され、対応する仮引数に代入される。ということは関数insideにおいてabはともに配列型ではないものの、配列型はそれの要素型と要素の数によって特徴づけられることから考えてabは同等の配列(

abはポインタ型だが配列を象徴していることが明らかまたは、配列にアクセスするためのポインタ型であることが明らかまたは、配列を象徴していないにしてもオフセットを適用することにより、sizeof(int)サイズで3要素数の(同等の)配列にアクセスできるから「配列」呼んでもよいのではないだろうか?「グレーな配列」?

)といえる。

void inside(int * a) {
    int *b = (int *) malloc(3 * sizeof(int));
}

void outside(void) {
    int a[3] = {0, 0, 0};

    inside(a);
}

  1. 配列 は、同じデータ型のオブジェクトのコレクションであり、メモリー内に連続して割り振られます。 配列内の個々のオブジェクト elements は、配列内のそれらの位置を基にしてアクセスされます。 

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0