数组基本概念

数组就像一排连续的储物柜,每个柜子大小相同,按顺序排列。

数组具有以下特点:

  • 数组是相同类型元素的集合
  • 所有元素在内存中连续存储
  • 每个元素可以通过索引(下标)来访问
  • 数组长度在创建时就固定,不能改变
// 数组的直观比喻
int locker[5]; // 5个连续的整数”储物柜”
// 索引:0 1 2 3 4
// 值: ? ? ? ? ? (初始值不确定)

数组声明与初始化

声明数组

声明数组需要指定:元素类型 + 数组名称 + 数组大小

// 声明一个包含5个整数的数组
int numbers[5];

// 声明一个包含10个浮点数的数组
float temperatures[10];

// 声明一个包含20个字符的数组
char letters[20];

初始化数组

可以在声明数组的同时给它赋初始值:

// 完全初始化
int primes[5] = {2, 3, 5, 7, 11};

// 部分初始化(剩余元素自动设为0)
int scores[5] = {95, 87}; // [95, 87, 0, 0, 0]

// 自动确定数组大小
int days[] = {31, 28, 31, 30}; // 大小为4

注意: 数组大小必须是整数常量,不能是变量(除非使用C99的变长数组)

访问数组元素

使用索引操作符 [ ] 来访问数组元素:

int numbers[5] = {10, 20, 30, 40, 50};

// 访问第一个元素(索引0)
int first = numbers[0]; // first = 10

// 修改第三个元素(索引2)
numbers[2] = 300; // 数组变为 [10, 20, 300, 40, 50]

// 使用变量作为索引
int index = 4;
int last = numbers[index]; // last = 50

重要警告: C语言不会检查数组索引是否越界!访问超出数组范围的元素会导致未定义行为(程序崩溃、数据损坏等)

数组内存示意图

数组内存布局

数组元素在内存中连续存储,每个元素大小相同

数组遍历技巧

遍历数组通常使用for循环

// 定义一个数组
int values[5] = {5, 10, 15, 20, 25};

// 使用for循环遍历
for(int i = 0; i < 5; i++) {
  printf(“values[%d] = %d\n”, i, values[i]);
}

// 输出:
// values[0] = 5
// values[1] = 10
// … 以此类推

计算数组长度

C语言没有内置的数组长度函数,但可以通过sizeof运算符来计算:

int arr[] = {1, 2, 3, 4, 5};

// 计算数组长度
int length = sizeof(arr) / sizeof(arr[0]);
// sizeof(arr) → 整个数组的字节大小
// sizeof(arr[0]) → 一个元素的字节大小
// 两者相除 → 元素个数

printf(“数组长度: %d”, length); // 输出:数组长度: 5

多维数组

多维数组(尤其是二维数组)可以看作是”数组的数组”:

// 声明一个3行4列的整数矩阵
int matrix[3][4];

// 初始化二维数组
int grid[2][3] = {
  {1, 2, 3}, // 第0行
  {4, 5, 6} // 第1行
};

// 访问元素:grid[行][列]
int element = grid[1][2]; // element = 6

二维数组内存布局

二维数组内存布局

二维数组在内存中仍然是一维连续存储的

遍历多维数组

// 遍历二维数组
for(int i = 0; i < 2; i++) { // 行索引
  for(int j = 0; j < 3; j++) { // 列索引
    printf(“grid[%d][%d] = %d\n”, i, j, grid[i][j]);
  }
}

数组与指针

在C语言中,数组名实际上是一个指向数组首元素的指针

int arr[3] = {10, 20, 30};

int *ptr = arr; // ptr指向arr[0]

// 以下访问方式等价
printf(“%d\n”, arr[0]); // 10
printf(“%d\n”, *arr); // 10
printf(“%d\n”, *(arr+1)); // 20
printf(“%d\n”, ptr[1]); // 20

重要区别: 虽然数组名可以当作指针使用,但它不是一个变量指针,不能修改它指向的地址(例如不能做 arr++

数组指针运算

int nums[5] = {5, 10, 15, 20, 25};
int *p = nums;

printf(“%d\n”, *p); // 5
printf(“%d\n”, *(p+2)); // 15

p++; // 指针移动到下一个元素
printf(“%d\n”, *p); // 10

字符数组与字符串

C语言中没有专门的字符串类型,而是使用字符数组来表示字符串:

// 字符数组表示字符串
char name[20] = “Alice”; // 实际存储:’A’,’l’,’i’,’c’,’e’,’\0′

// 初始化字符数组
char greeting[] = “Hello”; // 自动包含结束符’\0′

// 手动创建字符串
char message[10];
message[0] = ‘H’;
message[1] = ‘i’;
message[2] = ‘\0’; // 必须有结束符!

字符串结束符: C语言字符串以空字符 '\0' 结尾,这是字符串结束的标志

字符串操作函数

使用 string.h 提供的函数处理字符串:

#include <string.h>

char str1[20] = “Hello”;
char str2[] = “World”;

// 获取字符串长度
int len = strlen(str1); // len = 5

// 连接字符串
strcat(str1, ” “);
strcat(str1, str2); // str1 = “Hello World”

// 复制字符串
char copy[20];
strcpy(copy, str1); // copy = “Hello World”

// 比较字符串
if(strcmp(str1, str2) == 0) {
  printf(“字符串相同”);
}