?
このドキュメントでは、 php中國語ネットマニュアル リリース
數(shù)組是由連續(xù)分配的具有特定元素類型的非空對象序列組成的類型。在陣列生命周期內(nèi),這些對象的數(shù)量(數(shù)組大?。┯肋h(yuǎn)不會(huì)改變。
在數(shù)組聲明的聲明語法中,類型說明符序列指定元素類型(必須是完整的對象類型),聲明符的格式如下:
static(optional) qualifiers(optional) expression(optional) | (1) | |
---|---|---|
qualifiers(optional) static(optional) expression(optional) | (2) | |
qualifiers(optional) * | (3) |
1,2)常規(guī)數(shù)組聲明語法
3)未指定大小的 VLA 的聲明符(只能出現(xiàn)在函數(shù)原型范圍內(nèi))其中
expression | - | any expression other than comma operator, designates the number of elements in the array |
---|---|---|
qualifiers | - | any combination of const, restrict, or volatile qualifiers, only allowed in function parameter lists; this qualifies the pointer type to which this array parameter is transformed |
float fa[11], *afp[17]; // fa is an array of 11 floats // afp is an array of 17 pointers to floats
數(shù)組類型有多種變體:已知常量大小的數(shù)組,可變長度數(shù)組和大小未知的數(shù)組。
如果數(shù)組聲明符中的表達(dá)式是一個(gè)整數(shù)常量表達(dá)式,其值大于零且元素類型是已知常量大小的類型(即元素不是 VLA)(因?yàn)?C99),那么聲明符聲明一個(gè)數(shù)組恒定的已知尺寸:
int n[10]; // integer constants are constant expressionschar o[sizeof(double)]; // sizeof is a constant expressionenum { MAX_SZ=100 };int n[MAX_SZ]; // enum constants are constant expressions
已知大小的常量數(shù)組可以使用數(shù)組初始化器來提供它們的初始值:
int a[5] = {1,2,3}; // declares int[5] initalized to 1,2,3,0,0char str[] = "abc"; // declares char[4] initialized to 'a','b','c','\0'
在函數(shù)參數(shù)列表中,數(shù)組聲明符中允許使用其他語法元素:關(guān)鍵字static和qualifiers,它們可能在大小表達(dá)式之前以任何順序出現(xiàn)(即使忽略大小表達(dá)式時(shí)它們也可能出現(xiàn))。在每個(gè)函數(shù)調(diào)用一個(gè)函數(shù),其中數(shù)組類型的參數(shù)使用與之間的關(guān)鍵字static時(shí),實(shí)際參數(shù)的值必須是指向數(shù)組的第一個(gè)元素的有效指針,其中至少與expression指定的元素?cái)?shù)量一樣多:void fadd(double astatic 10,const double bstatic 10){for(int i = 0; i <10; i ++){if(ai <0.0)return; ai + = bi; }} //對fadd的調(diào)用執(zhí)行編譯時(shí)邊界檢查//并且還允許優(yōu)化,例如預(yù)取10個(gè)雙精度int main(void){double a10 = {0},b20 = {0}; fadd(a,b); // OK double x5 = {0}; fadd(x,b); //錯(cuò)誤:數(shù)組參數(shù)太小}如果存在限定符,它們限定數(shù)組參數(shù)類型轉(zhuǎn)換的指針類型:int f(const int a20){//在此函數(shù)中,a的類型為const int *(指向const int的指針)} int g(const int aconst 20){//在此函數(shù)中,a的類型為const int * const(const指針的常量)}這通常與restrict類型限定符一起使用:void fadd(double (int i = 0; i <10; i ++){//如果(ai <0.0)break,循環(huán)可以展開并重新排序; ai + = bi; }}變長數(shù)組如果表達(dá)式不是一個(gè)整型常量表達(dá)式,那么聲明符是可變大小的數(shù)組。每當(dāng)控制流程通過聲明時(shí),表達(dá)式被評估(并且它必須總是計(jì)算大于零的值),并且分配數(shù)組(相應(yīng)地,當(dāng)聲明超出范圍時(shí),VLA的生存期結(jié)束)。每個(gè)VLA實(shí)例的大小在其生命周期內(nèi)不會(huì)更改,但在另一次傳遞相同的代碼時(shí),它可能會(huì)以不同的大小進(jìn)行分配。{int n = 1; label:int an; //重新分配10次,每次都有不同的大小printf(“數(shù)組有%zu元素\ n”,sizeof a / sizeof * a); 如果(n ++ <10)轉(zhuǎn)到標(biāo)簽; //離開VLA的范圍終止其生命周期}如果大小是*,則聲明是針對未指定大小的VLA。這種聲明只能出現(xiàn)在函數(shù)原型范圍內(nèi),并聲明一個(gè)完整類型的數(shù)組。事實(shí)上,將函數(shù)原型范圍內(nèi)的所有VLA聲明符視為用*替換表達(dá)式。void foo(size_t x,int a *); void foo(size_t x,int ax){printf(“%zu \ n”,sizeof a); //與sizeof(int *)相同}可變長度數(shù)組及其派生類型(指向它們的指針等)通常稱為“可變修改類型”(VM)。任何可變修改類型的對象只能在塊范圍或函數(shù)原型范圍內(nèi)聲明。extern int n; int An; //錯(cuò)誤:文件范圍VLA extern int(* p2)n; //錯(cuò)誤:文件范圍VM int B100; // OK:常量已知大小的文件范圍數(shù)組void fvla(int m,int Cm); // OK:原型范圍VLA VLA必須具有自動(dòng)存儲(chǔ)持續(xù)時(shí)間。指向VLA,而不是VLA本身也可能具有靜態(tài)存儲(chǔ)持續(xù)時(shí)間。沒有VM類型可能有聯(lián)系。void fvla(int m,int Cm)// OK:塊范圍/自動(dòng)持續(xù)時(shí)間VLA的指針{typedef int VLAm; // OK:塊范圍VLA int Dm; // OK:塊范圍/自動(dòng)持續(xù)時(shí)間VLA // static int Em; //錯(cuò)誤:靜態(tài)持續(xù)時(shí)間VLA // extern int Fm; //錯(cuò)誤:帶連接的VLA int(* s)m; // OK:塊范圍/自動(dòng)持續(xù)時(shí)間VM // extern int(* r)m; //錯(cuò)誤:具有鏈接靜態(tài)int的虛擬機(jī)(* q)m =&B; // OK:塊范圍/靜態(tài)持續(xù)時(shí)間VM}}可變更改的類型不能是結(jié)構(gòu)或聯(lián)合的成員。結(jié)構(gòu)標(biāo)記{int zn; //錯(cuò)誤:VLA struct member int(* y)n; //錯(cuò)誤:VM結(jié)構(gòu)成員}; 帶連接int(* s)m的VLA; // OK:塊范圍/自動(dòng)持續(xù)時(shí)間VM // extern int(* r)m; //錯(cuò)誤:具有鏈接靜態(tài)int的虛擬機(jī)(* q)m =&B; // OK:塊范圍/靜態(tài)持續(xù)時(shí)間VM}}可變更改的類型不能是結(jié)構(gòu)或聯(lián)合的成員。結(jié)構(gòu)標(biāo)記{int zn; //錯(cuò)誤:VLA struct member int(* y)n; //錯(cuò)誤:VM結(jié)構(gòu)成員}; 帶連接int(* s)m的VLA; // OK:塊范圍/自動(dòng)持續(xù)時(shí)間VM // extern int(* r)m; //錯(cuò)誤:具有鏈接靜態(tài)int的虛擬機(jī)(* q)m =&B; // OK:塊范圍/靜態(tài)持續(xù)時(shí)間VM}}可變更改的類型不能是結(jié)構(gòu)或聯(lián)合的成員。結(jié)構(gòu)標(biāo)記{int zn; //錯(cuò)誤:VLA struct member int(* y)n; //錯(cuò)誤:VM結(jié)構(gòu)成員}; | (自C99以來) |
---|---|
如果編譯器將宏常量__STDC_NO_VLA__定義為整數(shù)常量1,則不支持VLA和VM類型。 | (自C11以來) |
如果數(shù)組聲明符中的表達(dá)式被省略,它將聲明一個(gè)未知大小的數(shù)組。除了函數(shù)參數(shù)列表(這些數(shù)組被轉(zhuǎn)換為指針)以及初始化程序可用時(shí),這種類型是不完整的類型(請注意,未指定大小的 VLA,以大小聲明*
,是一個(gè)完整類型)(自 C99開始) :
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"
在一個(gè)結(jié)構(gòu)體定義中,未知大小的數(shù)組可能會(huì)作為最后一個(gè)成員出現(xiàn)(只要至少有一個(gè)其他已命名成員),在這種情況下,它就是一個(gè)特殊情況,稱為靈活數(shù)組成員。有關(guān)詳細(xì)信息,請參閱struct:struct s {int n; double d []; }; // sd是一個(gè)靈活的數(shù)組成員struct s * s1 = malloc(sizeof(struct s)+(sizeof(double)* 8)); //好像d是雙d8 | (自C99以來) |
---|
如果使用 const,volatile,restrict(自C99)或_Atomic(自C11)限定符(可通過使用 typedef)聲明數(shù)組類型,則數(shù)組類型不是限定的,但其元素類型為:
typedef int A[2][3];const A a = {{4, 5, 6}, {7, 8, 9}}; // array of array of const intint* pi = a[0]; // Error: a[0] has type const int*
數(shù)組類型的對象不是可修改的左值,雖然它們的地址可以被采用,但它們不能出現(xiàn)在賦值運(yùn)算符的左側(cè)。但是,數(shù)組成員的結(jié)構(gòu)是可修改的左值,可以賦值為:
int a[3] = {1,2,3}, b[3] = {4,5,6};int (*p)[3] = &a; // okay, address of a can be taken// a = b; // error, a is an arraystruct { int c[3]; } s1, s2 = {3,4,5};s1 = s2; // okay: can assign structs holding array members
數(shù)組類型的任何左值表達(dá)式,當(dāng)在除。以外的任何上下文中使用時(shí)。
作為操作符地址的操作數(shù)
作為 sizeof 的操作數(shù)
作為用于數(shù)組初始化的字符串文字
as the operand of _Alignof | (since C11) |
---|
作為_Alignof 的操作數(shù)
(since C11)
經(jīng)歷了對指向其第一個(gè)元素的隱式轉(zhuǎn)換。結(jié)果不是左值。
如果數(shù)組被聲明為 register,那么嘗試這種轉(zhuǎn)換的程序的行為是未定義的。
int a[3] = {1,2,3};int* p = a;printf("%zu\n", sizeof a); // prints size of arrayprintf("%zu\n", sizeof p); // prints size of a pointer
在函數(shù)參數(shù)列表中使用數(shù)組類型時(shí),它將轉(zhuǎn)換為相應(yīng)的指針類型:int f(int a[2])
和int f(int* a)
聲明相同的函數(shù)。由于函數(shù)的實(shí)際參數(shù)類型是指針類型,因此具有數(shù)組參數(shù)的函數(shù)調(diào)用將執(zhí)行數(shù)組到指針的轉(zhuǎn)換; 參數(shù)數(shù)組的大小對被調(diào)用的函數(shù)不可用,并且必須顯式傳遞:
void f(int a[], int sz) // actually declares int f(int* a, int sz){ for(int i = 0; i < sz; ++i) printf("%d\n", a[i]);}int main(void){ int a[10]; f(a, 10); // converts a to int*, passes the pointer}
當(dāng)一個(gè)數(shù)組的元素類型是另一個(gè)數(shù)組時(shí),據(jù)說這個(gè)數(shù)組是多維的:
// array of 2 arrays of 3 ints eachint a[2][3] = {{1,2,3}, // can be viewed as a 2x3 matrix {4,5,6}}; // with row-major layout
請注意,當(dāng)應(yīng)用數(shù)組到指針的轉(zhuǎn)換時(shí),多維數(shù)組將轉(zhuǎn)換為指向其第一個(gè)元素的指針,例如指向第一行的指針:
int a[2][3]; // 2x3 matrixint (*p1)[3] = a; // pointer to the first 3-element rowint b[3][3][3]; // 3x3x3 cubeint (*p2)[3][3] = a; // pointer to the first 3x3 plane
Multidimensional arrays may be variably modified in every dimension: int n = 10; int an; | (since C99) |
---|
不允許使用零長度數(shù)組聲明,即使有些編譯器將它們作為擴(kuò)展提供(通常作為靈活數(shù)組成員的 C99之前的實(shí)現(xiàn))。
如果 VLA 的大小表達(dá)式有副作用,除非它是 sizeof 表達(dá)式的結(jié)果并不依賴于它的一部分,否則它們將被保證產(chǎn)生:
int n = 5;int m = 7;size_t sz = sizeof(int (*)[n++]); // may or may not increment n
C11標(biāo)準(zhǔn)(ISO / IEC 9899:2011):
6.7.6.2數(shù)組聲明符(p:130-132)
C99標(biāo)準(zhǔn)(ISO / IEC 9899:1999):
6.7.5.2數(shù)組聲明符(p:116-118)
C89 / C90標(biāo)準(zhǔn)(ISO / IEC 9899:1990):
3.5.4.2數(shù)組聲明符