You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环二次迭代时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;
}

修复说明

  1. 修正recv调用后,能正确获取实际接收长度,确保字符串终止符位置正确,避免堆内存越界破坏。
  2. 添加深拷贝构造函数和赋值运算符后,每个Connection对象拥有独立的data内存,互不干扰,解决了旧连接data被篡改的问题。
  3. 添加析构函数和释放connection对象的代码,解决了内存泄漏问题,延长程序稳定运行时间。

内容的提问来源于stack exchange,提问作者user23370524

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 16:57:34