1. 程式人生 > >返回static的變數指標危險和printf的執行順序

返回static的變數指標危險和printf的執行順序

char* fun(const char* src)
 {
   static char dest[32] = "";
   
   strcpy(dest, src);

  return dest;
}

int main(int argc, char* argv[])
{
	char s1[32] = "";
  char s2[32] = "";

  strcpy(s1, fun("hello"));
  strcpy(s2, fun("world"));

  printf("%s %s\n", s1, s2);
  printf("%s %s\n", fun("hello"), fun("world"));

	getchar();
}

上文在vs2008的執行結果如下

hello world

hello hello

從以上結果可以看出

1.printf函式從右執行

2.返回static變數的指標有點危險。值則不會有這個問題。

上面的這段程式碼確實不能看,字串複製,不需要傳入長度引數,也不根據結束符判斷大小,也無法確定是否會溢位。不可取,不可取。

   我們在寫C/C++程式的時候,經常需要從呼叫函式中取得自己想要的資料,這就需要呼叫者和函式之間要有個記憶體的互動,我們通常採用的方法是傳遞一個指標給被調函式,作為被調函式的輸出引數,這也是我們常用的、規範的做法。
    但有很多程式設計師比較習慣直接取返回值,這就面臨一個問題就是普通區域性變數都是在棧上分派的,會隨著函式的結束而彈棧釋放,那麼就會出現返回區域性變數陣列的問題,這時有人會想到用malloc或new在堆上分派記憶體,沒錯,這樣是避免了前面說的問題,但這樣又會帶來新的問題,就是需要在外部對這塊記憶體進行釋放,這個是比較難把握的,多次釋放會出現程式的crash,忘記釋放了會出現記憶體leak,所以這種方法也不被推薦。還有人想到了更另類的方法,就是上面例子中的static型別,沒錯,static變數也是全域性的,但就會出現上面程式的執行結果(可以認為不是我們想要的結果,也就是錯誤的結果)。


    所以,我們要慎用返回函式內部的static記憶體的這種設計,但如果在無法改變設計模式的情況下(有些系統函式的實現,比如inet_ntoa,可以通過在man手冊中看到這樣的一句話:The string is returned in a statically allocated buffer, which subsequent calls will overwrite),那麼在自己使用的時候一定要注意,不要試圖儲存返回的記憶體地址或引用,而要儲存返回記憶體的內容,也就是例子程式中的strcpy兩行。

inet_ntoa的錯誤使用(判斷兩個IP地址是否相等):

 1struct in_addr addr1;
 2struct in_addr addr2;
 3
 4// 網路包中包含了源地址 5addr1.s_addr =0x6500A8C0// 192.168.0.101 6addr2.s_addr =0x6600A8C0// 192.168.0.102
 7
 8// 這個if語句將永遠為真 9if (strcmp(inet_ntoa(addr1), inet_ntoa(addr2)) ==0{
10  // do something11}
else{
12  // do other thing13}

看官笑過,出差回來水一篇