c語言大殺器——指標詳解__c語言

來源:互聯網
上載者:User

一、指標

1、指標的概念:用來儲存地址的“變數”叫做指標,可以理解成指標是地址的一個別名。


例:定義一個整形指標


2、“指標的內容”,“指標所指向的內容”,“指標變數的地址”

  (1)、指標的內容:

    指標變數p裡面存放的是a的地址,也就是0x0018ff44.

  (2)、指標所指向的內容:

    指標變數p裡面存放的地址(0x18ff44)這塊空間所對應的值,也就是10,我們通過*p(解引用)可以訪問到這個值。即:*p作為右值時,*p==10,當*p作為左值時代表的就是a這塊空間。

  (3)、指標的地址:

    指標p本身有一個地址,由編譯器分配的我們不知道,注意:不要講指標變數p本身的地址和p所儲存的地址(0x0018ff44)相混淆。


3、"未初始化的指標"和"NULL指標"

例:定義兩個指標變數p1和p2:

int *p1;              //未初始化的指標

int *p2=NULL;         //null 指標

*p1=10;

*p2=10;

這樣賦值顯然是錯誤的,為什麼呢。。。

  試想一下,p1,p2是一個指標變數,所以p1,p2裡面應該存放的應該是一個地址。而對於p1我們沒有往裡面放地址,這時p1是隨機指向的。如果此時解引用*p1,訪問到的是塊隨機的地址,再修改這個隨機地址裡面的值,假設這個隨機空間裡面的值非常重要,那你就再也找不回來了,所以通常定義一個指標就將他初始化為NULL。

對於p2:雖然我們將它初始化為NULL,但它指向的是一塊空地址啊。。。向一塊空地址裡面放東西,根本是不可能的。


4、指標常量:

例:*(int *)200=10;

相信很多人對這個表達是都會產生疑惑,其實很好理解的,200是一個常數,我們將它強制轉化為 int *(也就是將常數200轉化成一個整形地址),再對這塊地址進行*引用,就訪問到一塊空間,可以對這塊空間進行賦值。


5、常量指標

例:int *p=&100;

讓指標指向一個常量,一般用不到。


二、進階指標


1、二級指標概念:

  什麼是指標。。。存放地址的變數就叫做指標,所以二級指標就是存放一級指標地址的指標變數。

注意:跟一級指標一樣,二級指標變數p2裡面存放的是一級指標變數p1的地址,一級指標變數p1裡面存放的是a的地址。要想訪問一塊地址裡面的內容可以使用間接訪問符“*”,所以:

*p2==&p1, *p2就是訪問p2這塊空間裡面存放的地址所對應的內容。

**p2==10,因為*p2得到的結果是p1的地址,在對p1的地址進行解引用*p1就訪問到了10.


  例1:分析下面幾種情況下能不能作為可修改的左值(可修改的左值必須代表一塊空間)

int a=10;

int *cp=&a;


  (1)*cp=20 //可以作為左值,當cp指向a時,*cp放到等號左邊代表a這塊空間,當*cp放到等號右邊代表a這塊空間的值。


  (2)&a=20  //錯誤,&a不可以作為左值,因為他不能表示一塊特定的空間,&a得到的結果是a的地址,但並不代表a這塊空間,要想使用這塊空間,必須進行*引用,*&a=20正確。&a可以作為右值,代表是a的地址這個數值。


  (3)*cp+1     //不可以作為左值,因為*優先順序高於+,所以*cp先結合,再加1相當於10+1,不代表一塊空間。


  (4)*(cp+1)   //可以作為左值,cp+1先結合,指向a的下一塊空間,再對這塊空間進行*引用,放在等號左邊就代表這塊空間。


  (5)++cp  //不可以作為左值,因為++cp只是將cp裡面的內容加一,並沒有進行*引用


  (6)cp++  //不可以作為左值


  (7)*cp++   //可以作為左值,先對cp裡面的地址進行*引用。再讓cp=cp+1(也就是讓cp指向a的下一塊空間,因為++優先順序高於*)


  (8)++*cp   //不可以作為左值,*cp代表cp所指向的內容,再讓其加一,相當於10+1

注意:C中++cp和--cp都不能做左值,C++中++cp可以作為左值。


  例2:const 修飾一級指標,修飾二級指標(const修飾的變數,還是一個變數,只不過只是可讀的 )

int const a=10;

int b=30;

  1、a=20;   //錯誤,const修飾a,所以不能改變a的值


  2、int const *p; //const修飾的是*p,所以不能改變*p

    p=&a;       //正確  

    *p=20;      //錯誤 不能通過*p改變a的值


  3、const int *p;    //const修飾的是*p

    p=&a;       //正確      

    *p=20;      //錯誤


  4、int *const p=&a;    //const修飾的是p

     p=&b;          //錯誤   不能改變p

     *p=20;         //正確     


  5、int const * const p;  //const修飾*p,也修飾p,所以*p,p都不能改變

     p=&b;        //錯誤     

     *p=20;       //錯誤

注意:const修飾變數的原則是離誰近修飾誰。const int *p與int const *p完全一樣。


2、指標和數組的關係 ,指標數組,數組指標,指標的運算


  2.1、指標和數組的關係:

    很多人都分不清指標和數組之間的關係,嚴格的來講指標和數組之間沒關係,指標是指標,數組是數組。只不過他們兩個都可以通過“*”引用的方式和下標的方式來訪問元素而已。


例1:

int a[5]={1,2,3,4,5};

int *p=a;

  a[5]佔20個位元組的大小,而p只佔4個位元組的大小,其次p本身有自己的地址,只不過他裡面存放的是數組首元素的地址。

要訪問3則有兩種方式:a[2]或者*(a+2).

  其中*(a+2)就是*的形式訪問的,因為a表示首元素的地址,加2表示向後位移2個整形大小,找到3的地址,在通過*得到3.

在編譯器中a[2]會被先解析成*(a+2)訪問的。


例2:

所以必須保持定義和聲明的一致性,指標就是指標,數組就是數組。


3、指標數組,數組指標

注意:[]的優先順序高於*,指標數組是一個數組,只不過裡面的元素全部都是指標。數組指標是一個指標,指向數組的指標,位移的單位是整個數組。


例1:

int a[6]={1,2,3,4,5,6};

int (*p2)[6];

p2=a;

  這是錯誤的,因為指標p2的類型是int [6],所以應該是p2=&a;

int (*p2)[3];

  這樣的話p2的類型是int [3],所以p2=(int(*) [3])&a;  要強制轉換成數組指標的類型。

注意:數組指標“所指向”的類型就是去掉指標變數之後所剩下的內容。

數組指標的類型就是去掉指標後剩下的內容。


例2:int (*p3)[5];

  p3的類型是 int(*)[5];

  p3所指向的類型是 int [5];


4、指標的運算:

   1、指標相減得到的結果是兩指標之間元素的個數,而不是位元組數。

   2、指標的運算

例1:

struct test

{

int name;

char *pcname;

short data;

char c[2];

}*p;

   假設p的值是0x100000,結構體的大小是12;

則:

  1、 p+0x1=0x10000c    //p指向結構體 則p+1表示的是p+sizeof(test)*1


  2、(unsigned int)p+0x1=0x100001     //p已經被轉化為一個無符號的數,加一就相當於兩個數相加


  3、(int *)p+0x1=0x100004            //p被轉化為int *,所以p+1就表示p+sizeof(int *)*1


例2:假設當前機器小端儲存

   int a[4] = { 1, 2, 3, 4 };

   int *p = (int *)(a + 1);

   int *p1 = (int *)(&a + 1);

     int *p2 = (int *)(( int)&a + 1);

     printf( "*p=%d,*p1=%d,*p2=%d\n" , *p, p1[-1],*p2);


     輸出結果:*p=2,*p1=4,*p2=2000000 

解析:p = (int *)(a + 1); a代表首元素地址,加1指向第二個元素,所以是2.

     p1 = (int *)(&a + 1); &a表示數組的地址,&a+1就相當於&a+sizeof(a),p1指向的就是a[3]後面的地址,p1[-1]被解析成*(p1-1),所以是4.

     p2 = (int *)(( int)&a + 1); (int)&a是把數組的地址取出來再轉化為一個int類型的數再加1,這時的加1就相當於兩個數相加(效果相當於讓&a向後位移一個位元組),相加的結果再轉化成(int *)地址,使p2指向這個地址。

     當前數組的儲存:01 00 00 00 02 00 00 00 ........... 因為&a指向的是01這個位元組的位置,(int)&a+1的結果是指向了01的下一個位元組,這時在強制類型轉換成int *,則p2這時指向的空間的內容就是 00 00 00 02,因為是小端儲存,所以大端就是 02 00 00 00,輸出後就是2000000.

<

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.