• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            voip
            風(fēng)的方向
            厚德致遠(yuǎn),博學(xué)敦行!
            posts - 52,comments - 21,trackbacks - 0

            值傳遞, 指針傳遞?

            這幾天在學(xué)習(xí)C過(guò)程中,在使用指針作為函數(shù)參數(shù)傳遞的時(shí)候出現(xiàn)了問(wèn)題,根本不知道從何得解:源代碼如下:
                createNode(BinNode *tree,char *p)
                {
                    tree = (BinNode *) malloc(sizeof(BinNode));
                    tree->data = *p;
                }
            該代碼段的意圖是通過(guò)一個(gè)函數(shù)創(chuàng)建一個(gè)二叉樹(shù)的節(jié)點(diǎn),然而在,調(diào)用該函數(shù)后,試圖訪(fǎng)問(wèn)該節(jié)點(diǎn)結(jié)構(gòu)體的成員時(shí)候,卻發(fā)生了內(nèi)存訪(fǎng)問(wèn)錯(cuò)誤,到底問(wèn)題出在哪兒呢?

            一直不明白指針作為函數(shù)參數(shù)傳值的機(jī)制,翻開(kāi)林銳的《高質(zhì)量C/C++編程指南》,找到了答案。

                [如果函數(shù)的參數(shù)是一個(gè)指針,不要指望用該指針去申請(qǐng)動(dòng)態(tài)內(nèi)存]
                
            原來(lái)問(wèn)題出在C編譯器原理上:編譯器總是要為函數(shù)的每個(gè)參數(shù)制作臨時(shí)副本,指針參數(shù)tree的副本是 _tree,編譯器使 _tree = tree。如果函數(shù)體內(nèi)的程序修改了_tree的內(nèi)容,就導(dǎo)致參數(shù)tree的內(nèi)容作相應(yīng)的修改。這就是指針可以用作輸出參數(shù)的原因。
            即上面的函數(shù)代碼經(jīng)過(guò)編譯后成為:
                createNode(BinNode *tree,char *p)
                {
                    BinNode *_tree;
                    _tree = tree;
                    _tree = (BinNode *) malloc(sizeof(BinNode));
                    _tree->data = *p;
                }
            如果沒(méi)有
                _tree = (BinNode *) malloc(sizeof(BinNode));
            這個(gè)語(yǔ)句,在函數(shù)體內(nèi)修改了_tree的內(nèi)容,將會(huì)導(dǎo)致參數(shù)tree的內(nèi)容作相應(yīng)的修改,因?yàn)樗鼈冎赶蛳嗤膬?nèi)存地址。而
                _tree = (BinNode *) malloc(sizeof(BinNode));
            這個(gè)句,系統(tǒng)重新分配內(nèi)存給_tree指針,_tree指針指向了系統(tǒng)分配的新地址,函數(shù)體內(nèi)修改的只是_tree的內(nèi)容,對(duì)原tree所指的地址的內(nèi)容沒(méi)有任何影響。因此,函數(shù)的參數(shù)是一個(gè)指針時(shí),不要在函數(shù)體內(nèi)部改變指針?biāo)傅牡刂?,那樣毫無(wú)作用,需要修改的只能是指針?biāo)赶虻膬?nèi)容。即應(yīng)當(dāng)把指針當(dāng)作常量。

            如果非要使用函數(shù)指針來(lái)申請(qǐng)內(nèi)存空間,那么需要使用指向指針的指針
                createNode(BinNode **tree,char *p)
                {
                    *tree = (BinNode *) malloc(sizeof(BinNode));
                }
            上面的是林銳的說(shuō)法,目前來(lái)說(shuō)不知道怎么去理解,不過(guò)可以有另外的方案,通過(guò)函數(shù)返回值傳遞動(dòng)態(tài)內(nèi)存:
                BinNode *createNode()
                {
                    BinNode *tree;
                    tree = (BinNode *) malloc(sizeof(BinNode));
                    return tree;
                }
            這個(gè)倒還說(shuō)得過(guò)去,因?yàn)楹瘮?shù)返回的是一個(gè)地址的值,該地址就是申請(qǐng)的內(nèi)存塊首地址。但是,這個(gè)容易和另外的一個(gè)忠告相混繞
                [不要用return語(yǔ)句返回指向“棧內(nèi)存”的指針,因?yàn)樵搩?nèi)存在函數(shù)結(jié)束時(shí)自動(dòng)消亡]

            這里區(qū)分一下靜態(tài)內(nèi)存,棧內(nèi)存和動(dòng)態(tài)分配的內(nèi)存(堆內(nèi)存)的區(qū)別:
            (1) 從靜態(tài)存儲(chǔ)區(qū)域分配。內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好,這塊內(nèi)存在程序的整個(gè)運(yùn)行期間都存在。例如全局變量,static變量。
            (2) 在棧上創(chuàng)建。在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
            (3) 從堆上分配,亦稱(chēng)動(dòng)態(tài)內(nèi)存分配。程序在運(yùn)行的時(shí)候用malloc或new申請(qǐng)任意多少的內(nèi)存,程序員自己負(fù)責(zé)在何時(shí)用free或delete釋放內(nèi)存。動(dòng)態(tài)內(nèi)存的生存期由我們決定,使用非常靈活,但問(wèn)題也最多。

            因此,試圖返回一個(gè)棧上分配的內(nèi)存將會(huì)引發(fā)未知錯(cuò)誤
                char *GetString(void)
                {
                    char p[] = "hello world";
                    return p; // 編譯器將提出警告
                }
            p是在棧上分配的內(nèi)存,函數(shù)結(jié)束后將會(huì)自動(dòng)釋放,p指向的內(nèi)存區(qū)域內(nèi)容不是"hello world",而是未知的內(nèi)容。
            如果是返回靜態(tài)存儲(chǔ)的內(nèi)存呢:
                char *GetString(void)
                {
                    char *p = "hello world";
                    return p;
                }
            這里“hello world”是常量字符串,位于靜態(tài)存儲(chǔ)區(qū),它在程序生命期內(nèi)恒定不變。無(wú)論什么時(shí)候調(diào)用GetString,它返回的始終是同一個(gè)“只讀”的內(nèi)存塊。
             
            [參考:林銳《高質(zhì)量C/C++編程指南》]

            posted on 2010-10-31 19:32 jince 閱讀(694) 評(píng)論(0)  編輯 收藏 引用

            只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            哈哈哈哈哈哈
            久久久久亚洲精品天堂久久久久久 | 久久国产乱子精品免费女| 国内精品九九久久精品| 色播久久人人爽人人爽人人片AV| 欧美牲交A欧牲交aⅴ久久| 青青草国产精品久久久久| 97久久国产综合精品女不卡| 亚洲综合日韩久久成人AV| 精品久久一区二区| 国内精品久久久久久久久电影网 | 狠狠色丁香久久婷婷综| 久久久久无码精品国产app| 久久天天躁狠狠躁夜夜avapp| 欧美精品一区二区精品久久| 久久久久久久波多野结衣高潮| 日韩美女18网站久久精品| 久久久综合九色合综国产| 久久久久久久久66精品片| 很黄很污的网站久久mimi色| 久久久久久久人妻无码中文字幕爆| 久久无码一区二区三区少妇| www性久久久com| 国产精品毛片久久久久久久| 97精品伊人久久久大香线蕉 | 精品综合久久久久久888蜜芽| 久久综合给合综合久久| 久久久久久久99精品免费观看| 亚洲AV无码久久寂寞少妇| 亚洲人成网亚洲欧洲无码久久| 精品久久久无码中文字幕| 久久精品国产亚洲AV无码偷窥 | 亚洲精品综合久久| 久久久久亚洲AV无码专区桃色| 精品久久久噜噜噜久久久| 久久人人爽爽爽人久久久| 亚洲精品乱码久久久久66| 久久精品国产亚洲AV蜜臀色欲| 久久久久久亚洲精品影院| 中文字幕无码久久久| 精品久久久一二三区| 99精品久久久久久久婷婷|