从字符串构建函数打印输出不返回预期结果

时间:2013-08-28 11:06:44

标签: c++ arduino

我正在编写一个输出基本小时数的功能。 24小时格式的分钟字符串,来自两个包含小时和分钟的全局int。

我在初始化期间定义了这些:

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()输出的那些全局变量变得如此不稳定?

5 个答案:

答案 0 :(得分:4)

您正在返回指向堆栈上的局部变量的指针。指针指向的内存不再有效,访问该内存会调用未定义的行为。你看到这种奇怪行为的原因是因为当你调用未定义的行为时会发生任何事情。

您的问题的解决方案是使用C ++编写代码并使用std :: string。

std::string t;
t.push_back((hours/10) + '0');
...

return t;

答案 1 :(得分:2)

您正在返回指向仅对您的函数本地的数组的指针。因此,当您的函数退出函数中创建的数组不再存在时,任何访问该内存的尝试都将导致未定义的行为。

答案 2 :(得分:1)

  

为什么使用导致getAlarmTime()输出的那些全局变量变得如此不稳定?

您实际上在这里查看未定义的行为,因为您正在返回本地(堆栈)变量的地址。

发生以下顺序:

  • 您致电getAlarmTime

  • 编译器为其变量(小时,分钟和t)分配堆栈空间。

  • 然后填写

  • 你返回t的地址。

  • 控制退出函数,返回的地址指向未使用的堆栈空间。

后续堆栈数据(之后声明的变量或其他函数调用)将覆盖此空间。

解决方案:考虑返回std::string而不是char*

答案 3 :(得分:0)

您正在返回一个Local变量作为指针。

return t;

Ideone编译器在编译时返回以下错误:

  

prog.cpp:在函数'char * getAlarmTime()'中:prog.cpp:8:8:警告:   返回的局部变量't'的地址[-Wreturn-local-addr] char   吨[6];

但是当我用

替换前2行时,我不明白它是如何工作的
int hours = 7;
int minutes = 0;

使用字符串或通过deference传递来解决您的问题。甚至全局变量都可以解决您的问题。

答案 4 :(得分: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*相同。

另一种可能性是使本地缓冲区静态;但请注意,该函数将不再是可重入或线程安全的,这可能会导致奇怪的错误。

  

为什么使用导致getAlarmTime()输出的那些全局变量变得如此不稳定?

我的猜测是,当你用常量初始化局部变量时,编译器会删除它们并使用常量代替。这会将数组移动到堆栈中的其他位置,在检查之前它不会被覆盖。但这都属于未定义行为的范畴,因此确切的细节并没有任何实际意义。