ESP32 Arduino开发:扫描WiFi网络后如何正确将SSID存入char*列表供外部使用
核心问题定位
- 栈临时变量生命周期失效:在for循环块内定义的
char temp_buffer[str_len]是栈上分配的局部临时变量,作用域仅覆盖单次循环迭代。每次循环执行完当前代码块,这块栈内存就会被编译器标记为可回收复用的空间,下一次循环会重复使用同一块栈地址做临时缓冲。这就是你观察到temp_buffer的指针地址在两个固定值间来回切换的根本原因:所有存在list_strings里的指针,最后都指向同一块被反复覆盖、甚至被函数其他栈数据占用的无效内存,读取时自然输出无意义的垃圾值。
你之前参考的char数组转换教程可以正常运行,是因为教程里的字符数组定义在全局作用域或者函数顶层作用域,不属于循环块内的临时栈变量,不会立刻被回收。 - 列表遍历越界:打印全局列表时的循环判断条件写为
i<=n,由于WiFi扫描返回的网络总数n对应的有效下标范围是0~n-1,i=n时已经读取了list_strings数组中未初始化的野指针,进一步放大了垃圾值的输出问题。 - 指针地址打印报错的原因:32位架构的ESP32上指针长度为4字节,直接强制转换为int类型会出现精度不匹配的编译报错,打印地址时直接转
uintptr_t类型即可兼容32位系统的指针长度。
可落地的解决方案
方案1:堆内存独立分配(适配变长SSID场景)
每个SSID单独从堆空间申请独立的内存块,不会受栈变量生命周期的限制。
修改循环内的存储逻辑为:
int str_len = WiFi.SSID(i).length() + 1; // 为每个SSID单独申请独立堆内存,申请的空间不会随循环退出自动回收 char* ssid_mem = (char*)malloc(str_len); WiFi.SSID(i).toCharArray(ssid_mem, str_len); list_strings[i] = ssid_mem;
注意:如果后续不再需要保留已存储的SSID数据,记得用
free(list_strings[i])释放对应内存,避免长期运行出现内存泄漏。
方案2:固定大小静态数组存储(ESP32开发最稳妥的无String方案)
WiFi协议本身规定SSID的最大长度为32字节,完全不需要动态计算长度申请空间。直接定义固定大小的全局二维字符数组,从根源上避免栈临时变量、动态内存的相关问题:
// 每个SSID预留33字节(32字节有效内容 + 1字节空终止符),最多存储10个网络 char list_strings[10][33];
循环内直接将SSID拷贝到对应数组位置,不需要额外临时缓冲区:
for (int i = 0; i < n; ++i) { WiFi.SSID(i).toCharArray(list_strings[i], sizeof(list_strings[i])); }
这种写法没有动态内存的开销,也不存在野指针问题,是嵌入式场景下存储短固定长度字符串的最优选择。
内容的提问来源于stack exchange,提问作者Lukas Petrikas
相关产品推荐
相关产品推荐

