?
This document uses PHP Chinese website manual Release
數(shù)組是由連續(xù)分配的具有特定元素類型的非空對象序列組成的類型。在陣列生命周期內,這些對象的數(shù)量(數(shù)組大?。┯肋h不會改變。
在數(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ù)原型范圍內)其中
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ù)組聲明符中的表達式是一個整數(shù)常量表達式,其值大于零且元素類型是已知常量大小的類型(即元素不是 VLA)(因為 C99),那么聲明符聲明一個數(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ù)組聲明符中允許使用其他語法元素:關鍵字static和qualifiers,它們可能在大小表達式之前以任何順序出現(xiàn)(即使忽略大小表達式時它們也可能出現(xiàn))。在每個函數(shù)調用一個函數(shù),其中數(shù)組類型的參數(shù)使用與之間的關鍵字static時,實際參數(shù)的值必須是指向數(shù)組的第一個元素的有效指針,其中至少與expression指定的元素數(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的調用執(zhí)行編譯時邊界檢查//并且還允許優(yōu)化,例如預取10個雙精度int main(void){double a10 = {0},b20 = {0}; fadd(a,b); // OK double x5 = {0}; fadd(x,b); //錯誤:數(shù)組參數(shù)太小}如果存在限定符,它們限定數(shù)組參數(shù)類型轉換的指針類型: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ù)組如果表達式不是一個整型常量表達式,那么聲明符是可變大小的數(shù)組。每當控制流程通過聲明時,表達式被評估(并且它必須總是計算大于零的值),并且分配數(shù)組(相應地,當聲明超出范圍時,VLA的生存期結束)。每個VLA實例的大小在其生命周期內不會更改,但在另一次傳遞相同的代碼時,它可能會以不同的大小進行分配。{int n = 1; label:int an; //重新分配10次,每次都有不同的大小printf(“數(shù)組有%zu元素\ n”,sizeof a / sizeof * a); 如果(n ++ <10)轉到標簽; //離開VLA的范圍終止其生命周期}如果大小是*,則聲明是針對未指定大小的VLA。這種聲明只能出現(xiàn)在函數(shù)原型范圍內,并聲明一個完整類型的數(shù)組。事實上,將函數(shù)原型范圍內的所有VLA聲明符視為用*替換表達式。void foo(size_t x,int a *); void foo(size_t x,int ax){printf(“%zu \ n”,sizeof a); //與sizeof(int *)相同}可變長度數(shù)組及其派生類型(指向它們的指針等)通常稱為“可變修改類型”(VM)。任何可變修改類型的對象只能在塊范圍或函數(shù)原型范圍內聲明。extern int n; int An; //錯誤:文件范圍VLA extern int(* p2)n; //錯誤:文件范圍VM int B100; // OK:常量已知大小的文件范圍數(shù)組void fvla(int m,int Cm); // OK:原型范圍VLA VLA必須具有自動存儲持續(xù)時間。指向VLA,而不是VLA本身也可能具有靜態(tài)存儲持續(xù)時間。沒有VM類型可能有聯(lián)系。void fvla(int m,int Cm)// OK:塊范圍/自動持續(xù)時間VLA的指針{typedef int VLAm; // OK:塊范圍VLA int Dm; // OK:塊范圍/自動持續(xù)時間VLA // static int Em; //錯誤:靜態(tài)持續(xù)時間VLA // extern int Fm; //錯誤:帶連接的VLA int(* s)m; // OK:塊范圍/自動持續(xù)時間VM // extern int(* r)m; //錯誤:具有鏈接靜態(tài)int的虛擬機(* q)m =&B; // OK:塊范圍/靜態(tài)持續(xù)時間VM}}可變更改的類型不能是結構或聯(lián)合的成員。結構標記{int zn; //錯誤:VLA struct member int(* y)n; //錯誤:VM結構成員}; 帶連接int(* s)m的VLA; // OK:塊范圍/自動持續(xù)時間VM // extern int(* r)m; //錯誤:具有鏈接靜態(tài)int的虛擬機(* q)m =&B; // OK:塊范圍/靜態(tài)持續(xù)時間VM}}可變更改的類型不能是結構或聯(lián)合的成員。結構標記{int zn; //錯誤:VLA struct member int(* y)n; //錯誤:VM結構成員}; 帶連接int(* s)m的VLA; // OK:塊范圍/自動持續(xù)時間VM // extern int(* r)m; //錯誤:具有鏈接靜態(tài)int的虛擬機(* q)m =&B; // OK:塊范圍/靜態(tài)持續(xù)時間VM}}可變更改的類型不能是結構或聯(lián)合的成員。結構標記{int zn; //錯誤:VLA struct member int(* y)n; //錯誤:VM結構成員}; | (自C99以來) |
---|---|
如果編譯器將宏常量__STDC_NO_VLA__定義為整數(shù)常量1,則不支持VLA和VM類型。 | (自C11以來) |
如果數(shù)組聲明符中的表達式被省略,它將聲明一個未知大小的數(shù)組。除了函數(shù)參數(shù)列表(這些數(shù)組被轉換為指針)以及初始化程序可用時,這種類型是不完整的類型(請注意,未指定大小的 VLA,以大小聲明*
,是一個完整類型)(自 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"
在一個結構體定義中,未知大小的數(shù)組可能會作為最后一個成員出現(xiàn)(只要至少有一個其他已命名成員),在這種情況下,它就是一個特殊情況,稱為靈活數(shù)組成員。有關詳細信息,請參閱struct:struct s {int n; double d []; }; // sd是一個靈活的數(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)在賦值運算符的左側。但是,數(shù)組成員的結構是可修改的左值,可以賦值為:
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ù)組類型的任何左值表達式,當在除。以外的任何上下文中使用時。
作為操作符地址的操作數(shù)
作為 sizeof 的操作數(shù)
作為用于數(shù)組初始化的字符串文字
as the operand of _Alignof | (since C11) |
---|
作為_Alignof 的操作數(shù)
(since C11)
經歷了對指向其第一個元素的隱式轉換。結果不是左值。
如果數(shù)組被聲明為 register,那么嘗試這種轉換的程序的行為是未定義的。
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ù)組類型時,它將轉換為相應的指針類型:int f(int a[2])
和int f(int* a)
聲明相同的函數(shù)。由于函數(shù)的實際參數(shù)類型是指針類型,因此具有數(shù)組參數(shù)的函數(shù)調用將執(zhí)行數(shù)組到指針的轉換; 參數(shù)數(shù)組的大小對被調用的函數(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}
當一個數(shù)組的元素類型是另一個數(shù)組時,據(jù)說這個數(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
請注意,當應用數(shù)組到指針的轉換時,多維數(shù)組將轉換為指向其第一個元素的指針,例如指向第一行的指針:
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ù)組聲明,即使有些編譯器將它們作為擴展提供(通常作為靈活數(shù)組成員的 C99之前的實現(xiàn))。
如果 VLA 的大小表達式有副作用,除非它是 sizeof 表達式的結果并不依賴于它的一部分,否則它們將被保證產生:
int n = 5;int m = 7;size_t sz = sizeof(int (*)[n++]); // may or may not increment n
C11標準(ISO / IEC 9899:2011):
6.7.6.2數(shù)組聲明符(p:130-132)
C99標準(ISO / IEC 9899:1999):
6.7.5.2數(shù)組聲明符(p:116-118)
C89 / C90標準(ISO / IEC 9899:1990):
3.5.4.2數(shù)組聲明符