1. 程式人生 > >C之指針(二十四)

C之指針(二十四)

C語言 指針

在 C 語言中用的最多的就是指針了,指針同樣也是 C 語言的精華所在了。我們今天就來看看指針到底是什麽,它是如何使用的。

我們先來回想下變量,在程序中的變量只是一段存儲空間的別名,那麽是不是必須要通過這個別名才能使用這段存儲空間呢?答案肯定不是的,我們還可以通過指針來使用這段存儲空間。在指針聲明時,* 號表示所聲明的變量為指針。在指針使用時,* 號表示取指針所指向的內存空間中的值。我們通過下面這幅圖可以更加直觀的看出他們的關系

技術分享圖片

通過這個圖片我們是不是更加直觀的看出它們的關系呢。上面即表示的是變量 p 保存著變量 i 的內存地址,即 p <--> &i; *p <--> i

下來我們通過示例代碼進行分析說明,代碼如下

#include <stdio.h>

int main()
{
    int i = 0;
    int* pI;
    char* pC;
    float* pF;
    
    pI = &i;
    
    *pI = 10;
    
    printf("%p, %p, %d\n", pI, &i, i);
    printf("%d, %d, %p\n", sizeof(int*), sizeof(pI), &pI);
    printf("%d, %d, %p\n", sizeof(char*), sizeof(pC), &pC);
    printf("%d, %d, %p\n", sizeof(float*), sizeof(pF), &pF);
    
    return 0;
}

我們在678行分別定義了 int* char* float* 類型的指針,在第10行通過指針 pI 指向了 i 的地址,再通過第12行的取指針的內容並賦值來達到改變 i 的值。那麽我們接下來打印下指針 pI 的地址,i 的地址還有 i 的值分別是什麽。還有看下三種不同類型的指針所占的內存大小和地址各是什麽,編譯結果如下

技術分享圖片

那麽我們看到指針 pI 和 i 的地址相同,並且 i 的值已經通過指針成功改變為10。接著我們看到不管是什麽類型的指針所占的內存大小都是4,並不是我們之前所認為的 int 為4,char 為1,float 為4啦,它們的地址連續著。說明指針在內存中並沒有類型之分,所存儲的內存都是在同一個段上。

我們接下來再來看個傳值調用和傳址調用。那麽在程序中,指針也是變量,因此可以聲明指針參數。當一個函數體內部需要改變實參的值,則需要使用指針參數。函數調用時實參值將復制到形參,指針適用於復雜數據類型作為參數的函數中。我們下來利用示例代碼進行說明傳值調用和傳址調用的區別,代碼如下

#include <stdio.h>

int swap(int a, int b)
{
    int c = a;
    
    a = b;
    
    b = c;
}

int main()
{
    int aa = 1;
    int bb = 2;
    
    printf("aa = %d, bb = %d\n", aa, bb);
    
    swap(aa, bb);
    
    printf("aa = %d, bb = %d\n", aa, bb);
    
    return 0;
}

我們想當然是 swap 函數能完成兩個數交換的功能,我們來編譯下,看看是否能交換呢?

技術分享圖片

結果是這樣的,臥槽,是我們搞錯了嘛。看來看去覺得程序就該這麽寫啊,我們再來仔細分析下。我們在第19行只是將變量 aa 和 bb 的值復制給了 swap 函數的實參 a 和 b。在 swap 函數內部確實完成 a 和 b 的值交換,但只是 a 和 b 的值交換了而已。換句話說,這時他兩跟變量 aa 和 bb 沒啥關系,我們這種就屬於傳值調用。我們再將 swap 函數改成下面這樣呢?看看結果如何

int swap(int* a, int* b)
{
    int c = *a;
    
    *a = *b;
    
    *b = c;
}

再將 main 函數中第19行改成 swap(&aa, &bb); 我們來看看編譯結果如何

技術分享圖片

我們看到加了個 * 號,竟然神奇般改變了 aa 和 bb 的值。感覺很神奇啊,我們仔細分析下,這就是屬於利用指針指向變量 aa 和 bb 的地址,然後再通過 * 取地址處的內容再賦值改變。這樣就是我們所說的傳址調用啦。

我們下來再來看看一個筆試面試中經常會問到的問題:a> const int* p;b> int const* p;c> int* const p;d> const int* const p 四種有什麽區別。我們來一一分析:a> p 可變但它指向的內容不可變;b> p 可變但它指向的內容不可變;c> p 不可變但它所指向的內容是可變的;d> p 和它所指向的內容都是不可變的。我們對待這種問題有個口訣就是:左數右指。什麽意思呢?就是當 const 出現在 * 號左邊時指針指向的數據為常量,當 const 出現在 * 號右邊時指針本身為常量。這樣是不是就很好記了呢?反正博主是記住了哈。

我們下來再來個示例代碼對其進行說明,代碼如下

#include <stdio.h>

int main()
{
    int i = 0;
    
    const int* p1 = &i;
    int const* p2 = &i;
    int* const p3 = &i;
    const int* const p4 = &i;
    
    *p1 = 1;    // compile error
    p1 = NULL;  // ok
    
    *p2 = 2;    // compile error
    p2 = NULL;  // ok
    
    *p3 = 3;    // ok
    p3 = NULL;  // compile error
    
    *p4 = 4;    // compile error
    p4 = NULL;  // compile error
    
    return 0;
}

我們看到第12行明顯會出錯,因為 const 出現在 * 號的左邊,左數右指嘛,就是它所指向的內容是不可變的。第15行也是同樣的錯誤。第19行則是因為 p3 是 const 出現在 * 號的右邊,所以它本身不可變。p4 前後都有 const,所以第21、22行均會出錯。我們來看看分析是否正確呢

技術分享圖片

我們看到結果與我們分析的是一致的,我們以後遇到這種筆試面試題豈不是送分題啦?哈哈,開個玩笑了,其實還是很簡單的只需記住口訣就好。我們看看指針是否是那樣傳說中的難呢?其實也不難的。通過對指針的學習,我們總結如下:1、指針是 C 語言中一種特別的變量;2、指針所保存的值是內存的地址;3、可以通過指針修改內存中的任意地址內容。


歡迎大家一起來學習 C 語言,可以加我QQ:243343083

C之指針(二十四)