C++智能指針實(shí)例詳解
本文通過(guò)實(shí)例詳細(xì)闡述了C++關(guān)于智能指針的概念及用法,有助于讀者加深對(duì)智能指針的理解。詳情如下:
一、簡(jiǎn)介
由于 C++ 語(yǔ)言沒(méi)有自動(dòng)內(nèi)存回收機(jī)制,程序員每次 new 出來(lái)的內(nèi)存都要手動(dòng) delete。程序員忘記 delete,流程太復(fù)雜,最終導(dǎo)致沒(méi)有 delete,異常導(dǎo)致程序過(guò)早退出,沒(méi)有執(zhí)行 delete 的情況并不罕見(jiàn)。
用智能指針便可以有效緩解這類問(wèn)題,本文主要講解參見(jiàn)的智能指針的用法。包括:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr。你可能會(huì)想,如此多的智能指針就為了解決new、delete匹配問(wèn)題,真的有必要嗎?看完這篇文章后,我想你心里自然會(huì)有答案。
下面就按照順序講解如上 7 種智能指針(smart_ptr)。
二、具體使用
1、總括
對(duì)于編譯器來(lái)說(shuō),智能指針實(shí)際上是一個(gè)棧對(duì)象,并非指針類型,在棧對(duì)象生命期即將結(jié)束時(shí),智能指針通過(guò)析構(gòu)函數(shù)釋放有它管理的堆內(nèi)存。所有智能指針都重載了“operator->”操作符,直接返回對(duì)象的引用,用以操作對(duì)象。訪問(wèn)智能指針原來(lái)的方法則使用“.”操作符。
訪問(wèn)智能指針包含的裸指針則可以用 get() 函數(shù)。由于智能指針是一個(gè)對(duì)象,所以if (my_smart_object)永遠(yuǎn)為真,要判斷智能指針的裸指針是否為空,需要這樣判斷:if (my_smart_object.get())。
智能指針包含了 reset() 方法,如果不傳遞參數(shù)(或者傳遞 NULL),則智能指針會(huì)釋放當(dāng)前管理的內(nèi)存。如果傳遞一個(gè)對(duì)象,則智能指針會(huì)釋放當(dāng)前對(duì)象,來(lái)管理新傳入的對(duì)象。
我們編寫(xiě)一個(gè)測(cè)試類來(lái)輔助分析:
class Simple { public: Simple(int param = 0) { number = param; std::cout << "Simple: " << number << std::endl; } ~Simple() { std::cout << "~Simple: " << number << std::endl; } void PrintSomething() { std::cout << "PrintSomething: " << info_extend.c_str() << std::endl; } std::string info_extend; int number; };
2、std::auto_ptr
std::auto_ptr 屬于 STL,當(dāng)然在 namespace std 中,包含頭文件 #include<memory> 便可以使用。std::auto_ptr 能夠方便的管理單個(gè)堆內(nèi)存對(duì)象。
我們從代碼開(kāi)始分析:
void TestAutoPtr() { std::auto_ptr<Simple> my_memory(new Simple(1)); // 創(chuàng)建對(duì)象,輸出:Simple:1 if (my_memory.get()) { // 判斷智能指針是否為空 my_memory->PrintSomething(); // 使用 operator-> 調(diào)用智能指針對(duì)象中的函數(shù) my_memory.get()->info_extend = "Addition"; // 使用 get() 返回裸指針,然后給內(nèi)部對(duì)象賦值 my_memory->PrintSomething(); // 再次打印,表明上述賦值成功 (*my_memory).info_extend += " other"; // 使用 operator* 返回智能指針內(nèi)部對(duì)象,然后用“.”調(diào)用智能指針對(duì)象中的函數(shù) my_memory->PrintSomething(); // 再次打印,表明上述賦值成功 } } //my_memory棧對(duì)象即將結(jié)束生命期,析構(gòu)堆對(duì)象Simple(1)
執(zhí)行結(jié)果為:
Simple: 1 PrintSomething: PrintSomething: Addition PrintSomething: Addition other ~Simple: 1
上述為正常使用 std::auto_ptr 的代碼,一切似乎都良好,無(wú)論如何不用我們顯示使用該死的 delete 了。
其實(shí)好景不長(zhǎng),我們看看如下的另一個(gè)例子:
void TestAutoPtr2() { std::auto_ptr<Simple> my_memory(new Simple(1)); if (my_memory.get()) { std::auto_ptr<Simple> my_memory2; // 創(chuàng)建一個(gè)新的 my_memory2 對(duì)象 my_memory2 = my_memory; // 復(fù)制舊的 my_memory 給 my_memory2 my_memory2->PrintSomething(); // 輸出信息,復(fù)制成功 my_memory->PrintSomething(); // 崩潰 } }
最終如上代碼導(dǎo)致崩潰,如上代碼時(shí)絕對(duì)符合 C++ 編程思想的,居然崩潰了,跟進(jìn) std::auto_ptr 的源碼后,我們看到,罪魁禍?zhǔn)资恰癿y_memory2 = my_memory”,這行代碼,my_memory2 完全奪取了 my_memory 的內(nèi)存管理所有權(quán),導(dǎo)致 my_memory 懸空,最后使用時(shí)導(dǎo)致崩潰。
所以,使用 std::auto_ptr 時(shí),絕對(duì)不能使用“operator=”操作符。作為一個(gè)庫(kù),不允許用戶使用,確沒(méi)有明確拒絕,多少會(huì)覺(jué)得有點(diǎn)出乎預(yù)料。
看完 std::auto_ptr 好景不長(zhǎng)的第一個(gè)例子后,讓我們?cè)賮?lái)看一個(gè):
void TestAutoPtr3() { std::auto_ptr<Simple> my_memory(new Simple(1)); if (my_memory.get()) { my_memory.release(); } }
執(zhí)行結(jié)果為:
Simple: 1
看到什么異常了嗎?我們創(chuàng)建出來(lái)的對(duì)象沒(méi)有被析構(gòu),沒(méi)有輸出“~Simple: 1”,導(dǎo)致內(nèi)存泄露。當(dāng)我們不想讓 my_memory 繼續(xù)生存下去,我們調(diào)用 release() 函數(shù)釋放內(nèi)存,結(jié)果卻導(dǎo)致內(nèi)存泄露(在內(nèi)存受限系統(tǒng)中,如果my_memory占用太多內(nèi)存,我們會(huì)考慮在使用完成后,立刻歸還,而不是等到 my_memory 結(jié)束生命期后才歸還)。
正確的代碼應(yīng)該為:
void TestAutoPtr3() { std::auto_ptr<Simple> my_memory(new Simple(1)); if (my_memory.get()) { Simple* temp_memory = my_memory.release(); delete temp_memory; } }
或
void TestAutoPtr3() { std::auto_ptr<Simple> my_memory(new Simple(1)); if (my_memory.get()) { my_memory.reset(); // 釋放 my_memory 內(nèi)部管理的內(nèi)存 } }
原來(lái) std::auto_ptr 的 release() 函數(shù)只是讓出內(nèi)存所有權(quán),這顯然也不符合 C++ 編程思想。
總結(jié):std::auto_ptr 可用來(lái)管理單個(gè)對(duì)象的對(duì)內(nèi)存,但是,請(qǐng)注意如下幾點(diǎn):
(1) 盡量不要使用“operator=”。如果使用了,請(qǐng)不要再使用先前對(duì)象。
(2) 記住 release() 函數(shù)不會(huì)釋放對(duì)象,僅僅歸還所有權(quán)。
(3) std::auto_ptr 最好不要當(dāng)成參數(shù)傳遞(讀者可以自行寫(xiě)代碼確定為什么不能)。
(4) 由于 std::auto_ptr 的“operator=”問(wèn)題,有其管理的對(duì)象不能放入 std::vector 等容器中。
使用一個(gè) std::auto_ptr 的限制還真多,還不能用來(lái)管理堆內(nèi)存數(shù)組,這應(yīng)該是你目前在想的事情吧,我也覺(jué)得限制挺多的,哪天一個(gè)不小心,就導(dǎo)致問(wèn)題了。
由于 std::auto_ptr 引發(fā)了諸多問(wèn)題,一些設(shè)計(jì)并不是非常符合 C++ 編程思想,所以引發(fā)了下面 boost 的智能指針,boost 智能指針可以解決如上問(wèn)題。
讓我們繼續(xù)向下看。
3、boost::scoped_ptr
boost::scoped_ptr 屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。boost::scoped_ptr 跟 std::auto_ptr 一樣,可以方便的管理單個(gè)堆內(nèi)存對(duì)象,特別的是,boost::scoped_ptr 獨(dú)享所有權(quán),避免了 std::auto_ptr 惱人的幾個(gè)問(wèn)題。
我們還是從代碼開(kāi)始分析:
void TestScopedPtr() { boost::scoped_ptr<Simple> my_memory(new Simple(1)); if (my_memory.get()) { my_memory->PrintSomething(); my_memory.get()->info_extend = "Addition"; my_memory->PrintSomething(); (*my_memory).info_extend += " other"; my_memory->PrintSomething(); my_memory.release(); // 編譯 error: scoped_ptr 沒(méi)有 release 函數(shù) std::auto_ptr<Simple> my_memory2; my_memory2 = my_memory; // 編譯 error: scoped_ptr 沒(méi)有重載 operator=,不會(huì)導(dǎo)致所有權(quán)轉(zhuǎn)移 } }
首先,我們可以看到,boost::scoped_ptr 也可以像 auto_ptr 一樣正常使用。但其沒(méi)有 release() 函數(shù),不會(huì)導(dǎo)致先前的內(nèi)存泄露問(wèn)題。其次,由于 boost::scoped_ptr 是獨(dú)享所有權(quán)的,所以明確拒絕用戶寫(xiě)“my_memory2 = my_memory”之類的語(yǔ)句,可以緩解 std::auto_ptr 幾個(gè)惱人的問(wèn)題。
由于 boost::scoped_ptr 獨(dú)享所有權(quán),當(dāng)我們真真需要復(fù)制智能指針時(shí),需求便滿足不了了,如此我們?cè)僖胍粋€(gè)智能指針,專門(mén)用于處理復(fù)制,參數(shù)傳遞的情況,這便是如下的 boost::shared_ptr。
4、boost::shared_ptr
boost::shared_ptr 屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。在上面我們看到 boost::scoped_ptr 獨(dú)享所有權(quán),不允許賦值、拷貝,boost::shared_ptr 是專門(mén)用于共享所有權(quán)的,由于要共享所有權(quán),其在內(nèi)部使用了引用計(jì)數(shù)。boost::shared_ptr 也是用于管理單個(gè)堆內(nèi)存對(duì)象的。
我們還是從代碼開(kāi)始分析:
void TestSharedPtr(boost::shared_ptr<Simple> memory) { // 注意:無(wú)需使用 reference (或 const reference) memory->PrintSomething(); std::cout << "TestSharedPtr UseCount: " << memory.use_count() << std::endl; } void TestSharedPtr2() { boost::shared_ptr<Simple> my_memory(new Simple(1)); if (my_memory.get()) { my_memory->PrintSomething(); my_memory.get()->info_extend = "Addition"; my_memory->PrintSomething(); (*my_memory).info_extend += " other"; my_memory->PrintSomething(); } std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl; TestSharedPtr(my_memory); std::cout << "TestSharedPtr2 UseCount: " << my_memory.use_count() << std::endl; //my_memory.release();// 編譯 error: 同樣,shared_ptr 也沒(méi)有 release 函數(shù) }
執(zhí)行結(jié)果為:
Simple: 1 PrintSomething: PrintSomething: Addition PrintSomething: Addition other TestSharedPtr2 UseCount: 1 PrintSomething: Addition other TestSharedPtr UseCount: 2 TestSharedPtr2 UseCount: 1 ~Simple: 1
boost::shared_ptr 也可以很方便的使用。并且沒(méi)有 release() 函數(shù)。關(guān)鍵的一點(diǎn),boost::shared_ptr 內(nèi)部維護(hù)了一個(gè)引用計(jì)數(shù),由此可以支持復(fù)制、參數(shù)傳遞等。boost::shared_ptr 提供了一個(gè)函數(shù) use_count() ,此函數(shù)返回 boost::shared_ptr 內(nèi)部的引用計(jì)數(shù)。查看執(zhí)行結(jié)果,我們可以看到在 TestSharedPtr2 函數(shù)中,引用計(jì)數(shù)為 1,傳遞參數(shù)后(此處進(jìn)行了一次復(fù)制),在函數(shù)TestSharedPtr 內(nèi)部,引用計(jì)數(shù)為2,在 TestSharedPtr 返回后,引用計(jì)數(shù)又降低為 1。當(dāng)我們需要使用一個(gè)共享對(duì)象的時(shí)候,boost::shared_ptr 是再好不過(guò)的了。
在此,我們已經(jīng)看完單個(gè)對(duì)象的智能指針管理,關(guān)于智能指針管理數(shù)組,我們接下來(lái)講到。
5、boost::scoped_array
boost::scoped_array 屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。
boost::scoped_array 便是用于管理動(dòng)態(tài)數(shù)組的。跟 boost::scoped_ptr 一樣,也是獨(dú)享所有權(quán)的。
我們還是從代碼開(kāi)始分析:
void TestScopedArray() { boost::scoped_array<Simple> my_memory(new Simple[2]); // 使用內(nèi)存數(shù)組來(lái)初始化 if (my_memory.get()) { my_memory[0].PrintSomething(); my_memory.get()[0].info_extend = "Addition"; my_memory[0].PrintSomething(); (*my_memory)[0].info_extend += " other"; // 編譯 error,scoped_ptr 沒(méi)有重載 operator* my_memory[0].release(); // 同上,沒(méi)有 release 函數(shù) boost::scoped_array<Simple> my_memory2; my_memory2 = my_memory; // 編譯 error,同上,沒(méi)有重載 operator= } }
boost::scoped_array 的使用跟 boost::scoped_ptr 差不多,不支持復(fù)制,并且初始化的時(shí)候需要使用動(dòng)態(tài)數(shù)組。另外,boost::scoped_array 沒(méi)有重載“operator*”,其實(shí)這并無(wú)大礙,一般情況下,我們使用 get() 函數(shù)更明確些。
下面肯定應(yīng)該講 boost::shared_array 了,一個(gè)用引用計(jì)數(shù)解決復(fù)制、參數(shù)傳遞的智能指針類。
6、boost::shared_array
boost::shared_array 屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。
由于 boost::scoped_array 獨(dú)享所有權(quán),顯然在很多情況下(參數(shù)傳遞、對(duì)象賦值等)不滿足需求,由此我們引入 boost::shared_array。跟 boost::shared_ptr 一樣,內(nèi)部使用了引用計(jì)數(shù)。
我們還是從代碼開(kāi)始分析:
void TestSharedArray(boost::shared_array<Simple> memory) { // 注意:無(wú)需使用 reference (或 const reference) std::cout << "TestSharedArray UseCount: " << memory.use_count() << std::endl; } void TestSharedArray2() { boost::shared_array<Simple> my_memory(new Simple[2]); if (my_memory.get()) { my_memory[0].PrintSomething(); my_memory.get()[0].info_extend = "Addition 00"; my_memory[0].PrintSomething(); my_memory[1].PrintSomething(); my_memory.get()[1].info_extend = "Addition 11"; my_memory[1].PrintSomething(); //(*my_memory)[0].info_extend += " other"; // 編譯 error,scoped_ptr 沒(méi)有重載 operator* } std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl; TestSharedArray(my_memory); std::cout << "TestSharedArray2 UseCount: " << my_memory.use_count() << std::endl; }
執(zhí)行結(jié)果為:
Simple: 0 Simple: 0 PrintSomething: PrintSomething: Addition 00 PrintSomething: PrintSomething: Addition 11 TestSharedArray2 UseCount: 1 TestSharedArray UseCount: 2 TestSharedArray2 UseCount: 1 ~Simple: 0 ~Simple: 0
跟 boost::shared_ptr 一樣,使用了引用計(jì)數(shù),可以復(fù)制,通過(guò)參數(shù)來(lái)傳遞。
至此,我們講過(guò)的智能指針有 std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array。這幾個(gè)智能指針已經(jīng)基本夠我們使用了,90% 的使用過(guò)標(biāo)準(zhǔn)智能指針的代碼就這 5 種??扇缦逻€有兩種智能指針,它們肯定有用,但有什么用處呢,一起看看吧。
7、boost::weak_ptr
boost::weak_ptr 屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。
在講 boost::weak_ptr 之前,讓我們先回顧一下前面講解的內(nèi)容。似乎 boost::scoped_ptr、boost::shared_ptr 這兩個(gè)智能指針就可以解決所有單個(gè)對(duì)象內(nèi)存的管理了,這兒還多出一個(gè) boost::weak_ptr,是否還有某些情況我們沒(méi)納入考慮呢?
回答:有。首先 boost::weak_ptr 是專門(mén)為 boost::shared_ptr 而準(zhǔn)備的。有時(shí)候,我們只關(guān)心能否使用對(duì)象,并不關(guān)心內(nèi)部的引用計(jì)數(shù)。boost::weak_ptr 是 boost::shared_ptr 的觀察者(Observer)對(duì)象,觀察者意味著 boost::weak_ptr 只對(duì) boost::shared_ptr 進(jìn)行引用,而不改變其引用計(jì)數(shù),當(dāng)被觀察的 boost::shared_ptr 失效后,相應(yīng)的 boost::weak_ptr 也相應(yīng)失效。
我們還是從代碼開(kāi)始分析:
void TestWeakPtr() { boost::weak_ptr<Simple> my_memory_weak; boost::shared_ptr<Simple> my_memory(new Simple(1)); std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl; my_memory_weak = my_memory; std::cout << "TestWeakPtr boost::shared_ptr UseCount: " << my_memory.use_count() << std::endl; }
執(zhí)行結(jié)果為:
Simple: 1 TestWeakPtr boost::shared_ptr UseCount: 1 TestWeakPtr boost::shared_ptr UseCount: 1 ~Simple: 1
我們看到,盡管被賦值了,內(nèi)部的引用計(jì)數(shù)并沒(méi)有什么變化,當(dāng)然,讀者也可以試試傳遞參數(shù)等其他情況。
現(xiàn)在要說(shuō)的問(wèn)題是,boost::weak_ptr 到底有什么作用呢?從上面那個(gè)例子看來(lái),似乎沒(méi)有任何作用,其實(shí) boost::weak_ptr 主要用在軟件架構(gòu)設(shè)計(jì)中,可以在基類(此處的基類并非抽象基類,而是指繼承于抽象基類的虛基類)中定義一個(gè) boost::weak_ptr,用于指向子類的 boost::shared_ptr,這樣基類僅僅觀察自己的 boost::weak_ptr 是否為空就知道子類有沒(méi)對(duì)自己賦值了,而不用影響子類 boost::shared_ptr 的引用計(jì)數(shù),用以降低復(fù)雜度,更好的管理對(duì)象。
8、boost::intrusive_ptr
boost::intrusive_ptr屬于 boost 庫(kù),定義在 namespace boost 中,包含頭文件 #include<boost/smart_ptr.hpp> 便可以使用。
講完如上 6 種智能指針后,對(duì)于一般程序來(lái)說(shuō) C++ 堆內(nèi)存管理就夠用了,現(xiàn)在有多了一種 boost::intrusive_ptr,這是一種插入式的智能指針,內(nèi)部不含有引用計(jì)數(shù),需要程序員自己加入引用計(jì)數(shù),不然編譯不過(guò)(⊙﹏⊙b汗)。個(gè)人感覺(jué)這個(gè)智能指針沒(méi)太大用處,至少我沒(méi)用過(guò)。有興趣的朋友自己研究一下源代碼哦。
三、總結(jié)
如上講了這么多智能指針,有必要對(duì)這些智能指針做個(gè)總結(jié):
1、在可以使用 boost 庫(kù)的場(chǎng)合下,拒絕使用 std::auto_ptr,因?yàn)槠洳粌H不符合 C++ 編程思想,而且極容易出錯(cuò)。
2、在確定對(duì)象無(wú)需共享的情況下,使用 boost::scoped_ptr(當(dāng)然動(dòng)態(tài)數(shù)組使用 boost::scoped_array)。
3、在對(duì)象需要共享的情況下,使用 boost::shared_ptr(當(dāng)然動(dòng)態(tài)數(shù)組使用 boost::shared_array)。
4、在需要訪問(wèn) boost::shared_ptr 對(duì)象,而又不想改變其引用計(jì)數(shù)的情況下,使用 boost::weak_ptr,一般常用于軟件框架設(shè)計(jì)中。
5、最后一點(diǎn),也是要求最苛刻一點(diǎn):在你的代碼中,不要出現(xiàn) delete 關(guān)鍵字(或 C 語(yǔ)言的 free 函數(shù)),因?yàn)榭梢杂弥悄苤羔樔ス芾怼?/p>
上一篇:WM_CLOSE、WM_DESTROY、WM_QUIT及各種消息投遞函數(shù)詳解
欄 目:C語(yǔ)言
下一篇:VC實(shí)現(xiàn)動(dòng)態(tài)菜單的創(chuàng)建方法
本文標(biāo)題:C++智能指針實(shí)例詳解
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3605.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解
- 01-10深入C/C++浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式詳解
- 01-10深入理解數(shù)組指針與指針數(shù)組的區(qū)別


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?