1. 程式人生 > >C指標的值和地址 [李園7舍_404]

C指標的值和地址 [李園7舍_404]

   在C語言中,函式傳參分為兩種:傳址和傳值。
   傳值是一個複製的過程。
   傳址對於變數和物件來說是傳址,而針對於同一級的指標來說也是傳值。傳址針對的物件是指標指向的物件,此時對指標的一切行為都是為了間接的操作指標所指向的物件。但如果想要操作指標本身的內容值,那麼就需要在指標層面再往下一層,讓指標本身上升為變數的地位,讓深一層的指標( 二級指標 )指向指標變數,二級指標在函式引數作為輸出引數時用得較廣。

1 指標和指向的變數

      指標是C語言資料型別中一種獨立的資料型別:指標型別。作為C語言的精華,當定義一個指標變數時,此變數的作用就是用來存相應資料結構(變數、函式)的地址。然後通過變數的地址(指標變數的值)取地址內容的方式(*

指標變數)訪問(讀、寫)相應的變數。

如定義一個整形變數和一個整形指標,用指標指向整形變數。

int i;
i = 1;
int *p = NULL;
p = &i;
*p = 2;       

       此小段程式的功能就是通過指標p訪問所指向的i,並通過p改變了所指向的變數i的內容。p地址通過取地址內容符*就能訪問地址中存的變量了(變數作為地址的內容)。

它們的關係如下i, p的關係如下:

圖1 指標和變數

        指標本身作為一個變數,也有自己的地址。指標作為一種特殊的變數作用是用來存地址,指標獲取資料結構的地址之後可以通過指標變數訪問(讀寫)到對應的資料結構。通過*p的形式訪問的是變數,改變的是指標存的內容中的內容

。如上圖中,*p = 2;時是通過指標p改變的0x0001(指標值)中的i(0x0001地址中存的內容)的值。

2 改變指標的內容

     試想一下,在外定義一個指標變數p1,並將它指向某個變數( var )。當向函式傳遞一個一級指標時,它傳遞給函式指標引數p2的是var變數的地址,如果在函式內對p2操作的程式碼是*p2( 訪p2地址中的內容 ),那麼所涉及的內容都是var變數;如果在函式內對p2的操作程式碼是p2,如p2 = var1( 另一個變數 ),那麼只能代表p2指向的目標變數發生了變化,p2的值也發生了變化。綜上,對p2的任何操作都跟外部定義的指標p1無關,p1不會受到任何影響

2.1指標內容和指標指向的內容(變數)

       指標內容是指指標的值,是指標指向內容的地址(如i的地址0x0001)。指標指向的內容是指指標指向的那個變數(如p指向的是變數i)。

2.2 通過指標賦值的形式改變指標內容

        同類型的指標可以相互賦值。被重新賦值的指標內容就會被改變,然後就可以訪問到新指標內容的變數。

int i = 1;
int j = 2;
int *p1 = NULL, *p2 = NULL;
p1 = &i;
p2 = &j;
p1 = p2;
//Do something

 原本p1指向i,存i的地址;p2指向j,存j的地址;p1=p2時,兩個指標指向同一塊記憶體,都是存的變數j的地址,兩個指標都可以訪問到變數j

這是兩個指標在同一個作用域內指標內容改變的形式:指標賦值即可改變。

那麼如何讓一個函式來改變指標的值呢?

2.3 將指標作為函式引數改變指標內容

傳址函式 void fun(int *p);

根據圖1知,呼叫函式fun(p);//(p = &i)

       形參為地址(指標)時,函式傳參為傳址方式即將指標的內容(一個變數的地址)傳了進去。然後通過*p(函式引數)操作的都是傳進來那個地址所存的變數,而對於這個函式來說,此地址對應的變數的作用域和生存期都還在,這樣就間接的操作了傳進地址中存的變數,改變的當然是變數(p所指向的變數i了),但未能改變實參指標p的內容(指標內容)。

        所以,如果要改變指標的內容且通過將自己作為函式的引數來實現,那就要使作用域比傳入指標變數作用域小的指標訪問傳入指標的指標內容(說起來有點繞)。圖示記錄


圖2 二級指標和指標關係

所以,經過fun(&p1)之後,p1指標內容自然就被改變指向變數j了。這樣就實現了指標作為函式引數傳入後指標內容被改變。此種方式在程式設計的時候可以採用的^-^。需要做到的一點就是讓外部指標的地址作為函式指標引數的值,即函式指標引數在一級指標(*p)形式下所訪問的是外部指標變數。函式指標引數的二級指標(**p)形式才是訪問外部指標所指向的變數。

C Note Over。