日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

  • 
    		
    當(dāng)前位置:首頁 > > 大魚機器人
    [導(dǎo)讀]指針是什么? 指針和其他的int, float等類似, 是一種類型. 有類型就有相應(yīng)類型的變量和常量. 本文主要討論變量的情況. 指針變量就是一種變量, 和其他種類的變量類似, 但指針和其他變量又有區(qū)別. 首先C語言作為一種類型語言, 每個變量都會有幾個屬性. 變量名稱.

    指針是什么?


    指針和其他的int, float等類似, 是一種類型. 有類型就有相應(yīng)類型的變量和常量. 本文主要討論變量的情況.

    指針變量就是一種變量, 和其他種類的變量類似, 但指針和其他變量又有區(qū)別.

    首先C語言作為一種類型語言, 每個變量都會有幾個屬性.


    • 變量名稱.
    • 變量類型.
    • 變量的值.

    例如int a = 3, 變量名稱就是a, 變量類型是int, 變量的值是3, 如果不提供初始值, 那么變量的值可能是一個隨機值.
    也就是說, 任何時候看到一個變量, 就會有這3個屬性.
    對于指針變量, 可以認為有4個屬性.

    • 指針變量的名稱.
    • 指針變量的類型, 即指針類型.
    • 指針變量的值, 即一個地址.
    • 指針變量的值所指向的內(nèi)存里的數(shù)據(jù)類型. 本文稱做"指向類型".

    可以看到指針變量的關(guān)鍵在于指針?biāo)赶虻膬?nèi)存里面數(shù)據(jù)的類型.

    例如 int a = 3; int *b = &a;

    指針變量名稱是b, 指針變量類型是指針, 變量b的值是變量a的內(nèi)存地址. 變量b所指向的內(nèi)存的數(shù)據(jù)類型是int. 

    指針變量多了一個"變量b所指向的內(nèi)存的數(shù)據(jù)類型是int”, 本文將指針變量所指向的內(nèi)存的數(shù)據(jù)類型稱做指向類型.

    任何時候看到一個指針就需要關(guān)注4點內(nèi)容: 名稱, 指針類型, 指針值, 指向類型. 搞清楚這幾個內(nèi)容, 就可以弄明白指針怎么回事, 當(dāng)然還要記憶 一些例外的情形.

    類型

    對于C語言來說, 搞清楚變量的類型相當(dāng)重要, 涉及到指針的時候就更加重要. 看到一個指針變量后需要理解其指向類型.

    例如 char * const * (*next)(), next是一個指針, 那么其指向類型是什么? 這個聲明/定義比較復(fù)雜, 日常編程可能就會碰到比較 復(fù)雜的情況, 所以要搞清楚指針首先要懂得怎么看一個聲明/定義的變量的類型.

    如果看到一個變量的聲明或者定義, 那么就需要弄明白變量的類型. 在 <<c專家編程>>這本書中有一部分內(nèi)容專門講解怎么分析 一個變量的類型, 值得參考.
    理解類型的規(guī)則

    1. 從變量名稱開始讀取, 然后依照優(yōu)先級按順序處理.
    2. 優(yōu)先級從高到低 a. 括號內(nèi)優(yōu)先級高. b. 后綴操作符, ()表示一個函數(shù), []表示一個數(shù)組. c. 前綴操作符,  *表示"指向...的指針"
    3. 如果const, volatile后面為類型(int, long等), 那么作用于類型, 其他情況下作用于const, volatile左邊的指針 *.

       
    char * const * (*next)()
    按照上面的規(guī)則來理解next的類型

    1. 括號內(nèi)的優(yōu)先級最高, 即首先看 (*next)
    2. next左邊為 * , 因此next是一個指針類型
    3. 然后后綴()的優(yōu)先級更高, 因此next是一個指針, 指向一個函數(shù).
    4. 接著是const右邊的 * , 表示next是一個指針, 指向一個函數(shù), 該函數(shù)返回值類型為一個指針.
    5. char * const 看作一個整體為指向字符的常量指針.

    整個來說: next是一個指針, 指向一個函數(shù), 函數(shù)的返回值也是一個指針, 指向一個類型為char的常量指針.
    更詳細的可以參考 <<c專家編程>>

    類型有什么用?

    C語言為類型語言, 即每個變量都有類型. 類型在變量的賦值, 函數(shù)傳參, 編譯檢查等等方面都會用到.
    類型可以確定數(shù)據(jù)的大小和操作.
    例如 int a = 3, 那么在內(nèi)存中會存儲一個數(shù)據(jù)3, 那么對于int類型具體來說.

    1. 這個數(shù)據(jù)3會占用4字節(jié)(常見32位機器與64位機器上int類型占用4字節(jié)). 實際上是有4字節(jié)的內(nèi)存, 內(nèi)容是0×00000003. 因此int類型就規(guī)定了占用的內(nèi)存大小.
    2. 對于int類型就可以進行+,-,*,/等操作, 但是不能進行取指針值(*a)的操作. 能夠進行什么操作, 也是由類型規(guī)定的.

    那么對于指針來說, 其指向類型就非常重要, 指向類型就規(guī)定了指針的值所指向的內(nèi)存的數(shù)據(jù)是什么類型, 也就是占用多大內(nèi)存, 可以進行什么操作.

    sizeof

    只要類型確定, 那么便可以用sizeof計算類型占用的內(nèi)存大小, 這個是編譯階段便可以確定的.

    對于指針類型來說, 所有指針類型占用的內(nèi)存大小基本都是一樣的, 例如在32bit的機器上占用4字節(jié), 在64bit的機器上占用8字節(jié).

    下面代碼的變量a和變量b都是指針類型, 但是指向類型不同. 因此sizeof(a)和sizeof(b)的值相等, 但是sizeof(*a)和sizeof(*b)不相等.

       
    int *a;
    double *b;

    sizeof(a) == sizeof(b);
    sizeof(*a) != sizeof(*b);

    指針類型的操作

    可以對指針變量進行 +操作.
       
    double a[3] = {1, 2, 3};
    double *b = a;

    printf("b: %p, content: %f\n", b, *b);
    printf("b+1: %p, content: %f\n", b+1, *(b+1));

    int c[3] = {1, 2, 3};
    int *d = d;

    printf("d: %p, content: %d\n", d, *d);
    printf("d+1: %p, content: %d\n", d+1, *(d+1));

    運行結(jié)果
       
    b: 0x7fff5f9ec7e0, content: 1.000000
    b+1: 0x7fff5f9ec7e8, content: 2.000000
    d: 0x7fff5f9ec7d0, content: 1
    d+1: 0x7fff5f9ec7d4, content: 2

    可以看到b+1的值比b要大8. d+1的值比b要大4. b+1實際上是指向a[1]的內(nèi)存地址. d+1是指向c[1]的內(nèi)存地址.

    有如下公式成立, 指針做加法后的指針變量值和指向類型占用的內(nèi)存大小相關(guān).
    指針變量 + 數(shù)字 = 指針變量值 + 數(shù)字 * sizeof(指向類型)

    可以看到指向類型除了告訴你指針指向的內(nèi)存里面的數(shù)據(jù)類型, 在指針變量的相關(guān)運算上也是有用的.

    數(shù)組類型

    數(shù)組與指針有一定的相似, 同時又很不一樣.

    數(shù)組與指針的關(guān)鍵區(qū)別在于數(shù)組名是一個常量(和const常量不同). const常量表示變量的內(nèi)容不會變化, 實際上還是一個變量. 這里所說的數(shù)組名為一個常量, 可以理解數(shù)組名稱是一個內(nèi)存地址值, 例如0×7fff5f9ec7d4.

    以下面的例子來說, a本身不會占用內(nèi)存, 占用內(nèi)存的是a[0], a[1], a[2], 實際上a所表示的這塊內(nèi)存才是數(shù)組變量.

       
    int a[10] = {0};
    int *b = a;
    int (*d)[10]= &a;
    int c;

    c = a[1];
    c = b[1];

    那么 a[1]b[1]的區(qū)別就在于數(shù)組是一個常量, 而不是變量(變量本身需要占用內(nèi)存).

    執(zhí)行 c = a[1]是直接從a表示的內(nèi)存地址偏移4字節(jié)的內(nèi)存中取數(shù)據(jù). 僅包含一次內(nèi)存讀操作.

    執(zhí)行 c = b[1]是首先從內(nèi)存中取出變量b的值, 然后將變量b的值偏移4字節(jié), 然后從這個地址的內(nèi)存中取數(shù)據(jù). 包含2次內(nèi)存讀操作. 第一次是讀取變量b的值.
    數(shù)組的其他幾個需要注意的地方。

    1. 數(shù)組名稱相當(dāng)于地址常量, 那么這個地址指向一段內(nèi)存, 因此這個地址本身會有指向類型, 其指向類型就是數(shù)組的元素類型. 例如 int a[10] , 那么a的指向類型就是 int , 因此a+1結(jié)果實際上指向a[1].
    2. sizeof(a) 是計算整個數(shù)組的類型.  sizeof(*a) 是計算其指向類型的大小.

    3. 可以對數(shù)組名進行 &a 操作(取地址), 實際上 &a 的指針值和a的指針值一樣, 而且也是個地址常量, 但是 &a 的指向類型 是 int [10] , 即指向一個包含10個int元素的數(shù)組, 所以 sizeof(*&a) , 計算&a的指向類型的占用內(nèi)存大小就是40.
    4. 數(shù)組作為函數(shù)參數(shù)傳遞后, 在函數(shù)內(nèi)使用等價于指針. 因為函數(shù)傳參是進行值傳遞, 相當(dāng)于有一個指針變量記錄數(shù)組的地址值.

    可以看到有的時候a看作一個數(shù)組(例如sizeof(a)是計算數(shù)組的內(nèi)存占用), 有時候a看作一個地址常量(例如計算sizeof(*a)和a+1的時候). 

    還有的時候完全是比較特殊的使用(例如&a得到的指向類型為int [10]的地址常量).

    函數(shù)指針

    函數(shù)名本身也是一個地址常量, 其指向類型為一個函數(shù). 實際指向的是函數(shù)在內(nèi)存中的指令集合的起始位置.

       
    int foo(int a)
    {
    return a;
    }

    int (*p_foo)(int a) = foo;

    printf("%d, %d, %d\n", sizeof(foo), sizeof(*foo), sizeof(&foo));
    printf("%d, %d\n", sizeof(p_foo), sizeof(*p_foo));

    輸出值如下:
       
    1, 1, 8
    8, 1

    1. 對函數(shù)名本身計算類型占用內(nèi)存大小, 其值為1, 對于函數(shù)名的指向類型計算內(nèi)存占用大小其值也為1.
    2. foo, *foo, &foo的類型相同, 但是sizeof(&foo)結(jié)果為8.
    3. 函數(shù)指針可以進行多次解引用,  *****p_foo == *p_foo = p_foo.
    4. 函數(shù)指針可以進行調(diào)用,  p_foo(3);

    以上幾點可以認為是函數(shù)的特殊情形, 直接記憶.
    可以將函數(shù)的指令看作是一個unsigned char []的數(shù)組. 這樣函數(shù)名就好像是一個數(shù)組名一樣, 都是地址常量, 其指向類型為unsigned char類型. 但是函數(shù)指令的數(shù)組的長度是未知的, 因此編譯器默認輸出sizeof(foo)為1, sizeof(*foo)相當(dāng)于是sizeof(unsigned char)為1.

    強制類型轉(zhuǎn)換

    很多時候涉及到指針和強制類型轉(zhuǎn)換就會感覺比較麻煩, 實際上只要抓住類型這個關(guān)鍵點也可以很簡單.
    強制類型轉(zhuǎn)換的關(guān)鍵是一段內(nèi)存, 這段內(nèi)存里面的數(shù)據(jù)你把它當(dāng)作什么類型來看待.
       
    double a = 23.456;
    int *b = (int *) &a;
    那么變量a有一段內(nèi)存(8個字節(jié)), 里面存儲了23.456(按標(biāo)準浮點格式存儲). 然后指針b指向這段內(nèi)存, 而且指針b的指向類型是int, 因此指針b認為這段內(nèi)存里面存儲的是一個int類型的數(shù)據(jù).

    小結(jié)

    本文內(nèi)容不算全面, 但關(guān)鍵點都有.
    每次看到指針的時候, 記住4個特征, 不管如何進行類型轉(zhuǎn)換, 多少級指針, 是否包含函數(shù)指針等, 看到指針 就思考下面4點, 尤其是3,4. 練習(xí)多了之后就會發(fā)現(xiàn)指針本身不是很難, 難的是怎么判斷數(shù)據(jù)的類型.

    1. 指針名稱
    2. 指針類型
    3. 指針內(nèi)容: 指向什么地方.
    4. 指向類型: 指向內(nèi)存的數(shù)據(jù)類型是什么.
    -END-

    猜你喜歡

    看完這篇文章,還不會做平衡小車,你來打我。
    為什么在中國電子工程師不如搞軟件的?
    博士學(xué)歷真的很重要嗎?

     最 后   
     

    若覺得文章不錯,轉(zhuǎn)發(fā)分享,也是我們繼續(xù)更新的動力。
    5T資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,PCB、FPGA、DSP、labview、單片機、等等!
    在公眾號內(nèi)回復(fù)「 更多資源 」,即可免費獲取,期待你的關(guān)注~
    長按識別圖中二維碼關(guān)注

    免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

    本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
    關(guān)閉