408 lines
50 KiB
HTML
408 lines
50 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh" dir="ltr" class="client-nojs" xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh">
|
|
<head><meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>数组声明</title>
|
|
<link rel="stylesheet" href="ext.css" />
|
|
<link rel="stylesheet" href="site_modules.css" />
|
|
</head>
|
|
<body class="mediawiki ltr sitedir-ltr ns-0 ns-subject page-c_language_array skin-cppreference2 action-view cpp-navbar">
|
|
<div id="cpp-content-base">
|
|
<div id="content"><a id="top"></a>
|
|
<h1 id="firstHeading" class="firstHeading">数组声明</h1>
|
|
<div id="bodyContent">
|
|
<div id="contentSub"><span class="subpages">< <a href="c.html">c</a>‎ | <a href="c-language.html">language</a></span></div>
|
|
<div id="mw-content-text" lang="zh" dir="ltr" class="mw-content-ltr" xml:lang="zh">
|
|
<p>数组是由连续无空隙分配的,拥有特定<i>元素类型</i>的对象构成的。这些对象的数目数量(数组大小)在数组生存期间决不改变。</p>
|
|
<h3><span class="mw-headline" id=".E8.AF.AD.E6.B3.95">语法</span></h3>
|
|
<p>在数组声明的<a href="c-language-declarations.html">声明文法</a>中,<i>类型指定</i>序列指明<i>元素类型</i>(必须是一个完整对象类型),而<i>声明器</i>拥有形式:</p>
|
|
<table class="t-sdsc-begin">
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <code><b>static</b></code><span class="t-mark">(可选)</span> <span class="t-spar">限定符</span><span class="t-mark">(可选)</span> <span class="t-spar">表达式</span><span class="t-mark">(可选)</span> <code><b>]</b></code> <span class="t-spar">属性说明符序列</span><span class="t-mark">(可选)</span></td>
|
|
<td>(1)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">限定符</span><span class="t-mark">(可选)</span> <code><b>static</b></code><span class="t-mark">(可选)</span> <span class="t-spar">表达式</span><span class="t-mark">(可选)</span> <code><b>]</b></code> <span class="t-spar">属性说明符序列</span><span class="t-mark">(可选)</span></td>
|
|
<td>(2)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
<tr class="t-sdsc">
|
|
<td><code><b>[</b></code> <span class="t-spar">限定符</span><span class="t-mark">(可选)</span> <code><b>*</b></code> <code><b>]</b></code> <span class="t-spar">属性说明符序列</span><span class="t-mark">(可选)</span></td>
|
|
<td>(3)</td>
|
|
<td class="t-sdsc-nopad"></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="10" class="t-sdsc-sep"></td>
|
|
</tr>
|
|
</table>
|
|
<div class="t-li1"><span class="t-li">1,2)</span> 生成通常数组语法</div>
|
|
<div class="t-li1"><span class="t-li">3)</span> 声明未指定大小的 VLA (只能出现于函数原型作用域) 其中</div>
|
|
<table class="t-par-begin">
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">表达式</span></td>
|
|
<td>-</td>
|
|
<td>任何无<a href="c-language-operator_other.html#.E9.80.97.E5.8F.B7.E8.BF.90.E7.AE.97.E7.AC.A6">逗号运算符</a>的表达式,表明数组中的元素数量</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">限定符</span></td>
|
|
<td>-</td>
|
|
<td>任意 <a href="c-language-const.html"><code>const</code></a> 、 <a href="c-language-restrict.html"><code>restrict</code></a> 或 <a href="c-language-volatile.html"><code>volatile</code></a> 限定符的混合,只允许出现于函数参数列表中;它们对数组参数所转换得到的指针类型赋予限定</td>
|
|
</tr>
|
|
<tr class="t-par">
|
|
<td><span class="t-spar">属性说明符序列</span></td>
|
|
<td>-</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23)</span>可选的<a href="c-language-attributes.html">属性</a>列表,应用到被声明的数组</td>
|
|
</tr>
|
|
</table>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">float</span> fa<span class="br0">[</span><span class="nu0">11</span><span class="br0">]</span>, <span class="sy2">*</span>afp<span class="br0">[</span><span class="nu0">17</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// fa 是 11 个 float 组成的数组</span>
|
|
<span class="co1">// afp 是 17 个指向 float 的指针组成的数组</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E8.A7.A3.E9.87.8A">解释</span></h3>
|
|
<p>有几种数组类型变体:已知常量大小的数组、变长度数组,以及未知大小数组。</p>
|
|
<h4><span class="mw-headline" id=".E5.B7.B2.E7.9F.A5.E5.B8.B8.E9.87.8F.E5.A4.A7.E5.B0.8F.E6.95.B0.E7.BB.84">已知常量大小数组</span></h4>
|
|
<p>若数组声明器中的 <span class="t-spar">表达式</span> 为<a href="c-language-constant_expression.html#.E6.95.B4.E6.95.B0.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">整数常量表达式</a>,拥有大于零的值<span class="t-rev-inl t-since-c99"><span>,且元素类型是一种拥有已知常量大小的类型(即元素不是 VLA )</span> <span><span class="t-mark-rev t-since-c99">(C99 起)</span></span></span>,则声明器声明已知常量大小的数组:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> n<span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 整数常量是常量表达式</span>
|
|
<span class="kw4">char</span> o<span class="br0">[</span><span class="kw4">sizeof</span><span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// sizeof 是常量表达式</span>
|
|
<span class="kw2">enum</span> <span class="br0">{</span> MAX_SZ<span class="sy1">=</span><span class="nu0">100</span> <span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> n<span class="br0">[</span>MAX_SZ<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 枚举常量是常量表达式</span></pre></div>
|
|
</div>
|
|
<p>已知常量大小的数组可以用<a href="c-language-array_initialization.html">数组初始化器</a>提供它们的初始值:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">5</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 声明 int[5] 初始化为 1,2,3,0,0</span>
|
|
<span class="kw4">char</span> str<span class="br0">[</span><span class="br0">]</span> <span class="sy1">=</span> <span class="st0">"abc"</span><span class="sy4">;</span> <span class="co1">// 声明 char[4] 初始化为 'a','b','c','\0'</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c99">
|
|
<td>
|
|
<p>在函数参数列表中,附加性语法元素允许出现于数组声明器内:关键词 <code><b>static</b></code> 及 <span class="t-spar">限定符</span> ,它们可以以任意顺序先于大小表达式出现(它们甚至可以在大小表达式被忽略时出现)。</p>
|
|
<p>在每个到数组参数类型在 <code><b>[</b></code> 和 <code><b>]</b></code> 使用关键词 <code><b>static</b></code> 的函数的<a href="c-language-operator_other.html#.E5.87.BD.E6.95.B0.E8.B0.83.E7.94.A8">函数调用</a>中,实际参数的值必须是一个指向数组首地址的合法指针,该数组元素数目至少为 <span class="t-spar">表达式</span> 的结果:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">void</span> fadd<span class="br0">(</span><span class="kw4">double</span> a<span class="br0">[</span><span class="kw4">static</span> <span class="nu0">10</span><span class="br0">]</span>, <span class="kw4">const</span> <span class="kw4">double</span> b<span class="br0">[</span><span class="kw4">static</span> <span class="nu0">10</span><span class="br0">]</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy1"><</span> <span class="nu0">10</span><span class="sy4">;</span> i<span class="sy2">++</span><span class="br0">)</span> <span class="br0">{</span>
|
|
<span class="kw1">if</span> <span class="br0">(</span>a<span class="br0">[</span>i<span class="br0">]</span> <span class="sy1"><</span> <span class="nu16">0.0</span><span class="br0">)</span> <span class="kw1">return</span><span class="sy4">;</span>
|
|
a<span class="br0">[</span>i<span class="br0">]</span> <span class="sy2">+</span><span class="sy1">=</span> b<span class="br0">[</span>i<span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span>
|
|
<span class="co1">// 对 fadd 的调用可能进行编译时边界检查</span>
|
|
<span class="co1">// 并且允许诸如预读取 10 个 double 的优化 </span>
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">double</span> a<span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span>, b<span class="br0">[</span><span class="nu0">20</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span><span class="sy4">;</span>
|
|
fadd<span class="br0">(</span>a, b<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
<span class="kw4">double</span> x<span class="br0">[</span><span class="nu0">5</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span><span class="sy4">;</span>
|
|
fadd<span class="br0">(</span>x, b<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 未定义行为:数组参数太小</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>若存在 <span class="t-spar">限定符</span> ,则它们对数组参数类型所转换得的指针类型赋予限定:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">20</span><span class="br0">]</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="co1">// 此函数中, a 拥有类型 const int* (指向 const int 的指针)</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">int</span> g<span class="br0">(</span><span class="kw4">const</span> <span class="kw4">int</span> a<span class="br0">[</span><span class="kw4">const</span> <span class="nu0">20</span><span class="br0">]</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="co1">// 此函数中, a 拥有类型 const int* const (指向 const int 的 const 指针)</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>这通常用于 <a href="c-language-restrict.html"><code>restrict</code></a> 类型限定符:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">void</span> fadd<span class="br0">(</span><span class="kw4">double</span> a<span class="br0">[</span><span class="kw4">static</span> <span class="kw4">restrict</span> <span class="nu0">10</span><span class="br0">]</span>,
|
|
<span class="kw4">const</span> <span class="kw4">double</span> b<span class="br0">[</span><span class="kw4">static</span> <span class="kw4">restrict</span> <span class="nu0">10</span><span class="br0">]</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">for</span> <span class="br0">(</span><span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy1"><</span> <span class="nu0">10</span><span class="sy4">;</span> i<span class="sy2">++</span><span class="br0">)</span> <span class="br0">{</span> <span class="co1">// 循环可被打开或重排</span>
|
|
<span class="kw1">if</span> <span class="br0">(</span>a<span class="br0">[</span>i<span class="br0">]</span> <span class="sy1"><</span> <span class="nu16">0.0</span><span class="br0">)</span> <span class="kw1">break</span><span class="sy4">;</span>
|
|
a<span class="br0">[</span>i<span class="br0">]</span> <span class="sy2">+</span><span class="sy1">=</span> b<span class="br0">[</span>i<span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E9.9D.9E.E5.B8.B8.E9.87.8F.E9.95.BF.E5.BA.A6.E6.95.B0.E7.BB.84">非常量长度数组</span></h4>
|
|
<p>若 <span class="t-spar">表达式</span> 不是<a href="c-language-constant_expression.html#.E6.95.B4.E6.95.B0.E5.B8.B8.E9.87.8F.E8.A1.A8.E8.BE.BE.E5.BC.8F">整数常量表达式</a>,则数组声明器声明一个非常量大小的数组( VLA )。</p>
|
|
<p>每次控制流经过该声明时,会求值 <span class="t-spar">表达式</span> (而且它必须每次求值为大于零的值),然后分配数组(对应地, VLA 的<a href="c-language-lifetime.html">生存期</a>在其声明离开作用域时结束)。 VLA 实例的大小不会在其生存期改变,但在另一次经过同一代码时,它可能被分配不同大小。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="br0">{</span>
|
|
<span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">1</span><span class="sy4">;</span>
|
|
label<span class="sy4">:;</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 重分配 10 次,每次拥有不同大小</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"The array has %zu elements<span class="es1">\n</span>"</span>, <span class="kw4">sizeof</span> a <span class="sy2">/</span> <span class="kw4">sizeof</span> <span class="sy2">*</span>a<span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw1">if</span> <span class="br0">(</span>n<span class="sy2">++</span> <span class="sy1"><</span> <span class="nu0">10</span><span class="br0">)</span> <span class="kw1">goto</span> label<span class="sy4">;</span> <span class="co1">// 离开作用域的 VLA 结束其生存期</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>若大小是 <code><b>*</b></code> ,则声明是对于未指定大小的 VLA 的。这种声明只能出现于函数原型作用域,并声明一个完整类型的数组。其实,所有函数原型作用域中的 VLA 声明器都被处理成如同用 <code><b>*</b></code> 替换 <span class="t-spar">表达式</span> 。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">void</span> foo<span class="br0">(</span><a href="c-types-size_t.html"><span class="kw100">size_t</span></a> x, <span class="kw4">int</span> a<span class="br0">[</span><span class="sy2">*</span><span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="kw4">void</span> foo<span class="br0">(</span><a href="c-types-size_t.html"><span class="kw100">size_t</span></a> x, <span class="kw4">int</span> a<span class="br0">[</span>x<span class="br0">]</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"%zu<span class="es1">\n</span>"</span>, <span class="kw4">sizeof</span> a<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 大小同sizeof(int*)</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>非常量长度数组与从它们派生的类型(指向它们的指针,等等)被通称为“可变修改类型”( VM )。任何可变修改类型的对象只能声明于块作用域或函数原型作用域中。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw2">extern</span> <span class="kw4">int</span> n<span class="sy4">;</span>
|
|
<span class="kw4">int</span> A<span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误:文件作用域 VLA</span>
|
|
<span class="kw2">extern</span> <span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>p2<span class="br0">)</span><span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误:文件作用域 VM</span>
|
|
<span class="kw4">int</span> B<span class="br0">[</span><span class="nu0">100</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK:文件作用域的已知常量大小数组</span>
|
|
<span class="kw4">void</span> fvla<span class="br0">(</span><span class="kw4">int</span> m, <span class="kw4">int</span> C<span class="br0">[</span>m<span class="br0">]</span><span class="br0">[</span>m<span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// OK:原型作用域 VLA</span></pre></div>
|
|
</div>
|
|
<p>VLA 必须拥有自动或分配存储期。指向 VLA 的指针,但不是 VLA 自身亦可拥有静态存储期。 VM 类型不能拥有链接。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">void</span> fvla<span class="br0">(</span><span class="kw4">int</span> m, <span class="kw4">int</span> C<span class="br0">[</span>m<span class="br0">]</span><span class="br0">[</span>m<span class="br0">]</span><span class="br0">)</span> <span class="co1">// OK :块作用域/自动存储期到 VLA 的指针</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">typedef</span> <span class="kw4">int</span> VLA<span class="br0">[</span>m<span class="br0">]</span><span class="br0">[</span>m<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK :块作用域 VLA</span>
|
|
<span class="kw4">int</span> D<span class="br0">[</span>m<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK :块作用域/自动存储期 VLA</span>
|
|
<span class="co1">// static int E[m]; // 错误:静态存储期 VLA</span>
|
|
<span class="co1">// extern int F[m]; // 错误:拥有链接的 VLA</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>s<span class="br0">)</span><span class="br0">[</span>m<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// OK:块作用域/自动存储期 VM</span>
|
|
<span class="co1">// extern int (*r)[m]; // 错误:拥有链接的 VM</span>
|
|
<span class="kw4">static</span> <span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>q<span class="br0">)</span><span class="br0">[</span>m<span class="br0">]</span> <span class="sy1">=</span> <span class="sy3">&</span>B<span class="sy4">;</span> <span class="co1">// 错误 :静态存储期指针需要静态存储期的B来初始化,</span>
|
|
<span class="co1">// 但无法定义static int B[m];</span>
|
|
<span class="kw4">static</span> <span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>p<span class="br0">)</span><span class="br0">[</span>m<span class="br0">]</span> <span class="sy1">=</span> <a href="c-types-NULL.html"><span class="kw103">NULL</span></a><span class="sy4">;</span>
|
|
p <span class="sy1">=</span> <span class="sy3">&</span>B<span class="sy4">;</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<p>可变修改的类型不能是结构体或联合体的成员。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">struct</span> tag <span class="br0">{</span>
|
|
<span class="kw4">int</span> z<span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误: VLA 结构体成员</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>y<span class="br0">)</span><span class="br0">[</span>n<span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误: VM 结构体成员</span>
|
|
<span class="br0">}</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<p>若编译器定义宏常量 <span class="t-c"><span class="mw-geshi c source-c">__STDC_NO_VLA__</span></span> 为整数常量 <span class="t-c"><span class="mw-geshi c source-c"><span class="nu0">1</span></span></span> ,则不提供 VLA 或 VM 。</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E6.9C.AA.E7.9F.A5.E5.A4.A7.E5.B0.8F.E6.95.B0.E7.BB.84">未知大小数组</span></h4>
|
|
<p>若忽略数组声明器中的 <span class="t-spar">表达式</span>,则它声明一个未知大小数组。除了函数参数列表中的情况(这种数组被转换成指针),而且当<a href="c-language-array_initialization.html">初始化器</a>可用时,这种类型是一个<a href="c-language-types.html#.E4.B8.8D.E5.AE.8C.E6.95.B4.E7.B1.BB.E5.9E.8B">不完整类型</a><span class="t-rev-inl t-since-c99"><span>(注意拥有未指定大小的VLA,以 <code><b>*</b></code> 代替大小声明时,它是完整类型)</span> <span><span class="t-mark-rev t-since-c99">(C99 起)</span></span></span>:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw2">extern</span> <span class="kw4">int</span> x<span class="br0">[</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// x 的类型是“边界未知的 int 数组”</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// a 的类型是“ 3 个 int 的数组”</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c99">
|
|
<td>
|
|
<p>在 <a href="c-language-struct.html">struct</a> 定义中,未知大小数组必须出现作最后一个元素(只要有一个具名成员),这种情况下,这是称为<i>柔性数组成员</i>的特殊情形。细节见 <a href="c-language-struct.html">struct</a> :</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">struct</span> s <span class="br0">{</span> <span class="kw4">int</span> n<span class="sy4">;</span> <span class="kw4">double</span> d<span class="br0">[</span><span class="br0">]</span><span class="sy4">;</span> <span class="br0">}</span><span class="sy4">;</span> <span class="co1">// s.d 是柔性数组成员</span>
|
|
<span class="kw1">struct</span> s <span class="sy2">*</span>s1 <span class="sy1">=</span> <a href="c-memory-malloc.html"><span class="kw403">malloc</span></a><span class="br0">(</span><span class="kw4">sizeof</span> <span class="br0">(</span><span class="kw1">struct</span> s<span class="br0">)</span> <span class="sy2">+</span> <span class="br0">(</span><span class="kw4">sizeof</span> <span class="br0">(</span><span class="kw4">double</span><span class="br0">)</span> <span class="sy2">*</span> <span class="nu0">8</span><span class="br0">)</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 如同 d 是 d[8]</span></pre></div>
|
|
</div>
|
|
<p><br /></p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E9.99.90.E5.AE.9A.E7.AC.A6">限定符</span></h4>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-until-c23">
|
|
<td>
|
|
<p>若数组类型声明拥有 <a href="c-language-const.html"><code>const</code></a> 、 <a href="c-language-volatile.html"><code>volatile</code></a> <span class="t-rev-inl t-since-c99"><span>、或 <a href="c-language-restrict.html"><code>restrict</code></a></span> <span><span class="t-mark-rev t-since-c99">(C99 起)</span></span></span> 限定符(可以通过使用 <a href="c-language-typedef.html"><code>typedef</code></a> ),则数组类型无限定,但其元素类型有限定:</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-until-c23">(C23 前)</span></td>
|
|
</tr>
|
|
<tr class="t-rev t-since-c23">
|
|
<td>
|
|
<p>始终认为数组类型与其元素类型有等同的限定,除了始终不认为数组类型有 <a href="c-language-atomic.html"><code>_Atomic</code></a> 限定:</p>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c23">(C23 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span> A<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="kw4">const</span> A a <span class="sy1">=</span> <span class="br0">{</span><span class="br0">{</span><span class="nu0">4</span>, <span class="nu0">5</span>, <span class="nu0">6</span><span class="br0">}</span>, <span class="br0">{</span><span class="nu0">7</span>, <span class="nu0">8</span>, <span class="nu0">9</span><span class="br0">}</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// const int 的数组的数组</span>
|
|
<span class="kw4">int</span><span class="sy2">*</span> pi <span class="sy1">=</span> a<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 错误: a[0] 拥有类型 const int*</span>
|
|
<span class="kw4">void</span> <span class="sy2">*</span>unqual_ptr <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// C23 前 OK ; C23 起错误</span>
|
|
<span class="co1">// 注: clang 即使在 C89-C17 模式也应用 C++/C23 中的规则</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<p>不允许应用 <a href="c-language-atomic.html"><code>_Atomic</code></a> 到数组类型,尽管允许原子类型的数组。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw1">typedef</span> <span class="kw4">int</span> A<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="sy4">;</span>
|
|
<span class="co1">// _Atomic A a0 = {0}; // 错误</span>
|
|
<span class="co1">// _Atomic(A) a1 = {0}; // 错误</span>
|
|
_Atomic <span class="kw4">int</span> a2<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK</span>
|
|
_Atomic<span class="br0">(</span><span class="kw4">int</span><span class="br0">)</span> a3<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">0</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// OK</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h4><span class="mw-headline" id=".E8.B5.8B.E5.80.BC">赋值</span></h4>
|
|
<p>数组类型的对象不是<a href="c-language-value_category.html">可修改左值</a>,尽管它们可以取地址,它们不能出现于赋值运算符的左侧。不过,拥有数组成员的结构体是可修改左值,并可以赋值:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span>, b<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">4</span>,<span class="nu0">5</span>,<span class="nu0">6</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>p<span class="br0">)</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="sy3">&</span>a<span class="sy4">;</span> <span class="co1">// OK ,可以取地址</span>
|
|
<span class="co1">// a = b; // 错误,a 是数组</span>
|
|
<span class="kw1">struct</span> <span class="br0">{</span> <span class="kw4">int</span> c<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span> <span class="br0">}</span> s1, s2 <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">3</span>,<span class="nu0">4</span>,<span class="nu0">5</span><span class="br0">}</span><span class="sy4">;</span>
|
|
s1 <span class="sy1">=</span> s2<span class="sy4">;</span> <span class="co1">// OK :可以赋值拥有数组成员的结构体</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E6.95.B0.E7.BB.84.E5.88.B0.E6.8C.87.E9.92.88.E8.BD.AC.E6.8D.A2">数组到指针转换</span></h4>
|
|
<p>任何数组类型的<a href="c-language-value_category.html">左值表达式</a>,当用于异于</p>
|
|
<ul>
|
|
<li>作为<a href="c-language-operator_member_access.html">取地址运算符</a>的操作数</li>
|
|
<li>作为 <a href="c-language-sizeof.html"><code>sizeof</code></a> 的操作数</li>
|
|
<li>作为用于<a href="c-language-array_initialization.html">数组初始化</a>的字符串字面量</li>
|
|
</ul>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c11">
|
|
<td>
|
|
<ul>
|
|
<li>作为 <a href="c-language-_Alignof.html"><code>_Alignof</code></a> 的操作数</li>
|
|
</ul>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c11">(C11 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<p>的语境时,会经历到指向其首元素指针的<a href="c-language-conversion.html">隐式转换</a>。结果为非左值。</p>
|
|
<p>若声明数组为 <a href="c-language-storage_duration.html"><code>register</code></a> ,则尝试这么做的程序的行为未定义。</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span><span class="sy2">*</span> p <span class="sy1">=</span> a<span class="sy4">;</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"%zu<span class="es1">\n</span>"</span>, <span class="kw4">sizeof</span> a<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 打印数组大小</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"%zu<span class="es1">\n</span>"</span>, <span class="kw4">sizeof</span> p<span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 打印指针大小</span></pre></div>
|
|
</div>
|
|
<p>当数组类型用于函数参数列表是,它会转换成对应的指针类型: <span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">)</span></span></span> 和<span class="t-c"><span class="mw-geshi c source-c"><span class="kw4">int</span> f<span class="br0">(</span><span class="kw4">int</span><span class="sy2">*</span> a<span class="br0">)</span></span></span> 声明同一个函数。因为函数实际参数类型为指针类型,使用数组参数的函数调用会进行一个数组到指针转换;参数数组的大小不为被调用函数可得,而必须显式传递:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">void</span> f<span class="br0">(</span><span class="kw4">int</span> a<span class="br0">[</span><span class="br0">]</span>, <span class="kw4">int</span> sz<span class="br0">)</span> <span class="co1">// 实际上声明 void f(int* a, int sz)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw1">for</span><span class="br0">(</span><span class="kw4">int</span> i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy1"><</span> sz<span class="sy4">;</span> <span class="sy2">++</span>i<span class="br0">)</span>
|
|
<a href="c-io-fprintf.html"><span class="kw851">printf</span></a><span class="br0">(</span><span class="st0">"%d<span class="es1">\n</span>"</span>, a<span class="br0">[</span>i<span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span>
|
|
<span class="br0">}</span>
|
|
<span class="kw4">int</span> main<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span>
|
|
<span class="br0">{</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">10</span><span class="br0">]</span><span class="sy4">;</span>
|
|
f<span class="br0">(</span>a, <span class="nu0">10</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// 转换成 int* ,传递指针</span>
|
|
<span class="br0">}</span></pre></div>
|
|
</div>
|
|
<h4><span class="mw-headline" id=".E5.A4.9A.E7.BB.B4.E6.95.B0.E7.BB.84">多维数组</span></h4>
|
|
<p>当数组的元素是另一个数组时,我们称数组是多维的:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="co1">// 2 个元素为 3 个 int 的数组的数组</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> <span class="br0">{</span><span class="br0">{</span><span class="nu0">1</span>,<span class="nu0">2</span>,<span class="nu0">3</span><span class="br0">}</span>, <span class="co1">// 可视作行主导排列的</span>
|
|
<span class="br0">{</span><span class="nu0">4</span>,<span class="nu0">5</span>,<span class="nu0">6</span><span class="br0">}</span><span class="br0">}</span><span class="sy4">;</span> <span class="co1">// 2x3 矩阵</span></pre></div>
|
|
</div>
|
|
<p>注意当应用数组到指针转换是,多维数组被转换成指向其首元素的指针,例如指针到首行:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> a<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 2x3 矩阵</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>p1<span class="br0">)</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// 指向首个 3 个元素行的指针</span>
|
|
<span class="kw4">int</span> b<span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="sy4">;</span> <span class="co1">// 3x3x3 立方体</span>
|
|
<span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span>p2<span class="br0">)</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span><span class="br0">[</span><span class="nu0">3</span><span class="br0">]</span> <span class="sy1">=</span> a<span class="sy4">;</span> <span class="co1">// 指向首个 3x3 平面的指针</span></pre></div>
|
|
</div>
|
|
<table class="t-rev-begin">
|
|
<tr class="t-rev t-since-c99">
|
|
<td>
|
|
<p><span class="t-rev-inl t-since-c11"><span>若支持 VLA ,则</span> <span><span class="t-mark-rev t-since-c11">(C11 起)</span></span></span>多维数组可以在每一维度可变修改:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">10</span><span class="sy4">;</span>
|
|
<span class="kw4">int</span> a<span class="br0">[</span>n<span class="br0">]</span><span class="br0">[</span><span class="nu0">2</span><span class="sy2">*</span>n<span class="br0">]</span><span class="sy4">;</span></pre></div>
|
|
</div>
|
|
</td>
|
|
<td><span class="t-mark-rev t-since-c99">(C99 起)</span></td>
|
|
</tr>
|
|
</table>
|
|
<h3><span class="mw-headline" id=".E6.B3.A8.E8.A7.A3">注解</span></h3>
|
|
<p>不允许零长度数组,即使一些编译器作为扩展提供它们(典型例子是 C99 前的<a href="c-language-struct.html">柔性数组成员</a>实现)。</p>
|
|
<p>若 VLA 的大小 <span class="t-spar">表达式</span> 拥有副作用,则保证会正确产生副作用,除非它们是 <code>sizeof</code> 表达式的一部分,而结果不依赖副效应:</p>
|
|
<div dir="ltr" class="mw-geshi" style="text-align: left;">
|
|
<div class="c source-c">
|
|
<pre class="de1"><span class="kw4">int</span> n <span class="sy1">=</span> <span class="nu0">5</span><span class="sy4">;</span>
|
|
<a href="c-types-size_t.html"><span class="kw100">size_t</span></a> sz <span class="sy1">=</span> <span class="kw4">sizeof</span><span class="br0">(</span><span class="kw4">int</span> <span class="br0">(</span><span class="sy2">*</span><span class="br0">)</span><span class="br0">[</span>n<span class="sy2">++</span><span class="br0">]</span><span class="br0">)</span><span class="sy4">;</span> <span class="co1">// n 可以自增也可以不自增</span></pre></div>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.BC.95.E7.94.A8">引用</span></h3>
|
|
<div class="t-ref-std-17">
|
|
<ul>
|
|
<li>C17 标准(ISO/IEC 9899:2018):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.6.2 Array declarators (p: 94-96)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-11">
|
|
<ul>
|
|
<li>C11 标准(ISO/IEC 9899:2011):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.6.2 Array declarators (p: 130-132)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c99">
|
|
<ul>
|
|
<li>C99 标准(ISO/IEC 9899:1999):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>6.7.5.2 Array declarators (p: 116-118)</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="t-ref-std-c89">
|
|
<ul>
|
|
<li>C89/C90 标准(ISO/IEC 9899:1990):</li>
|
|
</ul>
|
|
<dl>
|
|
<dd>
|
|
<ul>
|
|
<li>3.5.4.2 Array declarators</li>
|
|
</ul>
|
|
</dd>
|
|
</dl>
|
|
</div>
|
|
<h3><span class="mw-headline" id=".E5.8F.82.E9.98.85">参阅</span></h3>
|
|
<table class="t-dsc-begin"></table>
|
|
</div>
|
|
<div class="visualClear"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|