Skip to content

Arduino - 数组

数组是一种基本数据结构,用于存储相同数据类型的固定大小、顺序集合。可以将其视为一排带有标签的盒子,每个盒子都存放着相同类型的值(例如,都是整数)。

要访问数组中的特定元素,您需要使用其名称和索引。索引(或下标)指定了元素的位置。

  • 零基索引:在C++(Arduino的编程语言)中,数组索引从0开始。第一个元素位于索引0,第二个位于索引1,依此类推。
  • 最后一个元素:最后一个元素的索引始终是arraySize - 1。

让我们可视化一个名为sensorReadings的int类型数组,其中包含5个元素:

Array name: sensorReadings
Index: [0] [1] [2] [3] [4]
+-----+-----+-----+-----+-----+
Value: | 452 | 455 | 450 | 458 | 454 |
+-----+-----+-----+-----+-----+
// 要访问值450,您可以使用:
sensorReadings[2]

在使用数组之前,必须先声明它,指定其类型、名称和大小。一种现代的最佳实践是使用const或constexpr变量来定义大小,以避免魔术数字并使代码更易于维护。

// 最佳实践:将大小定义为常量。
const int SENSOR_COUNT = 5;
// 声明一个包含5个元素的整数数组。
int sensorReadings[SENSOR_COUNT];

数组可以通过多种方式初始化。

示例1:使用初始化列表进行初始化

Section titled “示例1:使用初始化列表进行初始化”

最常见和简洁的方法是在声明中直接提供值。

// 编译器自动从列表中推断大小。
int ledPins[] = {2, 3, 4, 5, 6};
void setup() {
Serial.begin(9600);
Serial.println("Configuring LED pins...");
// 遍历数组的一种现代、安全方式:基于范围的for循环
for (int pin : ledPins) {
pinMode(pin, OUTPUT);
Serial.print("Pin ");
Serial.print(pin);
Serial.println(" configured as OUTPUT.");
}
}
void loop() {
// 本示例中为空
}

有时您需要用计算值初始化数组。for循环是实现此目的的完美选择。

const int NUM_VALUES = 10;
int squaredValues[NUM_VALUES];
void setup() {
Serial.begin(9600);
// 使用索引的平方(i*i)初始化数组
for (int i = 0; i < NUM_VALUES; ++i) {
squaredValues[i] = i * i;
}
Serial.println("Array Initialized. Contents:");
// 打印数组内容进行验证
for (int i = 0; i < NUM_VALUES; ++i) {
Serial.print("Index ");
Serial.print(i);
Serial.print(": ");
Serial.println(squaredValues[i]);
}
}
void loop() {
// 本示例中为空
}

示例3:计算传感器读数的平均值

Section titled “示例3:计算传感器读数的平均值”

此程序计算存储在数组中的一系列模拟传感器读数的平均值。它演示了迭代和常见的计算。

// 传感器读数数组
int sensorReadings[] = {87, 68, 94, 100, 83, 78, 85, 91, 76, 87};
// 一种健壮的计算数组大小的方法,它会随着数组的更改而调整
const int NUM_READINGS = sizeof(sensorReadings) / sizeof(sensorReadings[0]);
void setup() {
Serial.begin(9600);
long total = 0; // 使用'long'类型计算总和以避免大数组溢出
// 对数组内容求和
for (int i = 0; i < NUM_READINGS; ++i) {
total += sensorReadings[i];
}
// 将平均值计算为浮点数
float average = (float)total / NUM_READINGS;
Serial.print("Total of array elements: ");
Serial.println(total);
Serial.print("Number of readings: ");
Serial.println(NUM_READINGS);
Serial.print("Average reading: ");
Serial.println(average);
}
void loop() {
// 主循环为空,因为计算只执行一次。
}
Total of array elements: 849
Number of readings: 10
Average reading: 84.90
  • 越界错误:最常见的错误是尝试访问不存在的元素(例如,在5个元素的数组中访问myArray[5])。C++不会阻止这种情况!它会从相邻内存中读取或写入,导致难以追踪的不可预测的崩溃和错误。请始终警惕您的循环条件(< size,而不是<= size)。
  • 差一错误:与零基索引相关的经典错误。忘记最后一个元素在size - 1处通常会导致越界访问。
  • 使用sizeof计算数组长度:sizeof(array) / sizeof(array[0])模式是确定数组元素数量的标准、健壮方法。如果您从初始化列表中添加或删除元素,它会自动适应。
  • 使用基于范围的for循环:当您只需要读取数组中的每个元素时,for (int element : myArray)语法更简洁、更安全,因为它消除了越界错误的可能。
概念描述
多维数组数组可以有多个维度。例如,int table[3][4];创建了一个2D数组(一个网格或表格),有3行4列。这些对于表示网格、矩阵或游戏棋盘非常有用。
将数组传递给函数您可以将数组传递给函数对其进行操作。通常,您会传递数组本身(它充当指向第一个元素的指针)及其大小作为单独的参数,以防止函数内部的越界访问。
现代C++容器对于更高级的项目或在更强大的开发板(如ESP32)上,考虑使用C++标准库容器,如std::array或std::vector。std::array是一个固定大小的容器,内存占用与C风格数组相似,但具有更现代的接口。std::vector是一个动态数组,可以根据需要增长和收缩。