在 C++ 中循环数组时访问结构 属性
Access to struct property while looping array in C++
我在遍历结构数组时遇到问题。
我有这个结构:
struct sensor
{
float data = 0;
bool status = false;
Idx idx; //enum
SensorType type; //enum
};
它包含一些适用于我的 arduino 的传感器。
所以为了发送我从他们那里收到的数据,我想在循环中使用传感器阵列。
这是我的数组定义:
sensor sensors[] = {light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut};
最后,我想遍历这个数组并调用一些方法,但是当我尝试按索引访问任何传感器时,我得到所有属性的零值。
for (unsigned int i = 0; i < sizeof(sensors) / sizeof(sensor); i++)
{
Serial.print("type:");
Serial.print(sensors[i].type);
Serial.print(" sens.idx:");
Serial.print(sensors[i].idx);
Serial.print(" sens.data:");
Serial.print(sensors[i].data);
Serial.print(" sens.status:");
Serial.print(sensors[i].status);
Serial.println();
}
在这个循环中,我得到如下输出:
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
但是,当我像这样直接访问我的任何结构时:
Serial.print("type:");
Serial.print(pressure.type);
Serial.print(" pressure.idx:");
Serial.print(pressure.idx);
Serial.print(" pressure.data:");
Serial.print(pressure.data);
Serial.print(" sens.status:");
Serial.print(pressure.status);
Serial.println();
我得到:
type:3 pressure.idx:13 pressure.data:0.00 sens.status:1
创建结构数组时:
sensor sensors[] = {light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut};
这会为您用来制作列表的每个结构创建一个副本。您要么必须使用指针数组:
sensor* sensors[] = {&light, &pressure, &pressureHpa, &temperature, &humidity, &temperatureOut, &humidityOut};
或者您必须创建自己的 class,存储对它们的引用:
class SensorArray {
sensor** arr = nullptr;
size_t count = 0;
public:
size_t size() const {
return count;
}
// Default-construct it
SensorArray() = default;
// Make a copy of the SensorArray
SensorArray(SensorArray const& source)
: arr(new sensor*[source.size()])
, count(source.size())
{
std::copy_n(source.arr, source.count, arr);
}
// Move-construct SensorArray
SensorArray(SensorArray&& source)
: arr(source.arr)
, count(source.count)
{
source.arr = nullptr;
source.count = 0;
}
template<class T...>
SensorArray(T&... sensors)
: arr(new sensor*[] { &sensors... }) // Initialize arr
, count(sizeof...(sensors)) // Initialize count
{} // Constructor is empty because we already initialized stuff
SensorArray& operator=(SensorArray const& source) {
if(this == &source) return *this;
SensorArray s = source;
swap(s);
return *this;
}
// Copy-and-swap idiom
// This automatically handles the case of self-assignment
SensorArray& operator=(SensorArray&& source) {
SensorArray s = std::move(source);
swap(s);
return *this;
}
sensor& operator[](int index) const {
return *arr[index];
}
~SensorArray() {
delete[] arr;
}
void swap(SensorArray& other) {
std::swap(arr, other.arr);
std::swap(count, other.count);
}
};
此 class 将按您的代码中的预期工作,因为它会为每个传感器存储一个 reference,而不是一个副本:
SensorArray sensors { light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut };
// sensors will update correctly
for (unsigned int i = 0; i < sensors.size(); i++)
{
Serial.print("type:");
Serial.print(sensors[i].type);
Serial.print(" sens.idx:");
Serial.print(sensors[i].idx);
Serial.print(" sens.data:");
Serial.print(sensors[i].data);
Serial.print(" sens.status:");
Serial.print(sensors[i].status);
Serial.println();
}
light
已定义并保留其默认值。
sensor sensors[] = {light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut};
将 light
复制到 sensors[0]
。这意味着 sensors[0]
包含与 light
相同的数据,但与 light
不同。稍后当代码为 light
赋值时,sensors[0]
的副本保持不变。
选项 1
舍弃light
和朋友。添加命名传感器的枚举类型
enum sensor_names
{
LIGHT, // will be 0
PRESSURE, //will be 1
...
NR_SENSORS // must be last. Used to size the array and for loop terminators
};
并使sensors
成为一个正确大小的简单数组
sensor sensors[NR_SENSORS];
如果可用,请随意使用 std::array
and the smarter enum
s of modern C++。我不了解 Arduino 可用和不可用的内容,因此我坚持使用基本的 C 样式数组和 enum
s。如果您有更好的工具,请使用它们。
然后访问 light
作为 sensors[LIGHT];
选项 2
使 sensors
存储指针并相应地更改访问。
sensor * sensors[] = {&light, &pressure, .... };
我更喜欢第一个选项。没有重复,并且将项目放置在数组中错误位置的可能性较低。
我在遍历结构数组时遇到问题。
我有这个结构:
struct sensor
{
float data = 0;
bool status = false;
Idx idx; //enum
SensorType type; //enum
};
它包含一些适用于我的 arduino 的传感器。
所以为了发送我从他们那里收到的数据,我想在循环中使用传感器阵列。
这是我的数组定义:
sensor sensors[] = {light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut};
最后,我想遍历这个数组并调用一些方法,但是当我尝试按索引访问任何传感器时,我得到所有属性的零值。
for (unsigned int i = 0; i < sizeof(sensors) / sizeof(sensor); i++)
{
Serial.print("type:");
Serial.print(sensors[i].type);
Serial.print(" sens.idx:");
Serial.print(sensors[i].idx);
Serial.print(" sens.data:");
Serial.print(sensors[i].data);
Serial.print(" sens.status:");
Serial.print(sensors[i].status);
Serial.println();
}
在这个循环中,我得到如下输出:
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
type:0 sens.idx:0 sens.data:0.00 sens.status:0
但是,当我像这样直接访问我的任何结构时:
Serial.print("type:");
Serial.print(pressure.type);
Serial.print(" pressure.idx:");
Serial.print(pressure.idx);
Serial.print(" pressure.data:");
Serial.print(pressure.data);
Serial.print(" sens.status:");
Serial.print(pressure.status);
Serial.println();
我得到:
type:3 pressure.idx:13 pressure.data:0.00 sens.status:1
创建结构数组时:
sensor sensors[] = {light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut};
这会为您用来制作列表的每个结构创建一个副本。您要么必须使用指针数组:
sensor* sensors[] = {&light, &pressure, &pressureHpa, &temperature, &humidity, &temperatureOut, &humidityOut};
或者您必须创建自己的 class,存储对它们的引用:
class SensorArray {
sensor** arr = nullptr;
size_t count = 0;
public:
size_t size() const {
return count;
}
// Default-construct it
SensorArray() = default;
// Make a copy of the SensorArray
SensorArray(SensorArray const& source)
: arr(new sensor*[source.size()])
, count(source.size())
{
std::copy_n(source.arr, source.count, arr);
}
// Move-construct SensorArray
SensorArray(SensorArray&& source)
: arr(source.arr)
, count(source.count)
{
source.arr = nullptr;
source.count = 0;
}
template<class T...>
SensorArray(T&... sensors)
: arr(new sensor*[] { &sensors... }) // Initialize arr
, count(sizeof...(sensors)) // Initialize count
{} // Constructor is empty because we already initialized stuff
SensorArray& operator=(SensorArray const& source) {
if(this == &source) return *this;
SensorArray s = source;
swap(s);
return *this;
}
// Copy-and-swap idiom
// This automatically handles the case of self-assignment
SensorArray& operator=(SensorArray&& source) {
SensorArray s = std::move(source);
swap(s);
return *this;
}
sensor& operator[](int index) const {
return *arr[index];
}
~SensorArray() {
delete[] arr;
}
void swap(SensorArray& other) {
std::swap(arr, other.arr);
std::swap(count, other.count);
}
};
此 class 将按您的代码中的预期工作,因为它会为每个传感器存储一个 reference,而不是一个副本:
SensorArray sensors { light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut };
// sensors will update correctly
for (unsigned int i = 0; i < sensors.size(); i++)
{
Serial.print("type:");
Serial.print(sensors[i].type);
Serial.print(" sens.idx:");
Serial.print(sensors[i].idx);
Serial.print(" sens.data:");
Serial.print(sensors[i].data);
Serial.print(" sens.status:");
Serial.print(sensors[i].status);
Serial.println();
}
light
已定义并保留其默认值。
sensor sensors[] = {light, pressure, pressureHpa, temperature, humidity, temperatureOut, humidityOut};
将 light
复制到 sensors[0]
。这意味着 sensors[0]
包含与 light
相同的数据,但与 light
不同。稍后当代码为 light
赋值时,sensors[0]
的副本保持不变。
选项 1
舍弃light
和朋友。添加命名传感器的枚举类型
enum sensor_names
{
LIGHT, // will be 0
PRESSURE, //will be 1
...
NR_SENSORS // must be last. Used to size the array and for loop terminators
};
并使sensors
成为一个正确大小的简单数组
sensor sensors[NR_SENSORS];
如果可用,请随意使用 std::array
and the smarter enum
s of modern C++。我不了解 Arduino 可用和不可用的内容,因此我坚持使用基本的 C 样式数组和 enum
s。如果您有更好的工具,请使用它们。
然后访问 light
作为 sensors[LIGHT];
选项 2
使 sensors
存储指针并相应地更改访问。
sensor * sensors[] = {&light, &pressure, .... };
我更喜欢第一个选项。没有重复,并且将项目放置在数组中错误位置的可能性较低。