首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言數組完全指南:聲明、初始化、多維數組、指針關系與性能優化

     編輯:關於C語言

前言

數組是 C 語言最基礎的聚合類型,看似簡單,實則蘊含豐富的內存佈局規則、指針轉換語義、編譯器優化機會與工程陷阱。本文系統梳理數組聲明初始化、多維數組行主序佈局、數組名與指針的微妙關系、可變長數組(VLA)、柔性數組成員,並給出性能優化實戰指南。

一、數組聲明與初始化

1. 基本聲明語法

type name[size];           // 固定長度,size 為常量表達式(C89)
type name[] = {init...};   // 推導長度
type name[size] = {init};  // 部分初始化,餘位零初始化
type name[size] = {0};     // 全零初始化(通用模式)

2. 指定初始化器

int arr[10] = { [0]=1, [5]=10, [9]=100 };  // C99
int arr[] = { [2]=5, [0]=1 };               // 長度推導為 3

3. 字符數組特殊初始化

char str[] = "hello";  // 等價於 {'h','e','l','l','o','\0'},長度 6
char str[6] = "hello"; // 同
char str[5] = "hello"; // 警告:截斷 \0,非字符串

二、多維數組與行主序佈局

1. 內存佈局:行主序

int a[2][3] = { {1,2,3}, {4,5,6} };
// 內存連續:1 2 3 4 5 6
// a[0][0] 地址最低,a[1][2] 最高

2. 指針算術與下標等價

a[i][j]  ==  *(*(a + i) + j)  ==  *(a[0] + i*3 + j)

編譯器將 a[i][j] 降為 *(a[0] + i*COLS + j),需知道列數 COLS。

3. 函數參數傳遞:退化為指針

// 以下聲明等價,參數實為 int (*)[3]
void foo(int a[][3]);
void foo(int (*a)[3]);
// 調用:foo(arr);  // arr 類型 int [2][3] → int (*)[3]

第一維長度丟失,第二維必須保留。

4. 動態分配二維數組三種模式

// 模式 1:單塊連續內存(推薦,緩存友好)
int (*p)[COLS] = malloc(ROWS * COLS * sizeof(int));
p[i][j]  // 直接雙下標訪問

// 模式 2:指針數組(行不連續)
int **p = malloc(ROWS * sizeof(int *));
for (i) p[i] = malloc(COLS * sizeof(int));
p[i][j]  // 雙重間接訪問

// 模式 3:扁平化一維數組(手動計算索引)
int *p = malloc(ROWS * COLS * sizeof(int));
p[i*COLS + j]  // 手動計算,最靈活

三、數組名、指針與 sizeof 核心規則

1. 數組名的雙重身份

  • 大多數表達式中:退化為**指向首元素的指針** type *(右值)
  • 三個例外(數組名代表整個數組對象):
    1. sizeof(arr):返回整個數組字節大小
    2. &arr:類型 type (*)[N],指向整個數組的指針
    3. 字符串字面量初始化:char arr[] = "abc"

2. sizeof 與指針的經典陷阱

int arr[10];
int *p = arr;
sizeof(arr)  // 40 (假設 int 4 字節)
sizeof(p)    // 8 (64 位指針大小)
sizeof(*p)   // 4 (int 大小)

3. 函數參數中 sizeof 失效

void foo(int arr[100]) {  // 實為 int *arr
    sizeof(arr);  // 返回指針大小,非數組大小!
}
// 必須額外傳遞長度參數

四、進階特性:VLA 與柔性數組成員

1. 可變長數組(VLA,C99/C11 可選)

void foo(int n) {
    int arr[n];  // 棧上分配,n 為運行時值
    // ...
}  // 作用域結束自動釋放

優點:避免 malloc 開銷、自動釋放。缺點:棧溢出風險、不支持初始化列表、C11 後為可選特性(__STDC_NO_VLA__),Microsoft MSVC 不支持。

2. 柔性數組成員(C99)

struct Buffer {
    size_t len;
    char data[];  // 最後一個成員,無長度
};

// 分配:一次 malloc 獲取結構體 + 數據區
struct Buffer *buf = malloc(sizeof(struct Buffer) + 1024);
buf->len = 1024;
// 釋放:free(buf) 一次完成

用於變長結構體、網絡包、文件系統 inode 等場景,替代「結構體 + 指針」雙重分配模式。

五、性能優化實戰指南

1. 緩存局部性:行主序順序訪問

// 差:列優先(步長大,缺失多)
for (j=0; j

2. 循環展開與向量化輔助

// 手動展開 4x,幫助編譯器生成 SIMD
for (i=0; i

3. 對齊分配:aligned_alloc / posix_memalign

int *p = aligned_alloc(64, n * sizeof(int));  // 64 字節對齊,利用 AVX-512

4. 避免別名阻礙優化

  1. 上一篇文章:
  2. 下一篇文章:
欄目導航
Copyright © 程式碼之家 All Rights Reserved