1. C语言数组的本质与核心价值
数组是C语言中最基础却最强大的数据结构之一,它本质上是一块连续的内存空间,用于存储相同类型的元素集合。这种连续存储特性带来了两个关键优势:一是可以通过下标直接计算出元素的内存地址(地址=基地址+下标×元素大小),实现O(1)时间复杂度的随机访问;二是由于局部性原理,数组遍历时CPU缓存命中率极高。
在实际开发中,数组的应用场景远超初学者想象。从最简单的成绩统计、传感器数据采集,到图像处理中的像素矩阵、游戏开发中的地图网格,再到算法中的哈希表、堆、栈等高级数据结构的底层实现,数组都扮演着核心角色。特别是在嵌入式系统和实时系统中,由于内存受限且对性能要求严苛,数组因其确定的内存占用和高效的访问特性成为首选。
关键理解:数组的"连续内存"特性既是优势也是约束。优势在于访问高效,约束在于大小固定。这也是为什么后续发展出了动态数组、链表等变体结构。
2. 数组的声明与初始化实战技巧
2.1 基础声明方式解析
C语言中数组的标准声明语法为:
数据类型 数组名[元素个数];例如声明一个包含10个整数的数组:
int scores[10];但实际工程中,我们更推荐使用宏定义或常量来指定数组大小,避免魔法数字:
#define MAX_STUDENTS 50 int studentScores[MAX_STUDENTS];2.2 初始化的高级用法
数组初始化有多种形式,每种都有其适用场景:
- 完全初始化:
int primes[5] = {2, 3, 5, 7, 11};- 部分初始化(剩余元素自动补0):
int arr[10] = {1, 2}; // 后8个元素为0- 自动计算大小:
int days[] = {31,28,31,30,31}; // 编译器自动计算为5- 字符数组的特殊性:
char str1[] = {'H','e','l','l','o'}; // 长度5 char str2[] = "Hello"; // 长度6(包含'\0')2.3 多维数组的内存布局
以二维数组为例:
int matrix[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };在内存中实际是按行优先顺序连续存储的:
1 2 3 4 5 6 7 8 9 10 11 12理解这一点对性能优化至关重要。访问数组元素时,应该尽量利用局部性原理,按内存顺序访问(即外层循环行,内层循环列)。
3. 数组与指针的深度关联
3.1 数组名的双重身份
数组名在大多数情况下会退化为指向首元素的指针,但有两个例外:
- 使用
sizeof(arr)时,返回的是整个数组的字节大小 - 使用
&arr时,得到的是指向整个数组的指针(类型为int(*)[N])
这种特性导致了许多初学者困惑。例如:
int arr[5]; printf("%p\n", arr); // 类型是int* printf("%p\n", &arr); // 类型是int(*)[5] // 值相同但类型不同3.2 指针运算遍历数组
以下两种遍历方式完全等价:
// 下标法 for(int i=0; i<5; i++) { printf("%d ", arr[i]); } // 指针法 for(int *p=arr; p<arr+5; p++) { printf("%d ", *p); }指针法的优势在于某些特定场景下更高效,特别是在处理字符串或硬件寄存器时。
3.3 数组作为函数参数
当数组传递给函数时,实际传递的是指针(首元素地址)。因此以下三种函数声明完全等价:
void func(int *arr); void func(int arr[]); void func(int arr[10]); // 这里的10会被忽略这也解释了为什么在函数内部无法用sizeof获取数组真实大小,必须额外传递长度参数。
4. 数组的典型应用场景剖析
4.1 实现基础数据结构
栈的实现示例:
#define MAX_SIZE 100 typedef struct { int data[MAX_SIZE]; int top; } Stack; void push(Stack *s, int val) { if(s->top >= MAX_SIZE-1) { printf("Stack overflow\n"); return; } s->data[++(s->top)] = val; } int pop(Stack *s) { if(s->top < 0) { printf("Stack underflow\n"); return -1; } return s->data[(s->top)--]; }4.2 位图(Bitmap)应用
用数组实现位图是空间效率极高的方案:
#define BITSPERWORD 32 #define SHIFT 5 #define MASK 0x1F int bitmap[1 + N/BITSPERWORD]; void set(int i) { bitmap[i>>SHIFT] |= (1<<(i & MASK)); } int test(int i) { return bitmap[i>>SHIFT] & (1<<(i & MASK)); }这种技术广泛应用于操作系统(页表管理)、数据库(布隆过滤器)、网络(路由表)等领域。
4.3 矩阵运算优化
矩阵乘法的最优实现需要考虑缓存命中率:
// 非优化版本(列优先,缓存不友好) void matmul(int **a, int **b, int **c, int n) { for(int i=0; i<n; i++) for(int j=0; j<n; j++) for(int k=0; k<n; k++) c[i][j] += a[i][k] * b[k][j]; } // 优化版本(分块处理,提高缓存命中) #define BLOCK_SIZE 32 void matmul_opt(int **a, int **b, int **c, int n) { for(int i0=0; i0<n; i0+=BLOCK_SIZE) for(int j0=0; j0<n; j0+=BLOCK_SIZE) for(int k0=0; k0<n; k0+=BLOCK_SIZE) for(int i=i0; i<i0+BLOCK_SIZE; i++) for(int j=j0; j<j0+BLOCK_SIZE; j++) for(int k=k0; k<k0+BLOCK_SIZE; k++) c[i][j] += a[i][k] * b[k][j]; }5. 数组使用中的陷阱与优化
5.1 常见错误排查表
| 错误类型 | 示例代码 | 问题分析 | 解决方案 |
|---|---|---|---|
| 数组越界 | int arr[5]; arr[5]=1; | 访问了非法内存 | 严格检查循环条件 |
| 大小不匹配 | int a[3]={1,2,3,4}; | 初始值过多 | 检查初始化列表 |
| 未初始化 | int arr[10]; printf("%d",arr[0]); | 值不确定 | 显式初始化 |
| 指针混淆 | int *p=arr; p++; arr++; | 数组名不是左值 | 使用临时指针变量 |
5.2 性能优化技巧
- 循环展开:减少循环控制开销
// 常规循环 for(int i=0; i<100; i++) sum += arr[i]; // 展开4次 for(int i=0; i<100; i+=4) { sum += arr[i]; sum += arr[i+1]; sum += arr[i+2]; sum += arr[i+3]; }- 预取数据:提前加载到缓存
for(int i=0; i<N; i++) { __builtin_prefetch(&arr[i+K]); // GCC内置函数 // 处理arr[i] }- 对齐访问:利用SIMD指令
// 确保数组按16字节对齐 __attribute__((aligned(16))) float vec[100];5.3 动态数组实现方案
虽然C语言原生不支持动态数组,但可以通过以下方式实现:
- malloc方案:
int *dynArr = (int*)malloc(size * sizeof(int)); // 使用... free(dynArr);- realloc扩容:
dynArr = (int*)realloc(dynArr, newSize * sizeof(int));- 柔性数组成员(C99):
struct dynArray { size_t length; int data[]; // 柔性成员 }; struct dynArray *arr = malloc(sizeof(struct dynArray) + length*sizeof(int));6. 现代C语言中的数组新特性
6.1 C99变长数组(VLA)
允许使用变量定义数组大小:
void func(int n) { int arr[n]; // VLA // ... }但需要注意:
- 不能初始化
- 栈空间有限,大数组可能溢出
- 某些嵌入式环境不支持
6.2 复合字面量
直接创建匿名数组:
int *ptr = (int[]){1, 2, 3}; // 复合字面量这在函数传参时特别有用:
printArray((int[]){1,2,3,4}, 4);6.3 指定初始化器
C99允许指定元素初始化:
int arr[10] = { [3]=7, [7]=9 }; // 其余为0对于结构数组尤其有用:
struct point { int x,y; } pts[5] = { [2].y=5, [3].x=8 };7. 数组在算法竞赛中的妙用
7.1 前缀和数组
快速求解区间和:
int nums[N], prefix[N+1]; // 构建前缀和数组 prefix[0] = 0; for(int i=0; i<N; i++) prefix[i+1] = prefix[i] + nums[i]; // 查询区间[i,j]的和 int sum = prefix[j+1] - prefix[i];7.2 差分数组
高效处理区间更新:
int diff[N+1]; // 初始全0 // 区间[i,j]增加val void add(int i, int j, int val) { diff[i] += val; if(j+1 < N) diff[j+1] -= val; } // 还原数组 for(int i=0, sum=0; i<N; i++) { sum += diff[i]; nums[i] += sum; }7.3 树状数组(Fenwick Tree)
高效维护前缀操作:
int tree[N+1]; // 1-based int lowbit(int x) { return x & -x; } void update(int i, int val) { while(i <= N) { tree[i] += val; i += lowbit(i); } } int query(int i) { int res = 0; while(i > 0) { res += tree[i]; i -= lowbit(i); } return res; }8. 数组与内存管理的深度思考
8.1 栈数组 vs 堆数组
| 特性 | 栈数组 | 堆数组(malloc) |
|---|---|---|
| 生命周期 | 所在作用域 | 直到free |
| 大小限制 | 较小(约MB级) | 受系统内存限制 |
| 分配速度 | 极快 | 相对较慢 |
| 访问速度 | 略快 | 略慢 |
| 适用场景 | 小型临时数组 | 大型或动态数组 |
8.2 缓存友好编程实践
- 访问模式优化:
// 差:列优先访问(对C语言不友好) for(int j=0; j<cols; j++) for(int i=0; i<rows; i++) sum += matrix[i][j]; // 好:行优先访问 for(int i=0; i<rows; i++) for(int j=0; j<cols; j++) sum += matrix[i][j];- 结构体数组 vs 数组结构体:
// AoS(不利于SIMD) struct { float x,y,z; } points[N]; // SoA(缓存友好) struct { float x[N], y[N], z[N]; } points;8.3 内存对齐实战
手动对齐示例:
// 16字节对齐数组 #ifdef _MSC_VER __declspec(align(16)) float arr[100]; #else float arr[100] __attribute__((aligned(16))); #endif // 动态分配对齐内存 void *aligned_malloc(size_t size, size_t align) { void *ptr = malloc(size + align - 1 + sizeof(void*)); if(!ptr) return NULL; void *aligned = (void*)(((uintptr_t)ptr + sizeof(void*) + align -1) & ~(align-1)); *((void**)aligned - 1) = ptr; return aligned; } void aligned_free(void *aligned) { free(*((void**)aligned - 1)); }9. 多维数组的高级应用
9.1 动态多维数组实现
方案1:指针数组
int **matrix = (int**)malloc(rows * sizeof(int*)); for(int i=0; i<rows; i++) matrix[i] = (int*)malloc(cols * sizeof(int));方案2:连续内存(更高效)
int **matrix = (int**)malloc(rows * sizeof(int*)); matrix[0] = (int*)malloc(rows * cols * sizeof(int)); for(int i=1; i<rows; i++) matrix[i] = matrix[0] + i * cols;9.2 锯齿数组(Jagged Array)
每行长度不同的数组:
int **jagged = (int**)malloc(rows * sizeof(int*)); for(int i=0; i<rows; i++) jagged[i] = (int*)malloc((i+1) * sizeof(int)); // 第i行有i+1个元素9.3 数组的数组 vs 一维数组模拟
性能对比:
// 传统二维数组 int arr2d[10][20]; arr2d[i][j] = value; // 一维数组模拟 int arr1d[10*20]; arr1d[i*20 + j] = value; // 更高效但可读性差10. 数组与其他数据结构的交互
10.1 数组与字符串
C字符串本质是字符数组:
char str1[] = "Hello"; // 自动添加'\0' char str2[10] = "World"; // 剩余补'\0' char *str3 = "Literal"; // 字符串常量(只读)安全操作建议:
- 使用
strncpy而非strcpy - 总是检查数组边界
- 考虑使用
snprintf格式化字符串
10.2 数组与结构体
结构体中的数组:
struct student { char name[20]; int scores[5]; };数组中的结构体:
struct point { int x,y; }; struct point polygon[10]; // 10个点的多边形10.3 数组与文件IO
二进制读写数组:
// 写入 float data[100]; FILE *fp = fopen("data.bin", "wb"); fwrite(data, sizeof(float), 100, fp); fclose(fp); // 读取 float newData[100]; fp = fopen("data.bin", "rb"); fread(newData, sizeof(float), 100, fp); fclose(fp);文本格式存储:
// 写入 for(int i=0; i<100; i++) fprintf(fp, "%f\n", data[i]); // 读取 for(int i=0; i<100 && !feof(fp); i++) fscanf(fp, "%f", &newData[i]);11. 现代硬件体系下的数组优化
11.1 SIMD指令优化
使用SSE/AVX指令集加速数组运算:
#include <immintrin.h> void add_arrays(float *a, float *b, float *c, int n) { for(int i=0; i<n; i+=8) { __m256 va = _mm256_load_ps(a+i); __m256 vb = _mm256_load_ps(b+i); __m256 vc = _mm256_add_ps(va, vb); _mm256_store_ps(c+i, vc); } }11.2 多线程并行处理
OpenMP并行化数组处理:
#include <omp.h> void scale_array(float *arr, float factor, int n) { #pragma omp parallel for for(int i=0; i<n; i++) { arr[i] *= factor; } }11.3 GPU加速方案
使用CUDA进行数组运算:
__global__ void addKernel(float *a, float *b, float *c, int n) { int i = blockIdx.x * blockDim.x + threadIdx.x; if(i < n) c[i] = a[i] + b[i]; } void addArrays(float *a, float *b, float *c, int n) { float *d_a, *d_b, *d_c; cudaMalloc(&d_a, n*sizeof(float)); cudaMalloc(&d_b, n*sizeof(float)); cudaMalloc(&d_c, n*sizeof(float)); cudaMemcpy(d_a, a, n*sizeof(float), cudaMemcpyHostToDevice); cudaMemcpy(d_b, b, n*sizeof(float), cudaMemcpyHostToDevice); addKernel<<<(n+255)/256, 256>>>(d_a, d_b, d_c, n); cudaMemcpy(c, d_c, n*sizeof(float), cudaMemcpyDeviceToHost); cudaFree(d_a); cudaFree(d_b); cudaFree(d_c); }12. 安全编程与防御性设计
12.1 数组边界检查
安全访问模式:
#define ARRAY_ACCESS(arr, idx, size) \ ((idx) >= 0 && (idx) < (size) ? (arr)[(idx)] : (error_handler(),0)) int safe_access(int *arr, int idx, int size) { if(idx < 0 || idx >= size) { handle_error(); return 0; } return arr[idx]; }12.2 缓冲区溢出防护
安全字符串处理:
// 不安全 char buf[10]; strcpy(buf, user_input); // 安全替代 strncpy(buf, user_input, sizeof(buf)-1); buf[sizeof(buf)-1] = '\0'; // 更安全的方案 snprintf(buf, sizeof(buf), "%s", user_input);12.3 防御性编程实践
- 输入验证:
void process_array(int *arr, int size) { assert(arr != NULL); assert(size > 0 && size <= MAX_SIZE); // ... }- 资源清理:
int *arr = malloc(size * sizeof(int)); if(!arr) { perror("malloc failed"); exit(EXIT_FAILURE); } // 使用... free(arr); arr = NULL; // 防止悬空指针- 错误恢复:
int save_data(float *data, int size) { FILE *fp = fopen("data.bin", "wb"); if(!fp) return -1; if(fwrite(data, sizeof(float), size, fp) != size) { fclose(fp); remove("data.bin"); return -2; } fclose(fp); return 0; }13. 调试与性能分析技巧
13.1 数组调试方法
GDB调试数组示例:
gdb ./your_program (gdb) break 42 # 在数组操作处设断点 (gdb) print *arr@10 # 查看前10个元素 (gdb) watch arr[5] # 监视特定元素变化 (gdb) x/20xw arr # 以16进制查看20个字13.2 Valgrind内存检查
检测数组越界和内存泄漏:
valgrind --tool=memcheck --leak-check=full ./your_program13.3 性能分析工具
使用perf分析数组访问模式:
perf stat -e cache-misses,cache-references ./your_program perf record ./your_program perf report13.4 可视化分析
生成火焰图定位热点:
perf record -g ./your_program perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg14. 跨平台开发注意事项
14.1 字节序问题
处理网络传输的数组数据:
uint32_t normalize_endian(uint32_t value) { union { uint32_t i; char c[4]; } u = {0x01020304}; if(u.c[0] == 0x01) { // 大端 return ((value >> 24) & 0xff) | ((value >> 8) & 0xff00) | ((value << 8) & 0xff0000) | ((value << 24) & 0xff000000); } return value; // 小端无需转换 }14.2 内存对齐差异
可移植的对齐分配:
void *aligned_alloc(size_t alignment, size_t size) { #ifdef _WIN32 return _aligned_malloc(size, alignment); #else void *ptr = NULL; posix_memalign(&ptr, alignment, size); return ptr; #endif } void aligned_free(void *ptr) { #ifdef _WIN32 _aligned_free(ptr); #else free(ptr); #endif }14.3 编译器扩展处理
处理不同编译器的数组扩展:
#ifdef __GNUC__ #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) #else // 其他编译器的实现 #endif15. 测试驱动开发实践
15.1 单元测试框架
使用Unity测试数组函数:
#include "unity.h" void test_array_sum(void) { int arr[] = {1, 2, 3, 4, 5}; TEST_ASSERT_EQUAL(15, array_sum(arr, 5)); } void test_array_reverse(void) { int arr[] = {1, 2, 3, 4, 5}; int expected[] = {5, 4, 3, 2, 1}; array_reverse(arr, 5); TEST_ASSERT_EQUAL_INT_ARRAY(expected, arr, 5); } int main() { UNITY_BEGIN(); RUN_TEST(test_array_sum); RUN_TEST(test_array_reverse); return UNITY_END(); }15.2 边界测试案例
典型边界测试场景:
- 空数组
- 单元素数组
- 已排序数组
- 逆序数组
- 全相同元素数组
- 随机大数组
15.3 性能测试方法
基准测试框架示例:
#include <time.h> void benchmark_array_sort() { const int size = 1000000; int *arr = generate_random_array(size); clock_t start = clock(); sort_array(arr, size); clock_t end = clock(); double elapsed = (double)(end - start) / CLOCKS_PER_SEC; printf("Sorting %d elements took %.3f seconds\n", size, elapsed); free(arr); }16. 工程实践中的数组应用
16.1 配置管理系统
使用数组存储配置参数:
#define MAX_CONFIG 100 struct config_item { char key[32]; char value[64]; } configs[MAX_CONFIG]; int load_config(const char *filename) { FILE *fp = fopen(filename, "r"); if(!fp) return -1; int count = 0; while(count < MAX_CONFIG && fscanf(fp, "%31[^=]=%63s\n", configs[count].key, configs[count].value) == 2) { count++; } fclose(fp); return count; }16.2 环形缓冲区实现
高效循环队列:
typedef struct { int *buffer; int capacity; int head; int tail; int count; } ring_buffer; void rb_init(ring_buffer *rb, int capacity) { rb->buffer = malloc(capacity * sizeof(int)); rb->capacity = capacity; rb->head = rb->tail = rb->count = 0; } int rb_push(ring_buffer *rb, int value) { if(rb->count >= rb->capacity) return -1; rb->buffer[rb->tail] = value; rb->tail = (rb->tail + 1) % rb->capacity; rb->count++; return 0; } int rb_pop(ring_buffer *rb) { if(rb->count <= 0) return -1; int value = rb->buffer[rb->head]; rb->head = (rb->head + 1) % rb->capacity; rb->count--; return value; }16.3 对象池模式
使用数组实现对象池:
#define POOL_SIZE 100 typedef struct { int id; // 其他成员... } object; object pool[POOL_SIZE]; int free_list[POOL_SIZE]; int free_top = 0; void pool_init() { for(int i=0; i<POOL_SIZE; i++) free_list[i] = POOL_SIZE-1 - i; free_top = POOL_SIZE-1; } object *pool_alloc() { if(free_top < 0) return NULL; int idx = free_list[free_top--]; return &pool[idx]; } void pool_free(object *obj) { int idx = obj - pool; if(idx >=0 && idx < POOL_SIZE) free_list[++free_top] = idx; }17. 从数组到更高级数据结构
17.1 动态数组实现
类似C++ vector的实现:
typedef struct { int *data; int size; int capacity; } dynamic_array; void da_init(dynamic_array *da, int cap) { da->data = malloc(cap * sizeof(int)); da->size = 0; da->capacity = cap; } void da_push_back(dynamic_array *da, int val) { if(da->size >= da->capacity) { da->capacity *= 2; da->data = realloc(da->data, da->capacity * sizeof(int)); } da->data[da->size++] = val; } void da_free(dynamic_array *da) { free(da->data); da->data = NULL; da->size = da->capacity = 0; }17.2 哈希表基础实现
使用数组+链表:
#define TABLE_SIZE 100 typedef struct node { char *key; int value; struct node *next; } node; node *hash_table[TABLE_SIZE]; unsigned int hash(const char *key) { unsigned int val = 0; while(*key) val = val * 31 + *key++; return val % TABLE_SIZE; } void hash_insert(const char *key, int value) { unsigned int idx = hash(key); node *n = malloc(sizeof(node)); n->key = strdup(key); n->value = value; n->next = hash_table[idx]; hash_table[idx] = n; } int hash_find(const char *key) { unsigned int idx = hash(key); for(node *n = hash_table[idx]; n; n = n->next) { if(strcmp(n->key, key) == 0) return n->value; } return -1; }17.3 优先队列实现
基于数组的堆:
typedef struct { int *data; int size; int capacity; } priority_queue; void pq_init(priority_queue *pq, int cap) { pq->data = malloc((cap+1) * sizeof(int)); // 索引从1开始 pq->size = 0; pq->capacity = cap; } void pq_swap(priority_queue *pq, int i, int j) { int tmp = pq->data[i]; pq->data[i] = pq->data[j]; pq->data[j] = tmp; } void pq_push(priority_queue *pq, int val) { if(pq->size >= pq->capacity) return; pq->data[++pq->size] = val; for(int i = pq->size; i > 1 && pq->data[i] < pq->data[i/2]; i /= 2) pq_swap(pq, i, i/2); } int pq_pop(priority_queue *pq) { if(pq->size <= 0) return -1; int min = pq->data[1]; pq->data[1] = pq->data[pq->size--]; for(int i = 1, child; i*2 <= pq->size; i = child) { child = i*2; if(child != pq->size && pq->data[child+1] < pq->data[child]) child++; if(pq->data[child] < pq->data[i]) pq_swap(pq, i, child); else break; } return min; }18. 嵌入式系统中的特殊考量
18.1 内存受限环境优化
- 使用位域压缩数据:
struct { unsigned int flag1 : 1; unsigned int flag2 : 1; unsigned int value : 6; } packed_data[100];- 共享内存区域:
union { uint8_t bytes[64]; uint32_t words[16]; float floats[16]; } shared_mem;18.2 寄存器映射技术
访问硬件寄存器:
#define GPIO_BASE 0x40020000 typedef struct { volatile uint32_t MODER; volatile uint32_t OTYPER; // 其他寄存器... } GPIO_TypeDef; #define GPIOA ((GPIO_TypeDef *)GPIO_BASE) void gpio_init() { GPIOA->MODER = 0xAB00; // 配置模式寄存器 GPIOA->OTYPER = 0x00; // 推挽输出 }18.3 静态分配策略
避免动态内存分配:
// 全局静态池 #define MAX_TASKS 10 static struct task task_pool[MAX_TASKS]; static int free_tasks[MAX_TASKS]; static int free_top = MAX_TASKS-1; // 初始化时填充空闲列表 void init_task_pool() { for(int i=0; i<MAX_TASKS; i++) free_tasks[i] = MAX_TASKS-1 - i; } struct task *alloc_task() { if(free_top < 0) return NULL; return &task_pool[free_tasks[free_top--]]; } void free_task(struct task *t) { int idx = t - task_pool; if(idx >=0 && idx < MAX_TASKS) free_tasks[++free_top] = idx; }19. 代码质量与可维护性
19.1 防御性编程实践
数组操作的健壮性检查:
int safe_array_access(int *arr, size_t size, size_t idx) { if(!arr || idx >= size) { log_error("Invalid array access"); return 0; // 或调用错误处理函数 } return arr[idx]; }19.2 文档注释规范
Doxygen风格注释示例:
/** * @brief 在有序数组中二分查找 * @param arr 已排序的数组 * @param size 数组大小 * @param target 查找目标值 * @return 目标值索引,未找到返回-1 * @note 数组必须已按升序排序 */ int binary_search(const int *arr, size_t size, int target) { // 实现... }19.3 单元测试覆盖
测试驱动开发示例:
void test_binary_search() { int arr[] = {1, 3, 5, 7, 9}; TEST_ASSERT_EQUAL(0, binary_search(arr, 5, 1)); TEST_ASSERT_EQUAL(2, binary_search(arr, 5, 5)); TEST_ASSERT_EQUAL(4, binary_search(arr, 5, 9)); TEST_ASSERT_EQUAL(-1, binary_search(arr, 5, 0)); TEST_ASSERT_EQUAL(-1, binary_search(arr, 5, 10)); TEST_ASSERT_EQUAL(-1, binary_search(NULL, 5, 1)); }20. 未来发展与替代方案
20.1 C++容器对比
C++标准库提供的替代方案:
std::array:固定大小数组包装器std::vector:动态数组std::valarray:数值计算专用数组
20.2 其他语言数组特性
现代语言的数组改进:
- Python列表:动态类型、自动扩容
- Java ArrayList:类型安全、丰富API
- Rust Vec:所有权模型保障安全
20.3 自定义智能数组
带边界检查的包装器:
typedef struct { int *data; size_t size; } safe_array; safe_array sa_create(size_t size) { safe_array sa; sa.data = malloc(size * sizeof(int)); sa.size = sa.data ? size : 0; return sa; } int sa_get(safe_array *sa, size_t idx) { if(!sa || !sa->data || idx >= sa->size) { handle_error(); return 0; } return sa->data[idx]; } void sa_free(safe_array *sa) { if(sa) { free(sa