C语言中,有一类数据结构,它可以存储一组相同类型的元素,并且可以通过索引访问这些元素,没错,这类数据结构就是数组。数组可以说是C语言中非常重要的数据结构之一了。使用数组可以是程序逻辑更加清晰,也更加具有可读性。
1 数组的声明和初始化
1)数组的声明
在C语言中,数组的声明方式如下:
type arrayName[arraySize];
- type:数组中元素的数据类型
- arrayName:数组的名字
- arraySize:数组的大小(即数组中可以存储的元素个数)
例如,声明一个包含5个LED端口的数组:
GPIO_TypeDef* LED_PortLists[5];
声明一个包含5个LED引脚的数组
uint16_t LED_PinLists[5];
2)数组的初始化
数组可以在声明的同时进行初始化:
GPIO_TypeDef* LED_PortLists[5] =
{
GPIOA,
GPIOA,
GPIOA,
GPIOA,
GPIOA,
};
uint16_t LED_PinLists[5] =
{
GPIO_Pin_10,
GPIO_Pin_11,
GPIO_Pin_12,
GPIO_Pin_13,
GPIO_Pin_14,
};
也可通过索引进行初始化,[index]中index为索引值。如:
GPIO_TypeDef* LED_PortLists[5] =
{
[0] = GPIOA,
[1] = GPIOA,
[2] = GPIOA,
[3] = GPIOA,
[4] = GPIOA,
};
uint16_t LED_PinLists[5] =
{
[LED_DEBUG] = GPIO_Pin_10,
[LED_FUN] = GPIO_Pin_11,
[LED_RUN] = GPIO_Pin_12,
[LED_TEMPEATATURE] = GPIO_Pin_13,
[LED_FAULT] = GPIO_Pin_14,
};
如果初始化的元素个数少于数组大小,未初始化的元素会被自动赋值为0:
GPIO_TypeDef* LED_PortLists[5] = {0}; // 等价于 {0, 0, 0, 0, 0}
也可以省略数组大小,让编译器自动计算:
GPIO_TypeDef* LED_PortLists[] = {GPIOA, GPIOA, GPIOA, GPIOA, GPIOA}; // 数组大小自动为5
2 数组元素的访问
数组元素可以通过索引访问,索引从0开始:
uint16_t LED_DEBUG_PIN = LED_PinLists[0]; //访问第一个元素
uint16_t LED_FUN_PIN = LED_PinLists[1]; //访问第一个元素
可以通过索引修改数组元素的值:
LED_PinLists[0] = GPIO_Pin_9; // 将第一个元素的值修改为GPIO_Pin_9
在没有引用数组类型前,我们前面是这样来操作LED灯的。
void LED_DebugSetOn(void)
{
GPIO_ResetBits(LED_DEBUG_PORT , LED_DEBUG_PIN); // 关闭
}
void LED_DebugSetOff(void)
{
GPIO_ResetBits(LED_DEBUG_PORT , LED_DEBUG_PIN); // 关闭
}
void LED_DebugSet(bool value)
{
if(value == false)
{
GPIO_ResetBits(LED_DEBUG_PORT , LED_DEBUG_PIN); // 关闭
}
else
{
GPIO_SetBits(LED_DEBUG_PORT, LED_DEBUG_PIN); // 点亮
}
}
void LED_Set(LED_t led,bool value)
{
switch (led)
{
case LED_DEBUG:
LED_DebugSet(value);
break;
default:
break;
}
}
在引用了数组类型后,代码就变成了这样:
void LED_Set(LED_t led,bool value)
{
if(value == false)
{
GPIO_ResetBits(LED_PortLists[led] , LED_PinLists[led] ); // 关闭
}
else
{
GPIO_SetBits(LED_PortLists[led] , LED_PinLists[led]); // 点亮
}
}
3 二维数组
二维数组类似于矩阵,可以用两个索引来访问元素。声明方式如下:
type arrayName[rows][columns];
- type:数组中元素的数据类型
- arrayName:数组的名字
- rows:数组中行数的大小
- columns:数组中列数的大小
例如,声明一个2行3列的二维数组:
uint16_t LED_PinMatrixs[2][3];
二维数组的初始化:
uint16_t LED_PinMatrixs[2][3] =
{
{GPIO_Pin_1, GPIO_Pin_2, GPIO_Pin_3},
{GPIO_Pin_4, GPIO_Pin_5, GPIO_Pin_6},
};
可以通过两个索引访问二维数组的元素:
uint16_t LED_PinValue = LED_PinMatrixs[1][2]; // 访问第一行第二列的元素,GPIO_Pin_2
LED_PinMatrixs[0][0] = GPIO_Pin_0; // 修改第一行第一列的元素
4 常见数组操作
1) 数组遍历
通过循环遍历数组的每个元素:
for (int i = 0; i < LED_NUM; i++)
{
LED_Set((LED_t)i,true); //LED灯全亮
}
2) 查找元素
遍历数组,查找特定元素的位置:
uint16_t LED_PinValue = GPIO_Pin_3;
int index = -1;
for (int i = 0; i < LED_NUM; i++)
{
if (LED_PinLists[i] == LED_PinValue)
{
index = i;
break;
}
}
if (index != -1)
{
printf("元素 %d 在数组中的位置是 %d\n", target, index);
}
else
{
printf("数组中没有找到元素 %d\n", target);
}
3) 元素移位
通过循环将数组中的元素依次向前移一位
uint16_t LED_PinValue = LED_PinLists[LED_NUM - 1];
for(int i = LED_NUM - 1;i > 0;i--)
{
LED_PinLists[i]=LED_PinLists[i-1];
}
LED_PinLists[0] = LED_PinValue;
4) 二维数组转换为一维数组
int rows = 2;
int columns = 3;
uint16_t LED_PinMatrixs[2][3] =
{
{GPIO_Pin_1, GPIO_Pin_2, GPIO_Pin_3},
{GPIO_Pin_4, GPIO_Pin_5, GPIO_Pin_6},
};
uint16_t LED_PinList[rows * columns];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
LED_PinList[i * columns + j] = LED_PinMatrixs[i][j];
}
}
5 数组名的本质
数组名的本质是指向该数组第一个元素的指针,关于指针,我们后面再讨论
6 使用数组的注意事项
1)在通过数组索引访问数组元素时,一定要注意数组的边界,即索引大小应小于数组元素的大小,5个数组元素,其索引值最大为4。
2)数组索引值从0开始计算。索引值应大于等于0,且小于数组元素的大小。