讀一下這個程序,先看這個程序寫的有問題沒(假設fun函數的參數長度小于32)?如果你對這個程序中的fun函數返回一個局部變量的數組產生了疑問,那么我希望你是沒注意到我使用的static類型,若你仍有疑問,建議你先回去查查static變量的作用域和生命周期的概念。 OK,是運行這個程序的時候了,看一下運行結果是否跟你想象的一樣呢?如果是一樣的,那么這篇文章你不用看了,因為你已經掌握了我下面要說的問題了。好吧,對于不理解運行結果的朋友,我們來分析一些下面那個printf語句,首先要知道printf中的表達式、函數的執行順序是至右向左的,也就是先執行了fun("world")返回了dest的地址,然后再執行fun("hello")也返回了dest的地址,而這兩次返回的dest用的同一塊地址(因為是static類型),也就是第二次的執行覆蓋了第一次執行的結果,對dest地址進行了重新的賦值,所以結果就是打印兩個hello了。
我們在寫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地址是否相等):
Copyright @ 老狼 Powered by: .Text and ASP.NET Theme by: .NET Monster