<kbd id="daqct"></kbd>

  • <nav id="daqct"></nav>
    <wbr id="daqct"><pre id="daqct"></pre></wbr>
    <wbr id="daqct"></wbr>
    <form id="daqct"><th id="daqct"></th></form>
    更多課程 選擇中心

    C/C++培訓
    達內IT學院

    400-111-8989

    1分鐘徹底理解C語言指針的概念

    • 發布:C++培訓
    • 來源:學習筆記
    • 時間:2017-06-06 17:50

    計算機中所有的數據都必須放在內存中,不同類型的數據占用的字節數不一樣,例如 int 占用4個字節,char 占用1個字節。為了正確地訪問這些數據,必須為每個字節都編上號碼,就像門牌號、身份證號一樣,每個字節的編號是唯一的,根據編號可以準確地找到某個字節。

    下圖是 4G 內存中每個字節的編號(以十六進制表示):


    我們將內存中字節的編號稱為地址(Address)或指針(Pointer)。地址從 0 開始依次增加,對于 32 位環境,程序能夠使用的內存為 4GB,最小的地址為 0,最大的地址為 0XFFFFFFFF。

    下面的代碼演示了如何輸出一個地址:

    1. #include<stdio.h>

    2. intmain(){

    3. inta=100;

    4. charstr[20]="c.biancheng.net";

    5. printf("%#X, %#X\n",&a,str);

    6. return0;

    7. }

    運行結果:
    0X28FF3C, 0X28FF10

    %#X表示以十六進制形式輸出,并附帶前綴0X。a 是一個變量,用來存放整數,需要在前面加&來獲得它的地址;str 本身就表示字符串的首地址,不需要加&。

    一切都是地址

    C語言用變量來存儲數據,用函數來定義一段可以重復使用的代碼,它們最終都要放到內存中才能供 CPU 使用。

    數據和代碼都以二進制的形式存儲在內存中,計算機無法從格式上區分某塊內存到底存儲的是數據還是代碼。當程序被加載到內存后,操作系統會給不同的內存塊指定不同的權限,擁有讀取和執行權限的內存塊就是代碼,而擁有讀取和寫入權限(也可能只有讀取權限)的內存塊就是數據。

    CPU 只能通過地址來取得內存中的代碼和數據,程序在執行過程中會告知 CPU 要執行的代碼以及要讀寫的數據的地址。如果程序不小心出錯,或者開發者有意為之,在 CPU 要寫入數據時給它一個代碼區域的地址,就會發生內存訪問錯誤。這種內存訪問錯誤會被硬件和操作系統攔截,強制程序崩潰,程序員沒有挽救的機會。

    CPU 訪問內存時需要的是地址,而不是變量名和函數名!變量名和函數名只是地址的一種助記符,當源文件被編譯和鏈接成可執行程序后,它們都會被替換成地址。編譯和鏈接過程的一項重要任務就是找到這些名稱所對應的地址。

    假設變量 a、b、c 在內存中的地址分別是 0X1000、0X2000、0X3000,那么加法運算c = a + b;將會被轉換成類似下面的形式:

    0X3000 = (0X1000) + (0X2000);

    ( )表示取值操作,整個表達式的意思是,取出地址 0X1000 和 0X2000 上的值,將它們相加,把相加的結果賦值給地址為 0X3000 的內存

    變量名和函數名為我們提供了方便,讓我們在編寫代碼的過程中可以使用易于閱讀和理解的英文字符串,不用直接面對二進制地址,那場景簡直讓人崩潰。

    需要注意的是,雖然變量名、函數名、字符串名和數組名在本質上是一樣的,它們都是地址的助記符,但在編寫代碼的過程中,我們認為變量名表示的是數據本身,而函數名、字符串名和數組名表示的是代碼塊或數據塊的首地址。

    C語言指針變量的運算

    指針變量保存的是地址,本質上是一個整數,可以進行部分運算,例如加法、減法、比較等,請看下面的代碼:

    1. #include<stdio.h>

    2. intmain(){

    3. int   a=10, *pa=&a,*paa=&a;

    4. doubleb=99.9,*pb=&b;

    5. char  c='@', *pc=&c;

    6. //最初的值

    7. printf("&a=%#X, &b=%#X, &c=%#X\n",&a,&b,&c);

    8. printf("pa=%#X, pb=%#X, pc=%#X\n",pa,pb,pc);

    9. //加法運算

    10. pa++;pb++;pc++;

    11. printf("pa=%#X, pb=%#X, pc=%#X\n",pa,pb,pc);

    12. //減法運算

    13. pa-=2;pb-=2;pc-=2;

    14. printf("pa=%#X, pb=%#X, pc=%#X\n",pa,pb,pc);

    15. //比較運算

    16. if(pa==paa){

    17. printf("%d\n",*paa);

    18. }else{

    19. printf("%d\n",*pa);

    20. }

    21. return0;

    22. }

    運行結果:

    &a=0X28FF44, &b=0X28FF30, &c=0X28FF2B pa=0X28FF44, pb=0X28FF30, pc=0X28FF2B pa=0X28FF48, pb=0X28FF38, pc=0X28FF2C pa=0X28FF40, pb=0X28FF28, pc=0X28FF2A 2686784

    從運算結果可以看出:pa、pb、pc 每次加 1,它們的地址分別增加 4、8、1,正好是 int、double、char 類型的長度;減 2 時,地址分別減少 8、16、2,正好是 int、double、char 類型長度的 2 倍。

    這很奇怪,指針變量加減運算的結果跟數據類型的長度有關,而不是簡單地加 1 或減 1,這是為什么呢?

    以 a 和 pa 為例,a 的類型為 int,占用 4 個字節,pa 是指向 a 的指針,如下圖所示:

    剛開始的時候,pa 指向 a 的開頭,通過 *pa 讀取數據時,從 pa 指向的位置向后移動 4 個字節,把這 4 個字節的內容作為要獲取的數據,這 4 個字節也正好是變量 a 占用的內存。

    如果pa++;使得地址加 1 的話,就會變成如下圖所示的指向關系:

    這個時候 pa 指向整數 a 的中間,*pa 使用的是紅色虛線畫出的 4 個字節,其中前 3 個是變量 a 的,后面 1 個是其它數據的,把它們“攪和”在一起顯然沒有實際的意義,取得的數據也會非常怪異。

    如果pa++;使得地址加 4 的話,正好能夠完全跳過整數 a,指向它后面的內存,如下圖所示:

    我們知道,數組中的所有元素在內存中是連續排列的,如果一個指針指向了數組中的某個元素,那么加 1 就表示指向下一個元素,減 1 就表示指向上一個元素,這樣指針的加減運算就具有了現實的意義,我們將在《C語言和數組》一節中深入探討。

    不過C語言并沒有規定變量的存儲方式,如果連續定義多個變量,它們有可能是挨著的,也有可能是分散的,這取決于變量的類型、編譯器的實現以及具體的編譯模式,所以對于指向普通變量的指針,我們往往不進行加減運算,雖然編譯器并不會報錯,但這樣做沒有意義,因為不知道它后面指向的是什么數據。

    下面的例子是一個反面教材,警告讀者不要嘗試通過指針獲取下一個變量的地址:

    1. #include<stdio.h>

    2. intmain(){

    3. inta=1,b=2,c=3;

    4. int*p=&c;

    5. inti;

    6. for(i=0;i<8;i++){

    7. printf("%d, ",*(p+i));

    8. }

    9. return0;

    10. }

    在 VS2010 Debug 模式下的運行結果為:

    3, -858993460, -858993460, 2, -858993460, -858993460, 1, -858993460,

    可以發現,變量 a、b、c 并不挨著,它們中間還參雜了別的輔助數據。

    指針變量除了可以參與加減運算,還可以參與比較運算。當對指針變量進行比較運算時,比較的是指針變量本身的值,也就是數據的地址。如果地址相等,那么兩個指針就指向同一份數據,否則就指向不同的數據。

    上面的代碼(第一個例子)在比較 pa 和 paa 的值時,pa 已經指向了 a 的上一份數據,所以它們不相等。而 a 的上一份數據又不知道是什么,所以會導致 printf() 輸出一個沒有意義的數,這正好印證了上面的觀點,不要對指向普通變量的指針進行加減運算。

    另外需要說明的是,不能對指針變量進行乘法、除法、取余等其他運算,除了會發生語法錯誤,也沒有實際的含義。

    預約申請免費試聽課

    填寫下面表單即可預約申請免費試聽!怕錢不夠?可就業掙錢后再付學費! 怕學不會?助教全程陪讀,隨時解惑!擔心就業?一地學習,可全國推薦就業!

    上一篇:一個C/C++程序是怎么從代碼到可執行文件的
    下一篇:C++語言中的內聯函數

    C語言創建windows窗口實例

    C++回調函數是什么?

    C++ shared_ptr和動態數組

    C語言有哪些關鍵詞,C語言44個關鍵詞大全

    • 掃碼領取資料

      回復關鍵字:視頻資料

      免費領取 達內課程視頻學習資料

    • 視頻學習QQ群

      添加QQ群:1143617948

      免費領取達內課程視頻學習資料

    Copyright ? 2021 Tedu.cn All Rights Reserved 京ICP備08000853號-56 京公網安備 11010802029508號 達內時代科技集團有限公司 版權所有

    選擇城市和中心
    黑龍江省

    吉林省

    河北省

    湖南省

    貴州省

    云南省

    廣西省

    海南省

    欧美三级片,白洁外传,第四色播日韩AV第一页,啪啪免费观看大全av 百度 好搜 搜狗
    <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>