c中防止字符数组溢出
Prevent character array from overflowing in c
我正在使用 ESP-IDF 和 FreeRTOS 为 ESP32 设计固件。
我想将传感器的读数转换为字符数组并将其存储在非易失性存储中。获取新读数时,会将其添加到 char 数组的前面,将旧读数推到右侧。
我是这样操作数组的:
#define MAX_BYTES 100
char oldData[MAX_BYTES];
nvs_get_str( nvsHandle, MASS_STRING_STORE, newData, &required_size);
char newData[15];
sprintf(newData, "%2.2f", Totalmass);
strcat(newData, ",");
printf("new data: %s\n", newData);
printf("strlen oldData: %d\n", strlen(oldData));
printf("strlen newData: %d\n", strlen(newData));
printf("sizeof oldData: %d\n", sizeof(oldData));
printf("i starts from: %d\n", (sizeof(oldData)-strlen(newData2)-1));
for(int i = (sizeof(oldData)-strlen(newData) - 1); i >= 0; i--)
{
oldData [i + strlen( newData )] = oldData[i];
}
for(int i = 0; i < ( strlen(newData) ); i++)
{
oldData[i] = newData[i];
}
nvs_set_str(nvsHandle, MASS_STRING_STORE, oldData);
现在来谈谈我面临的问题:
一旦字符串长度超过 MAX_LENGTH,即 100,代码就会崩溃。
崩溃消息是:
"Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0)"
发生崩溃重置后,代码继续正常工作,直到再次崩溃。 oldData 的 Strlen 打印 104,并保持在 104(我猜最大值应该是 99?)。代码在任务的无限循环的一个完整循环完成后恰好崩溃。
有人可以指导我这里可能做错了什么吗?如果需要,我可以提供更多信息。
提前致谢!
编辑:
原来下面一行没有注释:
strcpy(NEWDATA, oldData);
其中 NEWDATA 是一个大小为 20 的数组,显然是溢出导致了上述问题,现已解决。
我目前面临的另一个问题是我当前阅读的副本被附加到数组的末尾。下面我附上了我的日志副本:
new data: 5.00,
strlen oldData: 105
strlen newData: 5
Final Data: 5.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5.00,
对于 100 的 MAX_LENGTH,我的数组大小为 105,并且根据我新阅读的长度保持在 100 以上。但是,我的代码没有崩溃。但是我最终数据的额外 5 长度始终是我得到的当前读数。
谁能帮我解决这个问题?
"Interrupt wdt timeout on CPU0" 非常清楚。你有一个看门狗超时重置。这反过来意味着您的代码太慢了,或者您没有从代码中的任何地方踢狗。
在嵌入式系统中使用 stdio.h 是一个很大的禁忌,因为它非常慢并且消耗资源。
另一个例子,如果优化不好或被禁用,for(int i = 0; i < ( strlen(newData) ); i++)
可能会给出非常慢的代码,应该用 size_t length = strlen(newData); for(int i=0; i<length; ...
替换
最后,如果是写入flash,驱动需要先擦除flash,这需要很长时间。
您正在将 newData 复制到 oldData 中。 strlen() returns newData 的长度 不包括 空终止符。因此,您生成的 char 数组可能未终止,导致 nvs_set_str() 调用执行不需要的操作,并花费足够的时间来触发 WDT。
此外,memcpy() 可能会加快您对 oldData 的逐字节移位。我说可能是因为我不确定 memcpy 在 in situ 替换上是否正常工作;你需要阅读相关文档。
非常感谢所有评论和回答,我会考虑所有意见以改进我的代码。
然而,事实证明我在我的代码中错误地取消了注释,其中我的最终数组被复制到一个较小的数组中。这就是为什么我的代码不断崩溃的原因。问题,至此已经解决。一旦我完成了我代码的其他功能的实现,我将在稍后讨论这段代码的时间消耗和优化。
谢谢大家!!
由于对 OP 的编辑,添加了第二个答案。
首先,最好显示工作代码。这段话表明这不会编译:
nvs_get_str( nvsHandle, MASS_STRING_STORE, newData, &required_size);
char newData[15];
关于您的问题:您的 printf() 输出让我怀疑您是否真的在处理字符串数据。如果不是,则不要使用 nvs_get_str(),因为它会在遇到空字符后停止读取 NVS。同样,如果您在非字符串数据上使用 strlen() 可能无法正常工作。
如果您正在存储和操作非字符串数据,请使用 nvs_get_blob() 来检索它,并在您的程序中使用内存函数来复制它。
我正在使用 ESP-IDF 和 FreeRTOS 为 ESP32 设计固件。 我想将传感器的读数转换为字符数组并将其存储在非易失性存储中。获取新读数时,会将其添加到 char 数组的前面,将旧读数推到右侧。
我是这样操作数组的:
#define MAX_BYTES 100
char oldData[MAX_BYTES];
nvs_get_str( nvsHandle, MASS_STRING_STORE, newData, &required_size);
char newData[15];
sprintf(newData, "%2.2f", Totalmass);
strcat(newData, ",");
printf("new data: %s\n", newData);
printf("strlen oldData: %d\n", strlen(oldData));
printf("strlen newData: %d\n", strlen(newData));
printf("sizeof oldData: %d\n", sizeof(oldData));
printf("i starts from: %d\n", (sizeof(oldData)-strlen(newData2)-1));
for(int i = (sizeof(oldData)-strlen(newData) - 1); i >= 0; i--)
{
oldData [i + strlen( newData )] = oldData[i];
}
for(int i = 0; i < ( strlen(newData) ); i++)
{
oldData[i] = newData[i];
}
nvs_set_str(nvsHandle, MASS_STRING_STORE, oldData);
现在来谈谈我面临的问题:
一旦字符串长度超过 MAX_LENGTH,即 100,代码就会崩溃。
崩溃消息是:
"Guru Meditation Error: Core 0 panic'ed (Interrupt wdt timeout on CPU0)"
发生崩溃重置后,代码继续正常工作,直到再次崩溃。 oldData 的 Strlen 打印 104,并保持在 104(我猜最大值应该是 99?)。代码在任务的无限循环的一个完整循环完成后恰好崩溃。
有人可以指导我这里可能做错了什么吗?如果需要,我可以提供更多信息。
提前致谢!
编辑:
原来下面一行没有注释:
strcpy(NEWDATA, oldData);
其中 NEWDATA 是一个大小为 20 的数组,显然是溢出导致了上述问题,现已解决。 我目前面临的另一个问题是我当前阅读的副本被附加到数组的末尾。下面我附上了我的日志副本:
new data: 5.00,
strlen oldData: 105
strlen newData: 5
Final Data: 5.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,5.00,
对于 100 的 MAX_LENGTH,我的数组大小为 105,并且根据我新阅读的长度保持在 100 以上。但是,我的代码没有崩溃。但是我最终数据的额外 5 长度始终是我得到的当前读数。 谁能帮我解决这个问题?
"Interrupt wdt timeout on CPU0" 非常清楚。你有一个看门狗超时重置。这反过来意味着您的代码太慢了,或者您没有从代码中的任何地方踢狗。
在嵌入式系统中使用 stdio.h 是一个很大的禁忌,因为它非常慢并且消耗资源。
另一个例子,如果优化不好或被禁用,for(int i = 0; i < ( strlen(newData) ); i++)
可能会给出非常慢的代码,应该用 size_t length = strlen(newData); for(int i=0; i<length; ...
最后,如果是写入flash,驱动需要先擦除flash,这需要很长时间。
您正在将 newData 复制到 oldData 中。 strlen() returns newData 的长度 不包括 空终止符。因此,您生成的 char 数组可能未终止,导致 nvs_set_str() 调用执行不需要的操作,并花费足够的时间来触发 WDT。
此外,memcpy() 可能会加快您对 oldData 的逐字节移位。我说可能是因为我不确定 memcpy 在 in situ 替换上是否正常工作;你需要阅读相关文档。
非常感谢所有评论和回答,我会考虑所有意见以改进我的代码。
然而,事实证明我在我的代码中错误地取消了注释,其中我的最终数组被复制到一个较小的数组中。这就是为什么我的代码不断崩溃的原因。问题,至此已经解决。一旦我完成了我代码的其他功能的实现,我将在稍后讨论这段代码的时间消耗和优化。
谢谢大家!!
由于对 OP 的编辑,添加了第二个答案。
首先,最好显示工作代码。这段话表明这不会编译:
nvs_get_str( nvsHandle, MASS_STRING_STORE, newData, &required_size);
char newData[15];
关于您的问题:您的 printf() 输出让我怀疑您是否真的在处理字符串数据。如果不是,则不要使用 nvs_get_str(),因为它会在遇到空字符后停止读取 NVS。同样,如果您在非字符串数据上使用 strlen() 可能无法正常工作。
如果您正在存储和操作非字符串数据,请使用 nvs_get_blob() 来检索它,并在您的程序中使用内存函数来复制它。