• <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>

            C++中的指針問題-很難很基礎

            指針問題
            信息來源:網絡


            譯者序:

              這是一篇我所見過的關于指針的最好的入門級文章,它可使初學者在很短的時間內掌握復雜的指針操作。雖然,現在的JAVA、C#等語言已經取消了指針,但作為一個C++程序員,指針的直接操作內存,在數據操作方面有著速度快,節約內存等優點,仍是很多C++程序員的最愛。指針就像是一把良劍,就看你怎么去應用它!
              有關這篇文章的技術性問題你可以寫信給我:webmaster@chinahai.com.同時我的另外兩篇相關文章《模板Guide》和《STL Guide》也快完成,希望能對您有所幫助!Loading... ...

            譯者:萬江(chinahai)


            什么是指針?

              其實指針就像是其它變量一樣,所不同的是一般的變量包含的是實際的真實的數據,而指針是一個指示器,它告訴程序在內存的哪塊區域可以找到數據。這是一個非常重要的概念,有很多程序和算法都是圍繞指針而設計的,如鏈表。


            開始學習

              如何定義一個指針呢?就像你定義一個其它變量一樣,只不過你要在指針名字前加上一個星號。我們來看一個例子:
              下面這個程序定義了兩個指針,它們都是指向整型數據。


            int* pNumberOne;
            int* pNumberTwo;

              你注意到在兩個變量名前的“p”前綴了嗎?這是程序員通常在定義指針時的一個習慣,以提高便程序的閱讀性,表示這是個指針。現在讓我們來初始化這兩個指針:
            pNumberOne = &some_number;
            pNumberTwo = &some_other_number;
              &號讀作“什么的地址”,它表示返回的是變量在內存中的地址而不是變量本身的值。在這個例子中,pNumberOne 等于some_number的地址,所以現在pNumberOne指向some_number。 如果現在我們在程序中要用到some_number,我們就可以使用pNumberOne。


            我們來學習一個例子:

              在這個例子中你將學到很多,如果你對指針的概念一點都不了解,我建議你多看幾遍這個例子,指針是個很復雜的東西,但你會很快掌握它的。
              這個例子用以增強你對上面所介紹內容的了解。它是用C編寫的(注:原英文版是用C寫的代碼,譯者重新用C++改寫寫了所有代碼,并在DEV C++ 和VC++中編譯通過!)


            #include <iostream.h>

            void main()
            {
            // 聲明變量:
            int nNumber;
            int *pPointer;


            // 現在給它們賦值:
            nNumber = 15;
            pPointer = &nNumber;

            //打印出變量nNumber的值:
            cout<<"nNumber is equal to :"<< nNumber<<endl;

            // 現在通過指針改變nNumber的值:
            *pPointer = 25;

            //證明nNumber已經被上面的程序改變
            //重新打印出nNumber的值:
            cout<<"nNumber is equal to :"<<nNumber<<endl;
            }

              通讀一下這個程序,編譯并運行它,務必明白它是怎樣工作的。如果你完成了,準備好,開始下一小節。


            陷井!

              試一下,你能找出下面這段程序的錯誤嗎?

            #include <iostream.h>

            int *pPointer;

            void SomeFunction();
            {
            int nNumber;
            nNumber = 25;


            //讓指針指向nNumber:
            pPointer = &nNumber;
            }

            void main()
            {
            SomeFunction(); //為pPointer賦值

            //為什么這里失敗了?為什么沒有得到25
            cout<<"Value of *pPointer: "<<*pPointer<<endl;
            }

              這段程序先調用了SomeFunction函數,創建了個叫nNumber的變量,接著讓指針pPointer指向了它。可是問題出在哪兒呢?當函數結束后,nNumber被刪掉了,因為這一個局部變量。局部變量在定義它的函數執行完后都會被系統自動刪掉。也就是說當SomeFunction 函數返回主函數main()時,這個變量已經被刪掉,但pPointer還指著變量曾經用過的但現在已不屬于這個程序的區域。如果你還不明白,你可以再讀讀這個程序,注意它的局部變量和全局變量,這些概念都非常重要。
              但這個問題怎么解決呢?答案是動態分配技術。注意這在C和C++中是不同的。由于大多數程序員都是用C++,所以我用到的是C++中常用的稱謂。


            動態分配

              動態分配是指針的關鍵技術。它是用來在不必定義變量的情況下分配內存和讓指針去指向它們。盡管這么說可能會讓你迷惑,其實它真的很簡單。下面的代碼就是一個為一個整型數據分配內存的例子:
            int *pNumber;
            pNumber = new int;
              第一行聲明一個指針pNumber。第二行為一個整型數據分配一個內存空間,并讓pNumber指向這個新內存空間。下面是一個新例,這一次是用double雙精型:
            double *pDouble;
            pDouble = new double;
              這種格式是一個規則,這樣寫你是不會錯的。
              但動態分配又和前面的例子有什么不同呢?就是在函數返回或執行完畢時,你分配的這塊內存區域是不會被刪除的所以我們現在可以用動態分配重寫上面的程序:
            #include <iostream.h>

            int *pPointer;

            void SomeFunction()
            {
            // 讓指針指向一個新的整型
            pPointer = new int;
            *pPointer = 25;
            }

            void main()
            {
            SomeFunction(); // 為pPointer賦值

            cout<<"Value of *pPointer: "<<*pPointer<<endl;
            }
              通讀這個程序,編譯并運行它,務必理解它是怎樣工作的。當SomeFunction 調用時,它分配了一個內存,并讓pPointer指向它。這一次,當函數返回時,新的內存區域被保留下來,所以pPointer始終指著有用的信息,這是因為了動態分配。但是你再仔細讀讀上面這個程序,雖然它得到了正確結果,可仍有一個嚴重的錯誤。


            分配了內存,別忘了回收

              太復雜了,怎么會還有嚴重的錯誤!其實要改正并不難。問題是:你動態地分配了一個內存空間,可它絕不會被自動刪除。也就是說,這塊內存空間會一直存在,直到你告訴電腦你已經使用完了。可結果是,你并沒有告訴電腦你已不再需要這塊內存空間了,所以它會繼續占據著內存空間造成浪費,甚至你的程序運行完畢,其它程序運行時它還存在。當這樣的問題積累到一定程度,最終將導致系統崩潰。所以這是很重要的,在你用完它以后,請釋放它的空間,如:
            delete pPointer;
              這樣就差不多了,你不得不小心。在這你終止了一個有效的指針(一個確實指向某個內存的指針)。
              下面的程序,它不會浪費任何的內存:

            #include <iostream.h>

            int *pPointer;

            void SomeFunction()
            {
            // 讓指針指向一個新的整型
            pPointer = new int;
            *pPointer = 25;
            }

            void main()
            {
            SomeFunction(); //為pPointer賦值
            cout<<"Value of *pPointer: "<<*pPointer<<endl;

            delete pPointer;
            } 

              只有一行與前一個程序不同,但就是這最后一行十分地重要。如果你不刪除它,你就會制造一起“內存漏洞”,而讓內存逐漸地泄漏。
              (譯者:假如在程序中調用了兩次SomeFunction,你又該如何修改這個程序呢?請讀者自己思考)

            傳遞指針到函數

              傳遞指針到函數是非常有用的,也很容易掌握。如果我們寫一個程序,讓一個數加上5,看一看這個程序完整嗎?:
            #include <iostream.h>

            void AddFive(int Number)
            {
            Number = Number + 5;
            }

            void main()
            {
            int nMyNumber = 18;

            cout<<"My original number is "<<nMyNumber<<endl;
            AddFive(nMyNumber);
            cout<<"My new number is "<<nMyNumber<<endl;
            //得到了結果23嗎?問題出在哪兒?
            }
              問題出在函數AddFive里用到的Number是變量nMyNumber的一個副本而傳遞給函數,而不是變量本身。因此, " Number = Number + 5" 這一行是把變量的副本加了5,而原始的變量在主函數main()里依然沒變。試著運行這個程序,自己去體會一下。
              要解決這個問題,我們就要傳遞一個指針到函數,所以我們要修改一下函數讓它能接受指針:把'void AddFive(int Number)' 改成 'void AddFive(int* Number)' 。下面就是改過的程序,注意函數調用時要用&號,以表示傳遞的是指針:
            #include <iostream.h>
            void AddFive(int* Number)
            {
            *Number = *Number + 5;
            }

            void main()
            {
            int nMyNumber = 18;

            cout<<"My original number is "<<nMyNumber<<endl;
            AddFive(&nMyNumber);
            cout<<"My new number is "<<nMyNumber<<endl;
            }


              試著自己去運行它,注意在函數AddFive的參數Number前加*號的重要性:它告訴編譯器,我們是把指針所指的變量加5。而不并指針自己加5。

              最后,如果想讓函數返回指針的話,你可以這么寫:
            int * MyFunction();
              在這句里,MyFunction返回一個指向整型的指針。


            指向類的指針

              指針在類中的操作要格外小心,你可以用如下的辦法定義一個類:
            class MyClass
            {
              public:
              int m_Number;
              char m_Character;
            };
              接著你就可以定義一個MyClass 類的變量了:
            MyClass thing;
              你應該已經知道怎樣去定義一個指針了吧:
            MyClass *thing;
              接著你可以分配個內存空間給它:
            thing = new MyClass;
              注意,問題出現了。你打算怎樣使用這個指針呢,通常你可能會寫'thing.m_Number',但是thing是類嗎,不,它是一個指向類的指針,它本身并不包含一個叫m_Number的變量。所以我們必須用另一種方法:就是把'.'(點號)換成 -> ,來看下面的例子:
            class MyClass
            {
            public:
            int m_Number;
            char m_Character;
            };

            void main()
            {
            MyClass *pPointer;
            pPointer = new MyClass;

            pPointer->m_Number = 10;
            pPointer->m_Character = 's';

            delete pPointer;
            }

            指向數組的指針

              你也可以讓指針指向一個數組,按下面的方法操作:
            int *pArray;
            pArray = new int[6];
              程序會創建一個指針pArray,讓它指向一個有六個元素的數組。另外一種方法,不用動態分配:
            int *pArray;
            int MyArray[6];
            pArray = &MyArray[0];
              注意,&MyArray[0] 也可以簡寫成 MyArray ,都表示是數組的第一個元素地址。但如果寫成pArray = &MyArray可能就會出問題,結果是 pArray 指向的是指向數組的指針(在一維數組中盡管與&MyArray[0]相等),而不是你想要的,在多維數組中很容易出錯。


            在數組中使用指針

              一旦你定義了一個指向數組的指針,你該怎樣使用它呢?讓我們來看一個例子,一個指向整型數組的指針:

            #include <iostream.h>

            void main()
            {
            int Array[3];
            Array[0] = 10;
            Array[1] = 20;
            Array[2] = 30;

            int *pArray;
            pArray = &Array[0];

            cout<<"pArray points to the value %d\n"<<*pArray<<endl;
            }

              如果讓指針指向數組元素中的下一個,可以用pArray++.也可以用你應該能想到的pArray + 1,都會讓指針指向數組的下一個元素。要注意的是你在移動指針時,程序并不檢查你是否已經移動地超出了你定義的數組,也就是說你很可能通過上面的簡單指針加操作而訪問到數組以外的數據,而結果就是,可能會使系統崩潰,所以請格外小心。
              當然有了pArray + 1,也可以有pArray - 1,這種操作在循環中很常用,特別是while循環中。
              另一個需要注意的是,如果你定義了一個指向整型數的指針:int* pNumberSet ,你可以把它當作是數組,如:pNumberSet[0] 和 *pNumberSet是相等的,pNumberSet[1]與*(pNumberSet + 1)也是相等的。
              在這一節的最后提一個警告:如果你用 new 動態地分配了一個數組,
            int *pArray;
            pArray = new int[6];
              別忘了回收,
            delete[] pArray;
              這一句是告訴編譯器是刪除整個數組而不一個單獨的元素。千萬記住了。


            后話

              還有一點要小心,別刪除一個根本就沒分配內存的指針,典型的是如果沒用new分配,就別用delete:

            void main()
            {
              int number;
              int *pNumber = number;

              delete pNumber; // 錯誤 - *pNumber 沒有用new動態分配內存.
            }

            常見問題解答

            Q:為什么我在編譯程序時老是在 new 和 delete語句中出現'symbol undefined' 錯誤?
            A:new 和 delete都是C++在C上的擴展,這個錯誤是說編譯器認為你現在的程序是C而不C++,當然會出錯了。看看你的文件名是不是.cpp結尾。

            Q:new 和 malloc有什么不同?
            A:new 是C++中的關健字,用來分配內存的一個標準函數。如果沒有必要,請不要在C++中使用malloc。因為malloc是C中的語法,它不是為面向對象的C++而設計的。

            Q:我可以同時使用free 和 delete嗎?
            A:你應該注意的是,它們各自所匹配的操作不同。free只用在用malloc分配的內存操作中,而delete只用在用new分配的內存操作中。


            引用(寫給某些有能力的讀者)

              這一節的內容不是我的這篇文章的中心,只是供某些有能力的讀者參考。
              有些讀者經常問我關于引用和指針的問題,這里我簡要地討論一下。
              在前面指針的學習中,我們知道(&)是讀作“什么的地址”,但在下面的程序中,它是讀作“什么的引用”

            int& Number = myOtherNumber;
            Number = 25;
              引用有點像是一個指向myOtherNumber的指針,不同的是它是自動刪除的。所以他比指針在某些場合更有用。與上面等價的代碼是:
            int* pNumber = &myOtherNumber;
            *pNumber = 25;
              指針與引用另一個不同是你不能修改你已經定義好的引用,也就是說你不能改變它在聲明時所指的內容。舉個例子:
            int myFirstNumber = 25;
            int mySecondNumber = 20;
            int &myReference = myFirstNumber;

            myReference = mySecondNumber;//這一步能使myReference 改變嗎?

            cout<<myFristNumber<<endl;//結果是20還是25?

              當在類中操作時,引用的值必須在構造函數中設定,例:

            CMyClass::CMyClass(int &variable) : m_MyReferenceInCMyClass(variable)
            {
              // constructor code here
            }


            總結

              這篇文章開始可能會較難掌握,所以最好是多讀幾遍。有些讀者暫時還不能理解,在這兒我再做一個簡要的總結:
              指針是一個指向內存區域的變量,定義時在變量名前加上星號(*)(如:int *number)。
              你可以得到任何一個變量的地址,只在變量名前加上&(如:pNumber = &my_number)。
              你可以用'new' 關鍵字動態分配內存。指針的類型必須與它所指的變量類型一樣(如:int *number 就不能指向 MyClass)。
              你可以傳遞一個指針到函數。必須用'delete'刪除你動態分配的內存。
              你可以用&array[0]而讓指針指向一個數組。
              你必須用delete[]而不是delete來刪除動態分配的數組。

              文章到這兒就差不多結束了,但這些并不就是指針所有的東西,像指向指針的指針等我還沒有介紹,因為這些東西對于一個初學指針的人來說還太復雜了,我不能讓讀者一開始就被太復雜的東西而嚇走了。好了,到這兒吧,試著運行我上面寫的小程序,也多自己寫寫程序,你肯定會進步不小的!

            posted on 2010-06-21 22:32 lhking 閱讀(361) 評論(0)  編輯 收藏 引用

            導航

            <2010年6月>
            303112345
            6789101112
            13141516171819
            20212223242526
            27282930123
            45678910

            統計

            常用鏈接

            留言簿

            隨筆檔案

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            中文字幕乱码人妻无码久久| 久久久精品久久久久特色影视| 国产欧美久久久精品影院| 欧美久久久久久午夜精品| 区亚洲欧美一级久久精品亚洲精品成人网久久久久 | 国产精品99精品久久免费| 欧美亚洲国产精品久久蜜芽 | 色综合久久夜色精品国产| 亚洲AV无码成人网站久久精品大| 国产综合久久久久久鬼色| 久久天天躁狠狠躁夜夜2020| 久久91精品国产91久| 久久国产乱子伦精品免费强| 色婷婷久久综合中文久久一本| 亚洲天堂久久久| 国产成人精品久久亚洲| 亚洲中文字幕无码久久精品1 | 亚洲伊人久久综合影院| 久久精品aⅴ无码中文字字幕重口| 亚洲午夜久久久精品影院| 久久久久亚洲AV成人网人人网站| 热久久这里只有精品| 香蕉久久久久久狠狠色| 国产精品嫩草影院久久| 国产成人久久精品激情| 国产香蕉久久精品综合网| 久久99精品久久久久久野外| 99久久er这里只有精品18| 亚洲午夜无码久久久久| 香蕉99久久国产综合精品宅男自 | 久久se这里只有精品| 久久99精品国产麻豆宅宅| 亚洲国产一成人久久精品| 亚洲精品久久久www| 欧美日韩精品久久久久| 久久久久无码中| 精品国产91久久久久久久a| 91久久精品国产免费直播| 97精品伊人久久久大香线蕉| 婷婷久久综合九色综合98| 国产精品一久久香蕉产线看 |