Saq*_*Ali 2 c++ arrays arduino char
我有以下 C++ 函数,它从闪存读取字符串并返回它。我想避免使用 String 类,因为这是在 Arduino 上,并且我被告知 Arduino 的 String 类有问题。
const char* readFromFlashMemory()
{
char s[FLASH_STOP_ADDR-FLASH_START_ADDR+2];
memset(s, (byte)'\0', FLASH_STOP_ADDR-FLASH_START_ADDR+2);
unsigned short int numChars = 0;
for (int i = FLASH_START_ADDRESS; i <= FLASH_STOP_ADDRESS; i++)
{
byte b = EEPROM.read(i);
if (b == (byte)'\0')
return s;
else
s[numChars++] = (char)b;
}
}
Run Code Online (Sandbox Code Playgroud)
这个功能似乎有效。但调用方法返回一个空字符串。我是否不允许返回指向该函数堆栈上的字符数组的指针?我应该如何编写这个函数的最佳/最惯用的方式是什么,以便调用函数接收我想要传递给它的值?
这些评论可能会让您误入歧途,或者充其量会让您感到困惑。让我用一些选项来分解它。
首先,问题正如您所说:当函数从堆栈弹出到调用者时,您要返回的地址的数组不再存在。忽略此结果会导致未定义的行为。
以下是一些选项以及一些讨论:
调用者拥有缓冲区
void readFromFlashMemory(char *s, size_t len)
Run Code Online (Sandbox Code Playgroud)
优点是调用者可以选择如何分配内存,这在嵌入式环境中很有用。
请注意,为了方便起见,您也可以选择s从此函数返回,或者传达一些额外的含义。
对我来说,如果我在 Arduino 等嵌入式环境中工作,这将是我 100% 的偏好。
使用std::string,std::vector或类似的
std::string readFromFlashMemory()
Run Code Online (Sandbox Code Playgroud)
如果您不关心分配开销和其他潜在问题(例如随着时间的推移碎片),您可能会这样做。
自己分配内存
char* readFromFlashMemory()
Run Code Online (Sandbox Code Playgroud)
如果您想确保分配的内存大小完全正确,那么您可能会先读入本地缓冲区,然后分配内存并复制。std::string与处理堆内存的其他解决方案相同的内存注意事项。
这种形式还具有噩梦般的特性,即调用者负责管理返回的指针并最终调用delete[]. 这是非常不可取的。这也是令人痛苦的普遍现象。:(
如果绝对必须的话,返回动态分配的内存的更好方法
std::unique_ptr<char[]> readFromFlashMemory()
Run Code Online (Sandbox Code Playgroud)
与 #3 相同,但指针是安全管理的。需要 C++11 或更高版本。
使用静态缓冲区
const char* readFromFlashMemory()
{
static char s[FLASH_STOP_ADDR-FLASH_START_ADDR+2];
// ...
return s;
}
Run Code Online (Sandbox Code Playgroud)
一般都会皱起眉头。特别是因为这种类型的模式会在多线程环境中导致严重的问题。
人们大多选择这种方法,因为他们很懒并且想要一个简单的界面。我想一个好处是调用者不必知道可接受的缓冲区大小。
使用内部缓冲区创建您自己的类
class FlashReader
{
public:
const char* Read();
private:
char buffer[FLASH_STOP_ADDR-FLASH_START_ADDR+2];
};
Run Code Online (Sandbox Code Playgroud)
这是一个更加冗长的解决方案,并且可能开始听起来像是过度设计。但它确实结合了#1 和#5 的最佳部分。也就是说,您获得缓冲区的堆栈分配,您不需要知道大小,并且函数本身不需要额外的参数。
如果您确实想要一个静态缓冲区,那么您可以只定义该类的一个静态实例,但区别在于代码中对此的明确意图。