0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

二級(jí)指針和多級(jí)指針的定義形式

C語言編程學(xué)習(xí)基地 ? 來源:C語言編程學(xué)習(xí)基地 ? 作者:C語言編程學(xué)習(xí)基地 ? 2022-10-18 16:38 ? 次閱讀

二級(jí)指針 (多級(jí)指針)

指針變量作為一個(gè)變量也有自己的存儲(chǔ)地址,而指向指針變量的存儲(chǔ)地址就被稱為指針的指針,即二級(jí)指針。依次疊加,就形成了多級(jí)指針。指針可以指向一份普通類型的數(shù)據(jù),例如 int、double、char 等,也可以指向一份指針類型的數(shù)據(jù),例如 int *、double *、char * 等。如果一個(gè)指針指向的是另外一個(gè)指針,我們就稱它為二級(jí)指針,或者指向指針的指針。,我們先看看二級(jí)指針,它們關(guān)系如下:

int a =100;//一個(gè)普通變量
int *p1 = &a;//一個(gè)一級(jí)指針p1指向a變量的地址
int **p2 = &p1;//一個(gè)二級(jí)指針p2指向p1指針的地址
//  p2   ->   p1   ->   a
//  &p1       &a       100


/*規(guī)律:
一級(jí)指針 指向變量的地址
二級(jí)指針 指向一級(jí)指針的地址
三級(jí)指針 指向二級(jí)指針的地址
依次類推....

指針變量也是一種變量,也會(huì)占用存儲(chǔ)空間,也可以使用&獲取它的地址。C語言不限制指針的級(jí)數(shù),每增加一級(jí)指針,在定義指針變量時(shí)就得增加一個(gè)星號(hào)*。p1 是一級(jí)指針,指向普通類型的數(shù)據(jù),定義時(shí)有一個(gè)*;p2 是二級(jí)指針,指向一級(jí)指針 p1,定義時(shí)有兩個(gè)*。

多級(jí)指針的話就是:

int ***p3 = &p2;//三級(jí)指針
int ****p4 = &p3;//四級(jí)指針
int *****p5 = &p4;//五級(jí)指針


//實(shí)際開發(fā)中會(huì)經(jīng)常使用一級(jí)指針和二級(jí)指針,幾乎用不到高級(jí)指針。

想要獲取指針指向的數(shù)據(jù)時(shí),一級(jí)指針加一個(gè)*,二級(jí)指針加兩個(gè)*,三級(jí)指針加三個(gè)*關(guān)系如下:

#include 
int main() {


  int a = 100;
  int *p1 = &a;
  int **p2 = &p1;
  int ***p3 = &p2;


  printf("%d, %d, %d, %d
", a, *p1, **p2, ***p3);//他們的值都是一樣的
  printf("&p2 = %#X, p3 = %#X
", &p2, p3);//所指向的地址也是一樣的
  printf("&p1 = %#X, p2 = %#X, *p3 = %#X
", &p1, p2, *p3);
  printf(" &a = %#X, p1 = %#X, *p2 = %#X, **p3 = %#X
", &a, p1, *p2, **p3);


  return 0;
}
//以三級(jí)指針 p3 為例來分析上面的代碼。***p3等價(jià)于*(*(*p3))。*p3 得到的是 p2 的值,
  也即 p1 的地址;*(*p3) 得到的是 p1 的值,也即 a 的地址;經(jīng)過三次“取值”操作后,*(*(*p3)) 
  得到的才是 a 的值。

指針數(shù)組、指向函數(shù)的指針、指向二維數(shù)組的指針

指針數(shù)組:

指針變量和普通變量一樣,也能組成數(shù)組,如果一個(gè)數(shù)組中的所有元素保存的都是指針,那么我們就稱它為指針數(shù)組。指針數(shù)組的定義形式一般為:

數(shù)據(jù)類型 * 名字 [數(shù)組長度];
這里注意 [ ]的優(yōu)先級(jí)比 * 來得高
int *a [10];
這里說明a是一個(gè)數(shù)組,包含了10個(gè)元素,每個(gè)元素的類型為int *。

除了每個(gè)元素的數(shù)據(jù)類型不同,指針數(shù)組和普通數(shù)組在其他方面都是一樣的,下面是一個(gè)簡單的例子:

#include
int main(void) {


  int a = 1;
  int b = 2;
  int c = 3;


  //定義一個(gè)指針的數(shù)組
  int *an[3] = { &a,&b,&c };//由于里邊每一個(gè)元素都是指針,所以利用取地址符&,指向abc三個(gè)變量


  //這里定義一個(gè)指向指針數(shù)組的指針,由于數(shù)組已經(jīng)是指針了,所以要用到二級(jí)指針
  int **p = an;//由于數(shù)組本身就是表示一個(gè)地址所以不用取地址符&


  printf("%d %d %d
", *an[0], *an[1], *an[2]);
  printf("%d %d %d
", **(p + 0) , **(p + 1), **(p + 2));


  return 0;
}


//arr 是一個(gè)指針數(shù)組,它包含了 3 個(gè)元素,每個(gè)元素都是一個(gè)指針,在定義 arr 的同時(shí),
我們使用變量 a、b、c 的地址對(duì)它進(jìn)行了初始化,這和普通數(shù)組是多么地類似。


    parr 是指向數(shù)組 arr 的指針,確切地說是指向 arr 第 0 個(gè)元素的指針,
它的定義形式應(yīng)該理解為int *(*parr),括號(hào)中的*表示 parr 是一個(gè)指針,
括號(hào)外面的int *表示 parr 指向的數(shù)據(jù)的類型。arr 第 0 個(gè)元素的類型為 int *,
所以在定義 parr 時(shí)要加兩個(gè) *。

指針數(shù)組還可以和字符串?dāng)?shù)組結(jié)合使用:

#include 
int main(){


    char *str[3] = {  //定義一個(gè)字符串?dāng)?shù)組 長度為3
        "c.biancheng.net",
        "C語言中文網(wǎng)",
        "C Language"
    };


    printf("%s
%s
%s
", str[0], str[1], str[2]);//依次輸出每個(gè)字符串
    return 0;
}

指向函數(shù)的指針:

一個(gè)函數(shù)總是占用一段連續(xù)的內(nèi)存區(qū)域,函數(shù)名在表達(dá)式中有時(shí)也會(huì)被轉(zhuǎn)換為該函數(shù)所在內(nèi)存區(qū)域的首地址,這和數(shù)組名非常類似。我們可以把函數(shù)的這個(gè)首地址(或稱入口地址)賦予一個(gè)指針變量,使指針變量指向函數(shù)所在的內(nèi)存區(qū)域,然后通過指針變量就可以找到并調(diào)用該函數(shù)。這種指針就是函數(shù)指針。

數(shù)據(jù)類型 *指針名 (數(shù)據(jù)類型 參數(shù));


數(shù)據(jù)為函數(shù)返回值類型,指針名稱,括號(hào)里邊為函數(shù)參數(shù)列表。參數(shù)列表中可以同時(shí)給出參數(shù)的類型和名稱,
也可以只給出參數(shù)的類型,省略參數(shù)的名稱,這一點(diǎn)和函數(shù)原型非常類似。

注意( )的優(yōu)先級(jí)高于*,第一個(gè)括號(hào)不能省略,如果寫作returnType *pointerName(param list);就成了函數(shù)原型,它表明函數(shù)的返回值類型為returnType *

用指針來實(shí)現(xiàn)對(duì)函數(shù)的調(diào)用:

#include 


//返回兩個(gè)數(shù)中較大的一個(gè)
int max(int a, int b){
    return a>b ? a : b;
}
int main(void){


    int x, y, maxval;
    //定義指向函數(shù)指針*pmax
    int (*pmax)(int, int) = max;  //也可以寫作int (*pmax)(int a, int b)
            //要注意的是定義必須和函數(shù)形式一致
    printf("Input two numbers:");
    scanf("%d %d", &x, &y);


    maxval = (*pmax)(x, y);//將函數(shù)調(diào)用并指針賦值
    printf("Max value: %d
", maxval);


    return 0;
}


 // maxval 對(duì)函數(shù)進(jìn)行了調(diào)用。pmax 是一個(gè)函數(shù)指針,在前面加 * 就表示對(duì)它指向的函數(shù)進(jìn)行調(diào)用。
   注意( )的優(yōu)先級(jí)高于*,第一個(gè)括號(hào)不能省略。

指向二維數(shù)組的指針:

(復(fù)盤一下二維數(shù)組的知識(shí))二維數(shù)組在概念上是二維的,有行和列,但在內(nèi)存中所有的數(shù)組元素都是連續(xù)排列的,它們之間沒有“縫隙”。以下面的二維數(shù)組 a 為例:

int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };


a就是像一個(gè)矩陣:
0   1   2   3
4   5   6   7
8   9  10  11


但在內(nèi)存中,a 的分布是一維線性的,整個(gè)數(shù)組占用一塊連續(xù)的內(nèi)存:
【0】【1】【2】【3】【4】【5】【6】【7】【8】【9】【10】【11】

C語言中的二維數(shù)組是按行排列的,也就是先存放 a[0] 行,再存放 a[1] 行,最后存放 a[2] 行;每行中的 4 個(gè)元素也是依次存放。數(shù)組 a 為 int 類型,每個(gè)元素占用 4 個(gè)字節(jié),整個(gè)數(shù)組共占用 4×(3×4) = 48 個(gè)字節(jié)。

C語言把一個(gè)二維數(shù)組分解成多個(gè)一維數(shù)組來處理。對(duì)于數(shù)組 a,它可以分解成三個(gè)一維數(shù)組,即 a[0]、a[1]、a[2]。每一個(gè)一維數(shù)組又包含了 4 個(gè)元素,例如 a[0] 包含`a[0][0] 、a[0][1]、a[0][2]、a[0][3]。

為了更好的理解指針和二維數(shù)組的關(guān)系,我們先來定義一個(gè)指向 a 的指針變量 p:

int (*p)[4] = a;
//括號(hào)中的*表明 p 是一個(gè)指針,它指向一個(gè)數(shù)組,數(shù)組的類型為int [4],
  這正是 a 所包含的每個(gè)一維數(shù)組的類型。

[ ]的優(yōu)先級(jí)高于*,( )是必須要加的,如果赤裸裸地寫作int *p[4],那么應(yīng)該理解為int *(p[4]),p 就成了一個(gè)指針數(shù)組,而不是二維數(shù)組指針。

對(duì)指針進(jìn)行加法(減法)運(yùn)算時(shí),它前進(jìn)(后退)的步長與它指向的數(shù)據(jù)類型有關(guān),p 指向的數(shù)據(jù)類型是int [4],那么p+1就前進(jìn) 4×4 = 16 個(gè)字節(jié),p-1就后退 16 個(gè)字節(jié),那么這正好是數(shù)組 a 所包含的每個(gè)一維數(shù)組的長度。也就是說,p+1會(huì)使得指針指向二維數(shù)組的下一行,p-1會(huì)使得指針指向數(shù)組的上一行。

按照上面的定義,我們來看看代碼:

#include 
int main(void){


    int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
    int (*p)[4] = a;


    printf ( "%d
",  sizeof(*(p+1))  );//這里輸出是16
    return 0;
}

*(p+1)+1表示第 1 行第 1 個(gè)元素的地址:*(p+1)單獨(dú)使用時(shí)表示的是第 1 行數(shù)據(jù),放在表達(dá)式中會(huì)被轉(zhuǎn)換為第 1 行數(shù)據(jù)的首地址,也就是第 1 行第 0 個(gè)元素的地址,因?yàn)槭褂谜袛?shù)據(jù)沒有實(shí)際的含義,編譯器遇到這種情況都會(huì)轉(zhuǎn)換為指向該行第 0 個(gè)元素的指針;就像一維數(shù)組的名字,在定義時(shí)或者和 sizeof、& 一起使用時(shí)才表示整個(gè)數(shù)組,出現(xiàn)在表達(dá)式中就會(huì)被轉(zhuǎn)換為指向數(shù)組第 0 個(gè)元素的指針。

*(*(p+1)+1)表示第 1 行第 1 個(gè)元素的值。很明顯,增加一個(gè) * 表示取地址上的數(shù)據(jù):**

規(guī)律:
a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)




#include
int main(void) {
  int a[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
  int i, j;
  int(*p)[4] = a;//定義一個(gè)指向二維數(shù)組的指針p
          
  for (i = 0; i < 3; i++) {
    for (j = 0; j < 4; j++) {


      printf("%d ", *(*(p+i)+j));//利用二級(jí)指針就可以訪問到i行j列的元素
    }      //*(p+i):一維數(shù)組
    printf("n");    //*(*(p+i)+j)  二維數(shù)組
  }


  return 0;


}


/*輸出:
1 2 3 4
5 6 7 8
9 10 11 12




數(shù)組名 a 在表達(dá)式中也會(huì)被轉(zhuǎn)換為和 p 等價(jià)的指針!

指針數(shù)組和二維數(shù)組指針在定義時(shí)非常相似,但是括號(hào)的位置不同所表示的意思也就天壤之別:

int *(p1[5]);  //指針數(shù)組,可以去掉括號(hào)直接寫作 int *p1[5];
int (*p2)[5];  //二維數(shù)組指針,不能去掉括號(hào)

指針數(shù)組和二維數(shù)組指針有著本質(zhì)上的區(qū)別:

指針數(shù)組是一個(gè)數(shù)組,只是每個(gè)元素保存的都是指針,以上面的 p1 為例,在32位環(huán)境下它占用 4×5 = 20 個(gè)字節(jié)的內(nèi)存。二維數(shù)組指針是一個(gè)指針,它指向一個(gè)二維數(shù)組,以上面的 p2 為例,它占用 4 個(gè)字節(jié)的內(nèi)存。

至于多維數(shù)組和二維數(shù)組沒有本質(zhì)的區(qū)別,但是復(fù)雜度倒是高了許多。一般不常用。

結(jié)束語:

程序在運(yùn)行過程中需要的是數(shù)據(jù)和指令的地址,變量名、函數(shù)名、字符串名和數(shù)組名在本質(zhì)上是一樣的,它們都是地址的助記符:在編寫代碼的過程中,我們認(rèn)為變量名表示的是數(shù)據(jù)本身,而函數(shù)名、字符串名和數(shù)組名表示的是代碼塊或數(shù)據(jù)塊的首地址;程序被編譯和鏈接后,這些名字都會(huì)消失,取而代之的是它們對(duì)應(yīng)的地址。指針就是存放地址的一種變量。

常見的的指針:

d2db0a1a-4eb8-11ed-a3b6-dac502259ad0.png

1、 指針變量可以進(jìn)行四則運(yùn)算。指針變量的加減運(yùn)算并不是簡單的加上或減去一個(gè)整數(shù),而是跟指針指向的數(shù)據(jù)類型與地址有關(guān)。

2、給指針變量賦值時(shí),要將一份數(shù)據(jù)的地址賦給它,不能直接賦給一個(gè)整數(shù),例如int *p = 1000;是沒有意義的,使用過程中一般會(huì)導(dǎo)致程序崩潰。

3、使用指針變量之前一定要初始化,否則就不能確定指針指向哪里,如果它指向的內(nèi)存沒有使用權(quán)限,程序就崩潰了。對(duì)于暫時(shí)沒有指向的指針,直接賦值NULL讓它變?yōu)榭罩羔槨?/p>

4、數(shù)組也是有類型的,數(shù)組名的本意是表示一組類型相同的數(shù)據(jù)。在定義數(shù)組時(shí),或者和 sizeof、& 運(yùn)算符一起使用時(shí)數(shù)組名才表示整個(gè)數(shù)組,表達(dá)式中的數(shù)組名會(huì)被轉(zhuǎn)換為一個(gè)指向數(shù)組的指針。

指針的用法暫時(shí)就這些,C指針大法這些才是入門!繼續(xù)加油咯~

審核編輯:彭靜
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 存儲(chǔ)
    +關(guān)注

    關(guān)注

    13

    文章

    4122

    瀏覽量

    85273
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4235

    瀏覽量

    61965
  • 指針
    +關(guān)注

    關(guān)注

    1

    文章

    475

    瀏覽量

    70457
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    411

    瀏覽量

    25821

原文標(biāo)題:【零基礎(chǔ)學(xué)C語言】知識(shí)總結(jié)十:二級(jí)指針、指針數(shù)組和指向函數(shù)的指針

文章出處:【微信號(hào):cyuyanxuexi,微信公眾號(hào):C語言編程學(xué)習(xí)基地】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    詳解C語言二級(jí)指針三種內(nèi)存模型

    二級(jí)指針相對(duì)于一級(jí)指針,顯得更難,難在于指針和數(shù)組的混合,定義不同類型的
    發(fā)表于 11-02 09:35 ?341次閱讀

    嵌入式C語言二級(jí)指針

    二級(jí)指針相對(duì)于一級(jí)指針,顯得更難,難在于指針和數(shù)組的混合,定義不同類型的
    發(fā)表于 11-04 10:08 ?535次閱讀

    C語言中多級(jí)指針的概念和使用方法

    多級(jí)指針在C語言中是一種特殊的指針類型,它可以指向其他指針指針
    發(fā)表于 08-16 16:16 ?674次閱讀

    嵌入式軟開的二級(jí)指針輸出的程序是怎樣的

    嵌入式軟開的指針是什么意思?嵌入式軟開的二級(jí)指針輸出的程序是怎樣的?
    發(fā)表于 12-24 06:38

    C51指針定義和應(yīng)用小結(jié)

    一. 指針變量的定義指針變量定義與一般變量的定義類似,其形式如下:數(shù)據(jù)類型 [存儲(chǔ)器類型1] *
    發(fā)表于 06-07 17:52 ?3297次閱讀

    函數(shù)指針指針函數(shù)定義

    函數(shù)指針指針函數(shù),C語言學(xué)習(xí)中最容易混淆的一些概念,好好學(xué)習(xí)吧
    發(fā)表于 01-11 16:44 ?0次下載

    c語言函數(shù)指針定義,指針函數(shù)和函數(shù)指針的區(qū)別

     往往,我們一提到指針函數(shù)和函數(shù)指針的時(shí)候,就有很多人弄不懂。下面就由小編詳細(xì)為大家介紹C語言中函數(shù)指針,指針函數(shù)和函數(shù)指針之間的區(qū)別。
    發(fā)表于 11-16 15:18 ?3551次閱讀

    C語言中的“二級(jí)指針”該如何理解

    在討論C語言指針時(shí),我一直在強(qiáng)調(diào)“將指針看作普通數(shù)據(jù)類型”,要是讀者能夠記住這一點(diǎn),在看到二級(jí)指針時(shí),將其與其他普通數(shù)據(jù)類型對(duì)比分析,會(huì)發(fā)現(xiàn)其實(shí)二級(jí)
    發(fā)表于 07-31 16:58 ?1.2w次閱讀
    C語言中的“<b class='flag-5'>二級(jí)</b><b class='flag-5'>指針</b>”該如何理解

    C語言二級(jí)指針的用法與原理

    提到指針,我們都知道指針是用來存儲(chǔ)一個(gè)變量的地址。所以,當(dāng)我們定義了一個(gè)指向指針指針的時(shí)候(pointer to pointer),我們也
    發(fā)表于 07-02 14:52 ?3693次閱讀
    C語言<b class='flag-5'>二級(jí)</b><b class='flag-5'>指針</b>的用法與原理

    C進(jìn)階技巧:二級(jí)指針問題

    這里重點(diǎn)看看一、二級(jí),畢竟二級(jí)指針與我們的維數(shù)據(jù)結(jié)合使用,維素組在圖形、矩陣、算法等等方面還是使用非常廣泛的。
    的頭像 發(fā)表于 09-08 15:00 ?1772次閱讀
    C進(jìn)階技巧:<b class='flag-5'>二級(jí)</b><b class='flag-5'>指針</b>問題

    C語言中的指針(重點(diǎn))超詳細(xì)

    - 指針4.3、指針的運(yùn)算關(guān)系5、指針和數(shù)組6、二級(jí)指針7、指針數(shù)組1、
    發(fā)表于 01-13 14:10 ?11次下載
    C語言中的<b class='flag-5'>指針</b>(重點(diǎn))超詳細(xì)

    維數(shù)組與數(shù)組指針以及指針數(shù)組

    維數(shù)組與數(shù)組指針以及指針數(shù)組
    的頭像 發(fā)表于 08-16 09:02 ?2498次閱讀

    指針長度簡述

    我們使用這樣的方式來定義一個(gè)指針: Type *p; 我們說 p是指向type類型的指針 ,type可以是任意類型,除了可以是char,short, int, long等基本類型外,還可以是
    的頭像 發(fā)表于 09-29 18:42 ?3918次閱讀
    <b class='flag-5'>指針</b>長度簡述

    C語言中一級(jí)指針、二級(jí)指針和三級(jí)指針

    級(jí)指針的用法其實(shí)是取數(shù)據(jù)的地址,以此類推,二級(jí)指針就是取一級(jí)指針的地址,也可以表示一
    發(fā)表于 05-19 17:30 ?1577次閱讀
    C語言中一<b class='flag-5'>級(jí)</b><b class='flag-5'>指針</b>、<b class='flag-5'>二級(jí)</b><b class='flag-5'>指針</b>和三<b class='flag-5'>級(jí)</b><b class='flag-5'>指針</b>

    面試???1:函數(shù)指針指針函數(shù)、數(shù)組指針指針數(shù)組

    在嵌入式開發(fā)領(lǐng)域,函數(shù)指針指針函數(shù)、數(shù)組指針指針數(shù)組是一些非常重要但又容易混淆的概念。理解它們的特性和應(yīng)用場景,對(duì)于提升嵌入式程序的效率和質(zhì)量至關(guān)重要。一、
    的頭像 發(fā)表于 08-10 08:11 ?311次閱讀
    面試???1:函數(shù)<b class='flag-5'>指針</b>與<b class='flag-5'>指針</b>函數(shù)、數(shù)組<b class='flag-5'>指針</b>與<b class='flag-5'>指針</b>數(shù)組