2013-08-28 45 views
0

我正在写一个函数来输出一个基本小时数&分钟的字符串,其格式为包含小时和分钟的两个全局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 

当我用下面

int hours = 7; 
int minutes = 0; 

取代getAlarmTime()函数的顶部两行输出然后什么:

调用函数处的字符指针生成以下的十六进制值我期望的:

07:00\0 

为什么使用那些globa l变量导致getAlarmTime()的输出变得如此诡异?

+0

出于好奇心't [5] = 0;'是什么意思? –

+0

@Rohit将空字符分配给最后一个数组元素 – mathematician1975

+0

Isnt''\ 0'' null'字符。 –

回答

4

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

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

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

return t; 
+0

我正在做一个arduino与4KB内存和大量的代码正在执行,包括一个迷你网络服务器,我宁愿避免字符串库,如果可能的话,因为它有相当大的足迹。我明白你在说什么,但我假设没有涉及到的另一个解决方案是在函数之外声明字符数组,并将指针作为参数传递,以作为缓冲区来写入。 – bdx

+0

@bdx:你是否熟悉[String class](http://arduino.cc/en/Reference/StringObject?from=Reference.StringClass)? –

+0

我是,但已经反复警告说,它包含时比字符数组有更大的内存占用量。我尽量靠近内存限制,我正在寻找方法尽可能减少我的内存使用量。 – bdx

2

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

1

为什么使用这些全局变量导致getAlarmTime()的输出变得如此诡异?

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

以下顺序进行:

  • 你叫getAlarmTime

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

  • 则T充满

  • 返回T的地址。

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

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

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

0

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

prog.cpp:在编译

return t;

的Ideone编译器返回以下错误在函数 '字符* getAlarmTime()':prog.cpp:8:8:警告: 局部变量't'的地址返回[-Wreturn-local-addr] char t [6];

但我不明白,当你与

int hours = 7; 
int minutes = 0; 

使用字符串替换1号2号线或顺从传递给您解决问题,它是如何工作的。甚至全球变量可以解决您的问题。

+1

当我这样做的时候,它一直运行似乎是失败的。 – bdx

+0

你使用什么编译器?当您尝试返回时,它是否返回任何警告(如果不是错误) –

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()的输出变得如此诡异?

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

相关问题