2013-08-28 47 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()的輸出變得如此詭異?

我的猜測是,當你用常量初始化局部變量時,編譯器會消除它們並使用常量。這將數組移動到堆棧中的其他位置,在檢查之前它不會被覆蓋。但這都是未定義行爲的範疇,所以確切的細節沒有任何實際意義。

相關問題