循环二次迭代时Character数组为空(Arduino+C++)问题求助
问题分析与修复方案
问题现象
在Arduino平台上学习C++开发,无法使用STL库。代码中Arduino主循环持续调用refresh函数,首次接收数据并添加到连接数组时正常,但建立第二个连接后,第一个连接的data属性变为空值,相关日志如下:
15:42:53.153 -> Board setup complete 15:42:53.926 -> Received Short Range Data : Authorized Short Range Communicati 15:42:53.991 -> Data being returned from shortRangeListener::listen : Authorized Short Range Communicati 15:42:54.089 -> New Connection Instantiated : <Data:Authorized Short Range Communicati; LastEstablishedConnectionTime:898> 15:42:54.221 -> Short Range Connection received. Manging short range connections. 15:42:54.286 -> Hub::manageConnections invoked. 15:42:54.318 -> Connection established for <Data:Authorized Short Range Communicati; LastEstablishedConnectionTime:898> 15:42:54.418 -> Connections after adding latest 15:42:54.452 -> <Data:Authorized Short Range Communicati; LastEstablishedConnectionTime:898> 15:42:55.245 -> Received Short Range Data : Authorized Short Range Communicati 15:42:55.311 -> Data being returned from shortRangeListener::listen : Authorized Short Range Communicati 15:42:55.409 -> New Connection Instantiated : <Data:Authorized Short Range Communicati; LastEstablishedConnectionTime:2217> 15:42:55.539 -> Short Range Connection received. Manging short range connections. 15:42:55.605 -> Hub::manageConnections invoked. 15:42:55.637 -> Current Connections: 15:42:55.637 -> <Data:; LastEstablishedConnectionTime:898>
核心问题
1. RH_ASK接收函数调用错误,导致字符串处理异常
ShortRangeListener::listen方法中对RH_ASK::recv的调用不符合API规范:RH_ASK的recv函数第二个参数是引用类型,用于返回实际接收的字节数,而非直接传入缓冲区大小。错误的调用方式会导致字符串终止符处理不当,strlen计算出错误长度,进而new的内存空间不足,strcpy时发生越界,破坏堆内存结构,最终导致之前分配的data内存被篡改。
2. Connection类未实现深拷贝,存在浅拷贝隐患
Connection类包含char*类型的data成员,但未自定义拷贝构造函数和赋值运算符。当执行connections[(*numberOfConnections)] = *connection;这种对象赋值操作时,默认的浅拷贝只会复制指针值,而非指针指向的内存内容。多个Connection对象会共享同一块内存,一旦内存被修改或释放,所有关联对象的data都会失效。
3. 内存泄漏问题
getConnection方法中new创建的Connection对象,在manageConnections中赋值后未被释放,长期运行会耗尽Arduino的有限内存。
修复代码
修复ShortRangeListener::listen的recv调用
char *ShortRangeListener::listen() { uint16_t recvLen = sizeof(buf); // buf为类成员缓冲区,需提前定义(如char buf[64];) if (driver.recv(buf, recvLen)) { // 根据实际接收长度添加终止符,确保字符串有效 if (recvLen < sizeof(buf)) { buf[recvLen] = '\0'; } else { // 缓冲区满时,手动覆盖最后一个字节添加终止符 buf[sizeof(buf) - 1] = '\0'; } Serial.print("Received Short Range Data : "); Serial.println((char *)buf); size_t dataLen = strlen((char *)buf); char *data = new char[dataLen + 1]; strcpy(data, (char *)buf); return data; } return nullptr; }
为Connection类添加深拷贝与析构函数
// Connection类头文件中需声明以下函数 class Connection { public: char* data; long lastEstablishedConnectionTime; Connection(); // 拷贝构造函数 Connection(const Connection& other); // 赋值运算符 Connection& operator=(const Connection& other); // 析构函数 ~Connection(); void print(bool newLine = true); }; // 实现部分 Connection::Connection(const Connection& other) { // 深拷贝data内存 if (other.data != nullptr) { size_t len = strlen(other.data); data = new char[len + 1]; strcpy(data, other.data); } else { data = nullptr; } lastEstablishedConnectionTime = other.lastEstablishedConnectionTime; } Connection& Connection::operator=(const Connection& other) { if (this == &other) { return *this; // 防止自赋值 } // 释放当前对象的旧内存 if (data != nullptr) { delete[] data; data = nullptr; } // 深拷贝新内存 if (other.data != nullptr) { size_t len = strlen(other.data); data = new char[len + 1]; strcpy(data, other.data); } lastEstablishedConnectionTime = other.lastEstablishedConnectionTime; return *this; } Connection::~Connection() { // 释放data内存,避免泄漏 if (data != nullptr) { delete[] data; data = nullptr; } }
修复Hub::manageConnections的内存泄漏
void Hub::manageConnections(Connection *connection, Connection *connections, int *numberOfConnections, long currentOrchestrationStartTime) { Serial.println("Hub::manageConnections invoked."); if (*numberOfConnections > 0) { Serial.println("Current Connections:"); for (int i = 0; i < (*numberOfConnections); i++) { connections[i].print(); } } if ((*numberOfConnections) >= maxConnections) { Serial.print("Max connections established. Connection "); Serial.print(connection->data); Serial.println(" cannot be added."); // 释放未使用的connection对象 delete connection; return; } connections[(*numberOfConnections)] = *connection; (*numberOfConnections)++; Serial.print("Connection established for "); connection->print(); Serial.println("Connections after adding latest "); for (int i = 0; i < (*numberOfConnections); i++) { connections[i].print(); } // 释放堆上的connection对象,避免内存泄漏 delete connection; }
修复说明
- 修正
recv调用后,能正确获取实际接收长度,确保字符串终止符位置正确,避免堆内存越界破坏。 - 添加深拷贝构造函数和赋值运算符后,每个
Connection对象拥有独立的data内存,互不干扰,解决了旧连接data被篡改的问题。 - 添加析构函数和释放
connection对象的代码,解决了内存泄漏问题,延长程序稳定运行时间。
内容的提问来源于stack exchange,提问作者user23370524
相关产品推荐
相关产品推荐

