C++ 打印字符串生成函数的输出未返回预期结果
我正在编写一个函数,从包含小时和分钟的两个全局整数输出24小时格式的基本小时和分钟字符串 我在初始化过程中定义了以下内容:C++ 打印字符串生成函数的输出未返回预期结果,c++,arduino,C++,Arduino,我正在编写一个函数,从包含小时和分钟的两个全局整数输出24小时格式的基本小时和分钟字符串 我在初始化过程中定义了以下内容: int g_alarmHours = 7; int g_alarmMinutes = 0; 返回字符串的函数是: char* getAlarmTime() { int hours = g_alarmHours; int minutes = g_alarmMinutes; char t[6]; t[0] = (hours/10) + '0'; t[1]
int g_alarmHours = 7;
int g_alarmMinutes = 0;
返回字符串的函数是:
char* getAlarmTime() {
int hours = g_alarmHours;
int minutes = g_alarmMinutes;
char t[6];
t[0] = (hours/10) + '0';
t[1] = (hours%10) + '0';
t[2] = ':';
t[3] = (minutes/10) + '0';
t[4] = (minutes%10) + '0';
t[5] = 0;
return t;
}
全局变量是在添加到另一个设备的串行通信时要替换的存根,从中检索这些值
调用该函数会在字符指针处生成以下十六进制值:
0x20 0x4b 0x00
当我将getAlarmTime函数的前两行替换为以下内容时
int hours = 7;
int minutes = 0;
那么,输出就是我所期望的:
07:00\0
为什么使用这些全局变量会导致getAlarmTime的输出变得如此不稳定?您正在返回指向堆栈上局部变量的指针。指针指向的内存不再有效,访问该内存将调用未定义的行为。您看到这种奇怪行为的原因是,当您调用未定义的行为时,任何事情都可能发生
解决问题的方法是用C++编写代码,使用STD::String。
std::string t;
t.push_back((hours/10) + '0');
...
return t;
您返回的是一个指向数组的指针,该数组仅位于函数的本地。因此,当函数退出时,在函数中创建的数组将不再存在,任何访问该内存的尝试都将导致未定义的行为 为什么使用这些全局变量会导致getAlarmTime的输出变得如此不稳定 实际上,您在这里看到的是未定义的行为,因为您返回的是本地堆栈变量的地址 发生以下顺序: 您可以调用getAlarmTime 编译器为其变量小时、分钟和t分配堆栈空间 然后t被填满了 您返回t的地址 控件退出函数,返回的地址指向未使用的堆栈空间 随后声明的堆栈数据变量或其他函数调用将覆盖此空间
解决方案:考虑返回一个STD::String,而不是char *.< /p> ,您正在返回一个局部变量作为指针。 返回t
Ideone编译器在编译时返回以下错误: prog.cpp:在函数“char*getAlarmTime”中:prog.cpp:8:8:警告: 局部变量“t”的地址返回[-Wreturn local addr]char t[6] 但是我不明白当你把前两行换成int hours = 7;
int minutes = 0;
使用字符串或传递尊重来解决您的问题。甚至一个全局变量也可以解决您的问题 您正在返回指向本地数组的指针。在调用方可以访问它之前,它被销毁,从而导致未定义的行为;实际上,它可能会也可能不会被其他人的数据覆盖 通常的解决方案是返回一个动态数组,如std::string;但既然你说你有极端的内存限制,那在这里就不是个好主意 我将修改该函数,以便调用者提供缓冲区:
void getAlarmTime(char t[6]) {
int hours = g_alarmHours;
int minutes = g_alarmMinutes;
t[0] = (hours/10) + '0';
t[1] = (hours%10) + '0';
t[2] = ':';
t[3] = (minutes/10) + '0';
t[4] = (minutes%10) + '0';
t[5] = 0;
}
请注意,调用者现在负责确保缓冲区足够大。尽管我将参数声明为char[6],但它仅用作文档;对于编译器来说,它与char*相同
另一种可能是使本地缓冲区静态;但是请注意,该函数将不再是可重入的或线程安全的,这可能会导致奇怪的bug
为什么使用这些全局变量会导致getAlarmTime的输出变得如此不稳定
我的猜测是,当您使用常量初始化局部变量时,编译器会删除它们并使用常量。这会将数组移动到堆栈中的其他位置,在检查它之前,它恰好不会被覆盖。但是这些都是未定义行为的领域,因此确切的细节没有任何实际意义。出于好奇,什么是t[5]=0;平均值?@Rohit将空字符分配给最后一个数组元素不是'\0'空字符。@Rohit'\0'==0。我只是一个懒惰的打字员,用最短的路径得到同样的结果。谢谢你的解释:我在一个有4KB内存的arduino上做这件事,并且执行了很多代码,包括一个迷你Web服务器,如果可能的话,我宁愿避免使用字符串库,因为它占用了相当大的空间。不过我明白你的意思,我假设另一个不涉及的解决方案是在函数外部声明字符数组,并将指针作为参数传递给它作为缓冲区写入。@bdx:你熟悉吗?我是,但是,有人一再警告说,如果包含字符数组,它的内存占用比字符数组大得多。我正在接近RAM限制,我正在寻找尽可能减少内存使用的方法。@bdx:那么你的解决方案就可以了。我这样做时,它始终工作正常,这似乎是运气不佳。你在使用什么编译器?它还没回来吗 尝试返回时,如果没有错误,则发出警告