summaryrefslogtreecommitdiff
path: root/devdocs/c/language%2Farray.html
blob: 34623494d86d46a41bffe80701bf9ec12c0e21fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    <h1 id="firstHeading" class="firstHeading">Array declaration</h1>            <p>Array is a type consisting of a contiguously allocated nonempty sequence of objects with a particular <i>element type</i>. The number of those objects (the array size) never changes during the array lifetime.</p>
<h3 id="Syntax"> Syntax</h3> <p>In the <a href="declarations" title="c/language/declarations">declaration grammar</a> of an array declaration, the <i>type-specifier</i> sequence designates the <i>element type</i> (which must be a complete object type), and the <i>declarator</i> has the form:</p>
<table class="t-sdsc-begin">  <tr class="t-sdsc"> <td> <code>[</code> <code>static</code><span class="t-mark">(optional)</span> <span class="t-spar">qualifiers</span> <span class="t-mark">(optional)</span> <span class="t-spar">expression</span> <span class="t-mark">(optional)</span> <code>]</code> <span class="t-spar">attr-spec-seq</span> <span class="t-mark">(optional)</span> </td> <td> (1) </td> <td class="t-sdsc-nopad"> </td>
</tr>  <tr class="t-sdsc"> <td> <code>[</code> <span class="t-spar">qualifiers</span> <span class="t-mark">(optional)</span> <code>static</code><span class="t-mark">(optional)</span> <span class="t-spar">expression</span> <span class="t-mark">(optional)</span> <code>]</code> <span class="t-spar">attr-spec-seq</span> <span class="t-mark">(optional)</span> </td> <td> (2) </td> <td class="t-sdsc-nopad"> </td>
</tr>  <tr class="t-sdsc"> <td> <code>[</code> <span class="t-spar">qualifiers</span> <span class="t-mark">(optional)</span> <code>*</code> <code>]</code> <span class="t-spar">attr-spec-seq</span> <span class="t-mark">(optional)</span> </td> <td> (3) </td> <td class="t-sdsc-nopad"> </td>
</tr> 
</table> <div class="t-li1">
<span class="t-li">1,2)</span> General array declarator syntax</div> <div class="t-li1">
<span class="t-li">3)</span> Declarator for VLA of unspecified size (can appear in function prototype scope only) where</div> <table class="t-par-begin"> <tr class="t-par"> <td> <span class="t-spar">expression</span> </td> <td> - </td> <td> any expression other than <a href="operator_other#Comma_operator" title="c/language/operator other">comma operator</a>, designates the number of elements in the array </td>
</tr> <tr class="t-par"> <td> <span class="t-spar">qualifiers</span> </td> <td> - </td> <td> any combination of <a href="const" title="c/language/const"><code>const</code></a>, <a href="restrict" title="c/language/restrict"><code>restrict</code></a>, or <a href="volatile" title="c/language/volatile"><code>volatile</code></a> qualifiers, only allowed in function parameter lists; this qualifies the pointer type to which this array parameter is transformed </td>
</tr> <tr class="t-par"> <td> <span class="t-spar">attr-spec-seq</span> </td> <td> - </td> <td> <span class="t-mark-rev t-since-c23">(C23)</span>optional list of <a href="attributes" title="c/language/attributes">attributes</a>, applied to the declared array </td>
</tr>
</table> <div class="c source-c"><pre data-language="c">float fa[11], *afp[17]; // fa is an array of 11 floats
                        // afp is an array of 17 pointers to floats</pre></div> <h3 id="Explanation"> Explanation</h3> <p>There are several variations of array types: arrays of known constant size, variable-length arrays, and arrays of unknown size.</p>
<h4 id="Arrays_of_constant_known_size"> Arrays of constant known size</h4> <p>If <span class="t-spar">expression</span> in an array declarator is an <a href="constant_expression#Integer_constant_expression" title="c/language/constant expression">integer constant expression</a> with a value greater than zero <span class="t-rev-inl t-since-c99"><span>and the element type is a type with a known constant size (that is, elements are not VLA)</span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span>, then the declarator declares an array of constant known size:</p>
<div class="c source-c"><pre data-language="c">int n[10]; // integer constants are constant expressions
char o[sizeof(double)]; // sizeof is a constant expression
enum { MAX_SZ=100 };
int n[MAX_SZ]; // enum constants are constant expressions</pre></div> <p>Arrays of constant known size can use <a href="array_initialization" title="c/language/array initialization">array initializers</a> to provide their initial values:</p>
<div class="c source-c"><pre data-language="c">int a[5] = {1,2,3}; // declares int[5] initialized to 1,2,3,0,0
char str[] = "abc"; // declares char[4] initialized to 'a','b','c','\0'</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-since-c99">
<td> <p>In function parameter lists, additional syntax elements are allowed within the array declarators: the keyword <code>static</code> and <span class="t-spar">qualifiers</span>, which may appear in any order before the size expression (they may also appear even when the size expression is omitted).</p>
<p>In each <a href="operator_other#Function_call" title="c/language/operator other">function call</a> to a function where an array parameter uses the keyword <code>static</code> between <code>[</code> and <code>]</code>, the value of the actual parameter must be a valid pointer to the first element of an array with at least as many elements as specified by <span class="t-spar">expression</span>:</p>
<div class="c source-c"><pre data-language="c">void fadd(double a[static 10], const double b[static 10])
{
    for (int i = 0; i &lt; 10; i++)
    {
        if (a[i] &lt; 0.0) return;
        a[i] += b[i];
    }
}
// a call to fadd may perform compile-time bounds checking
// and also permits optimizations such as prefetching 10 doubles
int main(void)
{
    double a[10] = {0}, b[20] = {0};
    fadd(a, b); // OK
    double x[5] = {0};
    fadd(x, b); // undefined behavior: array argument is too small
}</pre></div> <p>If <span class="t-spar">qualifiers</span> are present, they qualify the pointer type to which the array parameter type is transformed:</p>
<div class="c source-c"><pre data-language="c">int f(const int a[20])
{
    // in this function, a has type const int* (pointer to const int)
}
int g(const int a[const 20])
{
    // in this function, a has type const int* const (const pointer to const int)
}</pre></div> <p>This is commonly used with the <a href="restrict" title="c/language/restrict"><code>restrict</code></a> type qualifier:</p>
<div class="c source-c"><pre data-language="c">void fadd(double a[static restrict 10],
          const double b[static restrict 10])
{
    for (int i = 0; i &lt; 10; i++) // loop can be unrolled and reordered
    {
        if (a[i] &lt; 0.0)
            break;
        a[i] += b[i];
    }
}</pre></div> <h4 id="Variable-length_arrays"> Variable-length arrays</h4> <p>If <span class="t-spar">expression</span> is not an <a href="constant_expression#Integer_constant_expression" title="c/language/constant expression">integer constant expression</a>, the declarator is for an array of variable size.</p>
<p>Each time the flow of control passes over the declaration, <span class="t-spar">expression</span> is evaluated (and it must always evaluate to a value greater than zero), and the array is allocated (correspondingly, <a href="lifetime" title="c/language/lifetime">lifetime</a> of a VLA ends when the declaration goes out of scope). The size of each VLA instance does not change during its lifetime, but on another pass over the same code, it may be allocated with a different size.</p>
<div class="c source-c"><pre data-language="c">#include &lt;stdio.h&gt;
 
int main(void)
{
   int n = 1;
label:;
   int a[n]; // re-allocated 10 times, each with a different size
   printf("The array has %zu elements\n", sizeof a / sizeof *a);
   if (n++ &lt; 10)
       goto label; // leaving the scope of a VLA ends its lifetime
}</pre></div>  <p>If the size is <code>*</code>, the declaration is for a VLA of unspecified size. Such declaration may only appear in a function prototype scope, and declares an array of a complete type. In fact, all VLA declarators in function prototype scope are treated as if <span class="t-spar">expression</span> were replaced by <code>*</code>.</p>
<div class="c source-c"><pre data-language="c">void foo(size_t x, int a[*]);
void foo(size_t x, int a[x])
{
    printf("%zu\n", sizeof a); // same as sizeof(int*)
}</pre></div> <p>Variable-length arrays and the types derived from them (pointers to them, etc) are commonly known as "variably-modified types" (VM). Objects of any variably-modified type may only be declared at block scope or function prototype scope.</p>
<div class="c source-c"><pre data-language="c">extern int n;
int A[n];            // Error: file scope VLA
extern int (*p2)[n]; // Error: file scope VM
int B[100];          // OK: file-scope array of constant known size
void fvla(int m, int C[m][m]); // OK: prototype-scope VLA</pre></div> <p>VLA must have automatic or allocated storage duration. Pointers to VLA, but not VLA themselves may also have static storage duration. No VM type may have linkage.</p>
<div class="c source-c"><pre data-language="c">void fvla(int m, int C[m][m]) // OK: block scope/auto duration pointer to VLA
{
    typedef int VLA[m][m]; // OK: block scope VLA
    int D[m];              // OK: block scope/auto duration VLA
//  static int E[m]; // Error: static duration VLA
//  extern int F[m]; // Error: VLA with linkage
    int (*s)[m];     // OK: block scope/auto duration VM
    s = malloc(m * sizeof(int)); // OK: s points to VLA in allocated storage
//  extern int (*r)[m]; // Error: VM with linkage
    static int (*q)[m] = &amp;B; // OK: block scope/static duration VM}
}</pre></div> <p>Variably-modified types cannot be members of structs or unions.</p>
<div class="c source-c"><pre data-language="c">struct tag
{
    int z[n]; // Error: VLA struct member
    int (*y)[n]; // Error: VM struct member
};</pre></div> </td> <td><span class="t-mark-rev t-since-c99">(since C99)</span></td>
</tr> <tr class="t-rev t-since-c11 t-until-c23">
<td> <p>If the compiler defines the macro constant <code>__STDC_NO_VLA__</code> to integer constant <code>1</code>, then VLA and VM types are not supported.</p>
</td> <td>
<span class="t-mark-rev t-since-c11">(since C11)</span><br><span class="t-mark-rev t-until-c23">(until C23)</span>
</td>
</tr> <tr class="t-rev t-since-c23">
<td> <p>If the compiler defines the macro constant <code>__STDC_NO_VLA__</code> to integer constant <code>1</code>, then VLA objects with automatic storage duration are not supported.</p>
<p>The support for VM types and VLAs with allocated storage durations is mandated.</p>
</td> <td><span class="t-mark-rev t-since-c23">(since C23)</span></td>
</tr> </table> <h4 id="Arrays_of_unknown_size"> Arrays of unknown size</h4> <p>If <span class="t-spar">expression</span> in an array declarator is omitted, it declares an array of unknown size. Except in function parameter lists (where such arrays are transformed to pointers) and when an <a href="array_initialization" title="c/language/array initialization">initializer</a> is available, such type is an <a href="type#Incomplete_types" title="c/language/type">incomplete type</a><span class="t-rev-inl t-since-c99"><span> (note that VLA of unspecified size, declared with <code>*</code> as the size, is a complete type)</span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span>:</p>
<div class="c source-c"><pre data-language="c">extern int x[]; // the type of x is "array of unknown bound of int"
int a[] = {1,2,3}; // the type of a is "array of 3 int"</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-since-c99">
<td> <p>Within a <a href="struct" title="c/language/struct">struct</a> definition, an array of unknown size may appear as the last member (as long as there is at least one other named member), in which case it is a special case known as <i>flexible array member</i>. See <a href="struct" title="c/language/struct">struct</a> for details:</p>
<div class="c source-c"><pre data-language="c">struct s { int n; double d[]; }; // s.d is a flexible array member
struct s *s1 = malloc(sizeof (struct s) + (sizeof (double) * 8)); // as if d was double d[8]</pre></div> </td> <td><span class="t-mark-rev t-since-c99">(since C99)</span></td>
</tr> </table> <h4 id="Qualifiers"> Qualifiers</h4> <table class="t-rev-begin"> <tr class="t-rev t-until-c23">
<td> <p>If an array type is declared with a <a href="const" title="c/language/const"><code>const</code></a>, <a href="volatile" title="c/language/volatile"><code>volatile</code></a><span class="t-rev-inl t-since-c99"><span>, or <a href="restrict" title="c/language/restrict"><code>restrict</code></a></span><span><span class="t-mark-rev t-since-c99">(since C99)</span></span></span> qualifier (which is possible through the use of <a href="typedef" title="c/language/typedef">typedef</a>), the array type is not qualified, but its element type is:</p>
</td> <td><span class="t-mark-rev t-until-c23">(until C23)</span></td>
</tr> <tr class="t-rev t-since-c23">
<td> <p>An array type and its element type are always considered to be identically qualified, except that an array type is never considered to be <a href="atomic" title="c/language/atomic"><code>_Atomic</code></a>-qualified.</p>
</td> <td><span class="t-mark-rev t-since-c23">(since C23)</span></td>
</tr> </table> <div class="c source-c"><pre data-language="c">typedef int A[2][3];
const A a = {{4, 5, 6}, {7, 8, 9}}; // array of array of const int
int* pi = a[0]; // Error: a[0] has type const int*
void* unqual_ptr = a; // OK until C23; error since C23
// Notes: clang applies the rule in C++/C23 even in C89-C17 modes</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-since-c11">
<td> <p><a href="atomic" title="c/language/atomic"><code>_Atomic</code></a> is not allowed to be applied to an array type, although an array of atomic type is allowed.</p>
<div class="c source-c"><pre data-language="c">typedef int A[2];
// _Atomic A a0 = {0};    // Error
// _Atomic(A) a1 = {0};   // Error
_Atomic int a2[2] = {0};  // OK
_Atomic(int) a3[2] = {0}; // OK</pre></div> </td> <td><span class="t-mark-rev t-since-c11">(since C11)</span></td>
</tr> </table> <h4 id="Assignment"> Assignment</h4> <p>Objects of array type are not <a href="value_category" title="c/language/value category">modifiable lvalues</a>, and although their address may be taken, they cannot appear on the left hand side of an assignment operator. However, structs with array members are modifiable lvalues and can be assigned:</p>
<div class="c source-c"><pre data-language="c">int a[3] = {1,2,3}, b[3] = {4,5,6};
int (*p)[3] = &amp;a; // okay, address of a can be taken
// a = b;            // error, a is an array
struct { int c[3]; } s1, s2 = {3,4,5};
s1 = s2; // okay: can assign structs holding array members</pre></div> <h4 id="Array_to_pointer_conversion"> Array to pointer conversion</h4> <p>Any <a href="value_category" title="c/language/value category">lvalue expression</a> of array type, when used in any context other than</p>
<ul>
<li> as the operand of the <a href="operator_member_access" title="c/language/operator member access">address-of operator</a> </li>
<li> as the operand of <a href="sizeof" title="c/language/sizeof"><code>sizeof</code></a> </li>
<li> as the operand of <a href="typeof" title="c/language/typeof"><code>typeof</code></a> and <a href="https://en.cppreference.com/mwiki/index.php?title=c/language/typeof_unqual&amp;action=edit&amp;redlink=1" class="new" title="c/language/typeof unqual (page does not exist)"><code>typeof_unqual</code></a> <span class="t-mark-rev t-since-c23">(since C23)</span> </li>
<li> as the string literal used for <a href="array_initialization" title="c/language/array initialization">array initialization</a> </li>
</ul> <table class="t-rev-begin"> <tr class="t-rev t-since-c11">
<td> <ul><li> as the operand of <a href="_alignof" title="c/language/ Alignof"><code>_Alignof</code></a> </li></ul> </td> <td><span class="t-mark-rev t-since-c11">(since C11)</span></td>
</tr> </table> <p>undergoes an <a href="conversion" title="c/language/conversion">implicit conversion</a> to the pointer to its first element. The result is not an lvalue.</p>
<p>If the array was declared <a href="storage_duration" title="c/language/storage duration"><code>register</code></a>, the behavior of the program that attempts such conversion is undefined.</p>
<div class="c source-c"><pre data-language="c">int a[3] = {1,2,3};
int* p = a;
printf("%zu\n", sizeof a); // prints size of array
printf("%zu\n", sizeof p); // prints size of a pointer</pre></div> <p>When an array type is used in a function parameter list, it is transformed to the corresponding pointer type: <code>int f(int a[2])</code> and <code>int f(int* a)</code> declare the same function. Since the function's actual parameter type is pointer type, a function call with an array argument performs array-to-pointer conversion; the size of the argument array is not available to the called function and must be passed explicitly:</p>
<div class="t-example"> <div class="c source-c"><pre data-language="c">#include &lt;stdio.h&gt;
 
void f(int a[], int sz) // actually declares void f(int* a, int sz)
{
    for (int i = 0; i &lt; sz; ++i)
        printf("%d\n", a[i]);
}
 
void g(int (*a)[10]) // pointer to array parameter is not transformed
{
    for (int i = 0; i &lt; 10; ++i)
        printf("%d\n", (*a)[i]);
}
 
int main(void)
{
    int a[10] = {0};
    f(a, 10); // converts a to int*, passes the pointer
    g(&amp;a);    // passes a pointer to the array (no need to pass the size)
}</pre></div> </div> <h4 id="Multidimensional_arrays"> Multidimensional arrays</h4> <p>When the element type of an array is another array, it is said that the array is multidimensional:</p>
<div class="c source-c"><pre data-language="c">// array of 2 arrays of 3 ints each
int a[2][3] = {{1,2,3},  // can be viewed as a 2x3 matrix
               {4,5,6}}; // with row-major layout</pre></div> <p>Note that when array-to-pointer conversion is applied, a multidimensional array is converted to a pointer to its first element, e.g., pointer to the first row:</p>
<div class="c source-c"><pre data-language="c">int a[2][3]; // 2x3 matrix
int (*p1)[3] = a; // pointer to the first 3-element row
int b[3][3][3]; // 3x3x3 cube
int (*p2)[3][3] = b; // pointer to the first 3x3 plane</pre></div> <table class="t-rev-begin"> <tr class="t-rev t-since-c99">
<td> <p>Multidimensional arrays may be variably modified in every dimension<span class="t-rev-inl t-since-c11"><span> if VLAs are supported</span><span><span class="t-mark-rev t-since-c11">(since C11)</span></span></span>:</p>
<div class="c source-c"><pre data-language="c">int n = 10;
int a[n][2*n];</pre></div> </td> <td><span class="t-mark-rev t-since-c99">(since C99)</span></td>
</tr> </table> <h3 id="Notes"> Notes</h3> <p>Zero-length array declarations are not allowed, even though some compilers offer them as extensions (typically as a pre-C99 implementation of <a href="struct" title="c/language/struct">flexible array members</a>).</p>
<p>If the size <span class="t-spar">expression</span> of a VLA has side effects, they are guaranteed to be produced except when it is a part of a sizeof expression whose result doesn't depend on it:</p>
<div class="c source-c"><pre data-language="c">int n = 5;
size_t sz = sizeof(int (*)[n++]); // may or may not increment n</pre></div> <h3 id="References"> References</h3>  <ul>
<li> C23 standard (ISO/IEC 9899:2023): </li>
<ul><li> 6.7.6.2 Array declarators (p: TBD) </li></ul>
<li> C17 standard (ISO/IEC 9899:2018): </li>
<ul><li> 6.7.6.2 Array declarators (p: 94-96) </li></ul>
<li> C11 standard (ISO/IEC 9899:2011): </li>
<ul><li> 6.7.6.2 Array declarators (p: 130-132) </li></ul>
<li> C99 standard (ISO/IEC 9899:1999): </li>
<ul><li> 6.7.5.2 Array declarators (p: 116-118) </li></ul>
<li> C89/C90 standard (ISO/IEC 9899:1990): </li>
<ul><li> 3.5.4.2 Array declarators </li></ul>
</ul>                   <h3 id="See_also"> See also</h3> <table class="t-dsc-begin"> <tr class="t-dsc"> <td colspan="2"> <span><a href="https://en.cppreference.com/w/cpp/language/array" title="cpp/language/array">C++ documentation</a></span> for <span class=""><span>Array declaration</span></span> </td>
</tr> </table>           <div class="_attribution">
  <p class="_attribution-p">
    &copy; cppreference.com<br>Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.<br>
    <a href="https://en.cppreference.com/w/c/language/array" class="_attribution-link">https://en.cppreference.com/w/c/language/array</a>
  </p>
</div>