目录搜索
AlgorithmsAlgorithms(算法)bsearchbsearch_sqsortqsort_sAtomic operationsAtomic operations library(原子操作库)ATOMIC_*_LOCK_FREEatomic_compare_exchange_strongatomic_compare_exchange_strong_explicitatomic_compare_exchange_weakatomic_compare_exchange_weak_explicitatomic_exchangeatomic_exchange_explicitatomic_fetch_addatomic_fetch_add_explicitatomic_fetch_andatomic_fetch_and_explicitatomic_fetch_oratomic_fetch_or_explicitatomic_fetch_subatomic_fetch_sub_explicitatomic_fetch_xoratomic_fetch_xor_explicitatomic_flagatomic_flag_clearatomic_flag_clear_explicitATOMIC_FLAG_INITatomic_flag_test_and_setatomic_flag_test_and_set_explicitatomic_initatomic_is_lock_freeatomic_loadatomic_load_explicitatomic_signal_fenceatomic_storeatomic_store_explicitatomic_thread_fence(线程围栏)ATOMIC_VAR_INITkill_dependencymemory_order(内存排序)C keywordsauto(自动存储)break(跳出循环)C keywords(关键词)casecharconst(常量修饰符)continuedefault(预设运算式)dodouble(双精度浮点型)elseenum(枚举类型)extern(全局变量)float(浮点数)forfortrangoto(goto语句)if(if语句)inline(行内函式)intlong(长整型)register(寄存器变量)restrict( restrict类型限定符)returnshortsignedsizeof(sizeof运算符)static(静态变量)struct(结构体)switch(switch语句)typedef(typedef关键字)union(联合体)unsigned(无符号)void(空类型)volatile(volatile变量)while(while语句)_Alignas_Alignof_Atomic_Bool_Complex_Generic_Imaginary_Noreturn_Static_assert_Thread_localC language#define directive#elif directive#else directive#endif directive#error directive#if directive#ifdef directive#ifndef directive#include directive#line directive#pragma directivealignas(对齐指定符)Alternative operators and tokens(替代运算符和令牌)AnalyzabilityArithmetic operatorsArithmetic typesArray declaration(数组声明)Array initialization(阵列初始化)ASCII ChartAssignment operators(赋值运算符)types(atomic类型限定符)Basic conceptsBit fields(位域)break statementC languageC Operator Precedencecast operatorcharacter constant(字符字面量)Comments(注释符)Comparison operators(比较运算符)compound literals(符合字面量)Conditional inclusion(条件包含)Conformance(一致性)const type qualifier(const 限定符)Constant expressions(常量表达)continue statementDeclarations(声明)do-while loopEnumerations(枚举类型)Escape sequences(转义字符)Expressions(表达式)External and tentative definitions(外部和暂定的定义)File scope(文件范围)floating constant(浮点常量)for loopFunction declarations(函数声明)Function definitions(函数声明)FunctionsGeneric selection泛型选择goto statementIdentifier(标示符)if statementImplicit conversions(隐式转换)Increment/decrement operators(前置/后置操作符)Initialization(初始化)inline function specifier(内联函式)integer constantLifetime(生命期)Logical operators(逻辑运算符)Lookup and name spacesMain function(主函式)Member access operators(会员接入运营商)Memory modelObjects and alignment(字节对齐)Order of evaluation(评估顺序)Other operatorsPhases of translation(翻译阶段)Pointer declarationPreprocessor(预处理)restrict type qualifier(restrict类型限定符)return statementScalar initialization(标量类型初始化)Scope(范围)sizeof operator(sizeof运算符)Statements(陈述)static assert declaration(静态断言声明)Static storage duration(静态存储周期)Storage-class specifiers(存储类说明符)string literals(字符串字面量)Struct and union initialization(结构体与联合体初始化)Struct declaration(结构体声明)switch statementThread storage duration(线程存储时间)TypeType(类型)Typedef declaration(Typedef声明)Undefined behavior(未定义行为)Union declaration(联合体声明)Value categories(值类别)Variadic arguments(变长参数宏)volatile type qualifier(volatile 类型限定符)while loop_Alignof operator_Noreturn function specifierDate and timeasctime(asctime函数)asctime_sclockCLOCKS_PER_SECclock_tctime(ctime函数)ctime_sDate and time utilities(日期和时间库)difftime(计算两个时间的间隔)gmtimegmtime_slocaltimelocaltime_smktime(将时间结构数据转换成经过的秒数的函数)strftime(格式化输出时间函数)timetimespectimespec_gettime_ttmwcsftime(格式化时间宽字符)Dynamic memory managementaligned_allocC memory management library(内存管理库)callocfree(释放动态分配空间的函数)malloc(动态分配内存空间的函数)realloc(重新分配内存空间的函数)Error handlingabort_handler_sassert(断言)constraint_handler_terrno(错误报告)Error handling(错误处理)Error numbers(错误个数)ignore_handler_sset_constraint_handler_sstatic_assertFile input/outputclearerr(清除/复位)fclosefeofferrorfflush(清空文件缓冲区)fgetcfgetposfgetsfgetwcfgetwsFile input/outputfopenfopen_sfprintffprintf_sfputcfputsfputwcfputwsfreadfreopenfreopen_sfscanffscanf_sfseekfsetposftellfwidefwprintffwprintf_sfwritefwscanffwscanf_sgetcgetchargetsgets_sgetwcharperrorprintfprintf_sputcputcharputsputwcputwcharremoverenamerewindscanfscanf_ssetbufsetvbufsnprintfsprintfsscanfsscanf_sswprintfswprintf_sswscanfswscanf_stmpfiletmpfile_stmpnamtmpnam_sungetcungetwcvfprintfvfprintf_svfscanfvfscanf_svfwprintfvfwprintf_svfwscanfvfwscanf_svprintfvprintf_svscanfvscanf_svsnprintfvsprintfvsscanfvsscanf_svswprintfvswprintf_svswscanfvswscanf_svwprintfvwprintf_svwscanfvwscanf_swprintfwprintf_swscanfwscanf_sLocalization supportlconvLC_ALLLC_COLLATELC_CTYPELC_MONETARYLC_NUMERICLC_TIMElocaleconvLocalization supportsetlocaleNumericsabsacosacosfacoshacoshfacoshlacoslasinasinfasinhasinhfasinhlasinlatanatan2atan2fatan2latanfatanhatanhfatanhlatanlcabscabsfcabslcacoscacosfcacoshcacoshfcacoshlcacoslcargcargfcarglcasincasinfcasinhcasinhfcasinhlcasinlcatancatanfcatanhcatanhfcatanhlcatanlcbrtcbrtfcbrtlccosccosfccoshccoshfccoshlccoslceilceilfceillcexpcexpfcexplcimagcimagfcimaglclogclogfcloglCMPLXCMPLXFCMPLXLCommon mathematical functionscomplexComplex number arithmeticconjconjfconjlcopysigncopysignfcopysignlcoscosfcoshcoshfcoshlcoslcpowcpowfcpowlcprojcprojfcprojlcrealcrealfcreallcsincsinfcsinhcsinhfcsinhlcsinlcsqrtcsqrtfcsqrtlctanctanfctanhctanhfctanhlctanldivdouble_terferfcerfcferfclerfferflexpexp2exp2fexp2lexpfexplexpm1expm1fexpm1lfabsfabsffabslfdimfeclearexceptfegetenvfegetexceptflagfegetroundfeholdexceptferaiseexceptfesetenvfesetexceptflagfesetroundfetestexceptfeupdateenvFE_ALL_EXCEPTFE_DFL_ENVFE_DIVBYZEROFE_DOWNWARDFE_INEXACTFE_INVALIDFE_OVERFLOWFE_TONEARESTFE_TOWARDZEROFE_UNDERFLOWFE_UPWARDFloating-point environmentfloat_tfloorfloorffloorlfmafmaffmalfmaxfmaxffmaxlfminfminffminlfmodfmodffmodlfpclassifyFP_INFINITEFP_NANFP_NORMALFP_SUBNORMALFP_ZEROfrexpfrexpffrexplHUGE_VALHUGE_VALFHUGE_VALLhypothypotfhypotlIilogbilogbfilogblimaginaryimaxabsimaxdivINFINITYisfiniteisgreaterisgreaterequalisinfislessislessequalislessgreaterisnanisnormalisunorderedlabsldexpldexpfldexplldivlgammalgammaflgammalllabslldivllrintllrintfllrintlllroundllroundfllroundlloglog10log10flog10llog1plog1pflog1pllog2log2flog2llogblogbflogbllogflogllrintlrintflrintllroundlroundflroundlMATH_ERREXCEPTmath_errhandlingMATH_ERRNOmodfmodffmodflnanNANnanfnanlnearbyintnearbyintfnearbyintlnextafternextafterfnextafterlnexttowardnexttowardfnexttowardlNumericspowpowfpowlPseudo-random number generationrandRAND_MAXremainderremainderfremainderlremquoremquofremquolrintrintfrintlroundroundfroundlscalblnscalblnfscalblnlscalbnscalbnfscalbnlsignbitsinsinfsinhsinhfsinhlsinlsqrtsqrtfsqrtlsrandtantanftanhtanhftanhltanltgammatgammaftgammaltrunctruncftrunclType-generic math_Complex_I_Imaginary_IProgram supportabortatexitat_quick_exitexitEXIT_FAILUREEXIT_SUCCESSgetenvgetenv_sjmp_buflongjmpProgram support utilitiesquick_exitraisesetjmpSIGABRTSIGFPESIGILLSIGINTsignalSIGSEGVSIGTERMsig_atomic_tSIG_DFLSIG_ERRSIG_IGNsystem_ExitStringsatofatoiatolatollbtowcc16rtombc32rtombchar16_tchar32_tisalnumisalphaisblankiscntrlisdigitisgraphislowerisprintispunctisspaceisupperiswalnumiswalphaiswblankiswcntrliswctypeiswdigitiswgraphiswloweriswprintiswpunctiswspaceiswupperiswxdigitisxdigitmblenmbrlenmbrtoc16mbrtoc32mbrtowcmbsinitmbsrtowcsmbsrtowcs_smbstate_tmbstowcsmbstowcs_smbtowcmemchrmemcmpmemcpymemcpy_smemmovememmove_smemsetmemset_sNull-terminated byte stringsNull-terminated multibyte stringsNull-terminated wide stringsstrcatstrcat_sstrchrstrcmpstrcollstrcpystrcpy_sstrcspnstrerrorstrerrorlen_sstrerror_sStrings librarystrlenstrncatThread supportcall_oncecnd_broadcastcnd_destroycnd_initcnd_signalcnd_timedwaitcnd_waitmtx_destroymtx_initmtx_lockmtx_plainmtx_recursivemtx_timedmtx_timedlockmtx_trylockmtx_unlockonce_flagONCE_FLAG_INITthrd_busythrd_createthrd_currentthrd_detachthrd_equalthrd_errorthrd_exitthrd_jointhrd_nomemthrd_sleepthrd_successthrd_timedoutthrd_yieldThread support librarythread_localtss_createtss_deleteTSS_DTOR_ITERATIONStss_gettss_setType supportBoolean type support libraryFixed width integer typesFLT_EVAL_METHODFLT_ROUNDSmax_align_tNULLNumeric limitsoffsetofptrdiff_tsize_tType supportVariadic functionsVariadic functionsva_argva_copyva_endva_listva_start
文字

数组是由连续分配的具有特定元素类型的非空对象序列组成的类型。在阵列生命周期内,这些对象的数量(数组大小)永远不会改变。

句法

在数组声明的声明语法中,类型说明符序列指定元素类型(必须是完整的对象类型),声明符的格式如下:

static(optional) qualifiers(optional) expression(optional)

(1)


qualifiers(optional) static(optional) expression(optional)

(2)


qualifiers(optional) *

(3)


1,2)常规数组声明语法

3)未指定大小的 VLA 的声明符(只能出现在函数原型范围内)其中

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

说明

数组类型有多种变体:已知常量大小的数组,可变长度数组和大小未知的数组。

恒定已知大小的数组

如果数组声明符中的表达式是一个整数常量表达式,其值大于零且元素类型是已知常量大小的类型(即元素不是 VLA)(因为 C99),那么声明符声明一个数组恒定的已知尺寸:

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

已知大小的常量数组可以使用数组初始化器来提供它们的初始值:

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'

在函数参数列表中,数组声明符中允许使用其他语法元素:关键字static和qualifiers,它们可能在大小表达式之前以任何顺序出现(即使忽略大小表达式时它们也可能出现)。在每个函数调用一个函数,其中数组类型的参数使用与之间的关键字static时,实际参数的值必须是指向数组的第一个元素的有效指针,其中至少与expression指定的元素数量一样多:void fadd(double astatic 10,const double bstatic 10){for(int i = 0; i <10; i ++){if(ai <0.0)return; ai + = bi; }} //对fadd的调用执行编译时边界检查//并且还允许优化,例如预取10个双精度int main(void){double a10 = {0},b20 = {0}; fadd(a,b); // OK double x5 = {0}; fadd(x,b); //错误:数组参数太小}如果存在限定符,它们限定数组参数类型转换的指针类型:int f(const int a20){//在此函数中,a的类型为const int *(指向const int的指针)} int g(const int aconst 20){//在此函数中,a的类型为const int * const(const指针的常量)}这通常与restrict类型限定符一起使用:void fadd(double (int i = 0; i <10; i ++){//如果(ai <0.0)break,循环可以展开并重新排序; ai + = bi; }}变长数组如果表达式不是一个整型常量表达式,那么声明符是可变大小的数组。每当控制流程通过声明时,表达式被评估(并且它必须总是计算大于零的值),并且分配数组(相应地,当声明超出范围时,VLA的生存期结束)。每个VLA实例的大小在其生命周期内不会更改,但在另一次传递相同的代码时,它可能会以不同的大小进行分配。{int n = 1; label:int an; //重新分配10次,每次都有不同的大小printf(“数组有%zu元素\ n”,sizeof a / sizeof * a); 如果(n ++ <10)转到标签; //离开VLA的范围终止其生命周期}如果大小是*,则声明是针对未指定大小的VLA。这种声明只能出现在函数原型范围内,并声明一个完整类型的数组。事实上,将函数原型范围内的所有VLA声明符视为用*替换表达式。void foo(size_t x,int a *); void foo(size_t x,int ax){printf(“%zu \ n”,sizeof a); //与sizeof(int *)相同}可变长度数组及其派生类型(指向它们的指针等)通常称为“可变修改类型”(VM)。任何可变修改类型的对象只能在块范围或函数原型范围内声明。extern int n; int An; //错误:文件范围VLA extern int(* p2)n; //错误:文件范围VM int B100; // OK:常量已知大小的文件范围数组void fvla(int m,int Cm); // OK:原型范围VLA VLA必须具有自动存储持续时间。指向VLA,而不是VLA本身也可能具有静态存储持续时间。没有VM类型可能有联系。void fvla(int m,int Cm)// OK:块范围/自动持续时间VLA的指针{typedef int VLAm; // OK:块范围VLA int Dm; // OK:块范围/自动持续时间VLA // static int Em; //错误:静态持续时间VLA // extern int Fm; //错误:带连接的VLA int(* s)m; // OK:块范围/自动持续时间VM // extern int(* r)m; //错误:具有链接静态int的虚拟机(* q)m =&B; // OK:块范围/静态持续时间VM}}可变更改的类型不能是结构或联合的成员。结构标记{int zn; //错误:VLA struct member int(* y)n; //错误:VM结构成员}; 带连接int(* s)m的VLA; // OK:块范围/自动持续时间VM // extern int(* r)m; //错误:具有链接静态int的虚拟机(* q)m =&B; // OK:块范围/静态持续时间VM}}可变更改的类型不能是结构或联合的成员。结构标记{int zn; //错误:VLA struct member int(* y)n; //错误:VM结构成员}; 带连接int(* s)m的VLA; // OK:块范围/自动持续时间VM // extern int(* r)m; //错误:具有链接静态int的虚拟机(* q)m =&B; // OK:块范围/静态持续时间VM}}可变更改的类型不能是结构或联合的成员。结构标记{int zn; //错误:VLA struct member int(* y)n; //错误:VM结构成员};

(自C99以来)

如果编译器将宏常量__STDC_NO_VLA__定义为整数常量1,则不支持VLA和VM类型。

(自C11以来)

未知尺寸的阵列

如果数组声明符中的表达式被省略,它将声明一个未知大小的数组。除了函数参数列表(这些数组被转换为指针)以及初始化程序可用时,这种类型是不完整的类型(请注意,未指定大小的 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"

在一个结构体定义中,未知大小的数组可能会作为最后一个成员出现(只要至少有一个其他已命名成员),在这种情况下,它就是一个特殊情况,称为灵活数组成员。有关详细信息,请参阅struct:struct s {int n; double d []; }; // sd是一个灵活的数组成员struct s * s1 = malloc(sizeof(struct s)+(sizeof(double)* 8)); //好像d是双d8

(自C99以来)

预选赛

如果使用 const,volatile,restrict(自C99)或_Atomic(自C11)限定符(可通过使用 typedef)声明数组类型,则数组类型不是限定的,但其元素类型为:

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*

分配

数组类型的对象不是可修改的左值,虽然它们的地址可以被采用,但它们不能出现在赋值运算符的左侧。但是,数组成员的结构是可修改的左值,可以赋值为:

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

数组到指针的转换

数组类型的任何左值表达式,当在除。以外的任何上下文中使用时。

  • 作为操作符地址的操作数

  • 作为 sizeof 的操作数

  • 作为用于数组初始化的字符串文字

as the operand of _Alignof

(since C11)

  • 作为_Alignof 的操作数

(since C11)

经历了对指向其第一个元素的隐式转换。结果不是左值。

如果数组被声明为 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

在函数参数列表中使用数组类型时,它将转换为相应的指针类型:int f(int a[2])int f(int* a)声明相同的函数。由于函数的实际参数类型是指针类型,因此具有数组参数的函数调用将执行数组到指针的转换; 参数数组的大小对被调用的函数不可用,并且必须显式传递:

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}

多维数组

当一个数组的元素类型是另一个数组时,据说这个数组是多维的:

// 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

请注意,当应用数组到指针的转换时,多维数组将转换为指向其第一个元素的指针,例如指向第一行的指针:

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)

注意

不允许使用零长度数组声明,即使有些编译器将它们作为扩展提供(通常作为灵活数组成员的 C99之前的实现)。

如果 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数组声明符(p:130-132)

  • C99标准(ISO / IEC 9899:1999):

    • 6.7.5.2数组声明符(p:116-118)

  • C89 / C90标准(ISO / IEC 9899:1990):

    • 3.5.4.2数组声明符

上一篇:下一篇: