讀一下這個程序,先看這個程序?qū)懙挠袉栴}沒(假設(shè)fun函數(shù)的參數(shù)長度小于32)?如果你對這個程序中的fun函數(shù)返回一個局部變量的數(shù)組產(chǎn)生了疑問,那么我希望你是沒注意到我使用的static類型,若你仍有疑問,建議你先回去查查static變量的作用域和生命周期的概念。 OK,是運(yùn)行這個程序的時候了,看一下運(yùn)行結(jié)果是否跟你想象的一樣呢?如果是一樣的,那么這篇文章你不用看了,因為你已經(jīng)掌握了我下面要說的問題了。好吧,對于不理解運(yùn)行結(jié)果的朋友,我們來分析一些下面那個printf語句,首先要知道printf中的表達(dá)式、函數(shù)的執(zhí)行順序是至右向左的,也就是先執(zhí)行了fun("world")返回了dest的地址,然后再執(zhí)行fun("hello")也返回了dest的地址,而這兩次返回的dest用的同一塊地址(因為是static類型),也就是第二次的執(zhí)行覆蓋了第一次執(zhí)行的結(jié)果,對dest地址進(jìn)行了重新的賦值,所以結(jié)果就是打印兩個hello了。
我們在寫C/C++程序的時候,經(jīng)常需要從調(diào)用函數(shù)中取得自己想要的數(shù)據(jù),這就需要調(diào)用者和函數(shù)之間要有個內(nèi)存的交互,我們通常采用的方法是傳遞一個指針給被調(diào)函數(shù),作為被調(diào)函數(shù)的輸出參數(shù),這也是我們常用的、規(guī)范的做法。 但有很多程序員比較習(xí)慣直接取返回值,這就面臨一個問題就是普通局部變量都是在棧上分派的,會隨著函數(shù)的結(jié)束而彈棧釋放,那么就會出現(xiàn)返回局部變量數(shù)組的問題,這時有人會想到用malloc或new在堆上分派內(nèi)存,沒錯,這樣是避免了前面說的問題,但這樣又會帶來新的問題,就是需要在外部對這塊內(nèi)存進(jìn)行釋放,這個是比較難把握的,多次釋放會出現(xiàn)程序的crash,忘記釋放了會出現(xiàn)內(nèi)存leak,所以這種方法也不被推薦。還有人想到了更另類的方法,就是上面例子中的static類型,沒錯,static變量也是全局的,但就會出現(xiàn)上面程序的運(yùn)行結(jié)果(可以認(rèn)為不是我們想要的結(jié)果,也就是錯誤的結(jié)果)。 所以,我們要慎用返回函數(shù)內(nèi)部的static內(nèi)存的這種設(shè)計,但如果在無法改變設(shè)計模式的情況下(有些系統(tǒng)函數(shù)的實(shí)現(xiàn),比如inet_ntoa,可以通過在man手冊中看到這樣的一句話:The string is returned in a statically allocated buffer, which subsequent calls will overwrite),那么在自己使用的時候一定要注意,不要試圖保存返回的內(nèi)存地址或引用,而要保存返回內(nèi)存的內(nèi)容,也就是例子程序中的strcpy兩行。inet_ntoa的錯誤使用(判斷兩個IP地址是否相等):
Copyright @ 老狼 Powered by: .Text and ASP.NET Theme by: .NET Monster