麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

進一步理解指針2:雙指針、指針數組和數組指針

2019-11-10 20:33:06
字體:
來源:轉載
供稿:網友
進一步理解指針2:雙指針、指針數組和數組指針             進一步理解指針2:雙指針、指針數組和數組指針 2015-04-22 15:44:50

分類: C/C++

進一步理解指針2:雙指針、指針數組和數組指針.pdf

目錄

目錄 1

1. 概念 1

1.1. 雙指針 1

1.2. 指針數組 1

1.3. 數組指針 1

2. 區別 2

3. 兼容性 2

4. 為何列數須相等? 2

5. 初始化 3

6. 轉化 4

7. 雙指針 6

8. 關系圖 8

8.1. 數組、指針和雙指針關系圖 8

8.2. 數組和雙指針關系圖 9

8.3. 演示代碼 9

9. 相關參考 10

 

1. 概念

1.1. 指針

對于“p + 1”,這里的“1”是啥?

1) 如果int* p,則“1”實際是sizeof(int),也就是p指向的類型大小;

2) 如果int** p,則“1”實際是sizeof(int*),仍然是p指向的類型大小;

3) 如果int p[5],則“1”是sizeof(int),而“&p+1”中的“1”則為sizeof(p),依然是p或&p指向類型的大小。

1.1. 雙指針

指向一個指針的指針。

1.2. 指針數組

由指針值組成的數組,也就是說數組的每個元素值的數據類型均為指針類型,如:int* p[2];

1.3. 數組指針

指向一個數組的指針。

2. 區別

 

 

行數

列數

說明

int** p1;

雙指針

不固定

不固定

列數和行數都不確定,而且每行可以列數不等。

int* p2[3];

指針數組

固定

不固定

共3行,每行多少列不確定,而且每行可以列數不等。

int (*p3)[3];

數組指針

不固定

固定

共3列,多少行不確定。

3. 兼容性

int** p1;

int* p2[3];

int (*p3)[3];

int p4[2][3];

int p5[3];

 

// 兼容性

p1 = p2;

p3 = p4;

p3 = &p5; // p5的列數必須和p3的列數相同

 

p1 = p2; // 兩者列數均不確定,可兼容

 

“列數相等”或“列數不確定”是兼容的提前條件,如上述的p3、p4和p5三者的列數均相同。

4. 為何列數須相等?

指針支持加減操作,比如:

int m[3][3];

int (*pm)[3] = m + 1;

 

上述第二行的m是指二維數組“int m[3][3];”在內存中的首地址,如:0x7fff82521370。而這個“1”是指這個二維數組一行的大小,也就是“int m[3];”的大小。因此,pm的值為:0x7fff82521370 + 12 = 0x7fffd5afd94c。

 

如果列數不相等,則加減操作無法進行,因此需要“列數相等”。假設:

int** b1;

int** b2 = b1 + 1;

 

上述中的“1”實際是多少?這個就要看b1的類型是什么?在這里,b1是一個雙指針,也就是指向指針的指針。本質上就是一個指針,因此在32位平臺上它的值是4,在64位平臺上它的值是8。

5. 初始化

如何來初始化雙指針、指針數組和數組指針?直接看下面的代碼:

#include 

 

int main()

{

        size_t i; // 行

        size_t j; // 列

 

        int** p1;     // 行數和列數,均不固定

        int* p2[3];   // 行數固定為3,列數不固定

        int (*p3)[3]; // 列數固定為3,行數不固定

 

        size_t num_rows_p1 = 3; // 行數不固定,可運行時設定

        p1 = new int*[num_rows_p1];

        for (i=0; i<num_rows_p1; ++i)< span="">

        {

                size_t num_cols_p1 = i + 1; // 列數不固定,可運行時設定

                p1[i] = new int[num_cols_p1];

                for (j=0; j<num_cols_p1; ++j)< span="">

                        p1[i][j] = i;

        }

        PRintf("p1[2][1]=%d/n", p1[2][1]);

        printf("p1[2][2]=%d/n", p1[2][2]);

 

        const size_t num_rows_p2 = sizeof(p2)/sizeof(p2[0]); // 行數固定,不可運行時設定

        for (i=0; i<num_rows_p2; ++i)< span="">

        {

                size_t num_cols_p2 = i + 1; // 列數不固定,可運行時設定

                p2[i] = new int[num_cols_p2];

                for (j=0; j<num_cols_p2; ++j)< span="">

                        p2[i][j] = i;

        }

        printf("p2[2][1]=%d/n", p2[2][1]);

        printf("p2[2][2]=%d/n", p2[2][2]);

 

        size_t num_rows_p3 = 5; // 行數不固定,可運行時設定

        const size_t num_cols_p3 = 3; // 列數固定,不可運行時設定

        p3 = new int[num_rows_p3][num_cols_p3];

        for (i=0; i<num_rows_p3; ++i)< span="">

        {

                for (j=0; j<num_cols_p3; ++j)< span="">

                        p3[i][j] = i;

        }

        printf("p3[2][1]=%d/n", p3[2][1]);

        printf("p3[2][2]=%d/n", p3[2][2]);

 

        return 0;

}

6. 轉化

下面這個表格,在內存中即可為“int** p1;”,也可以為“int* p2[3];”,還可以為“int (*p3)[3];”

1

2

3

4

5

6

7

8

9

 

如下來操作它:

#include 

 

int main()

{

        int m[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };

 

        int** p1;

        int* p2[3];

        int (*p3)[3];

 

        p1 = new int *[3];

        p1[0] = m[0]; // 列數不固定

        p1[1] = m[1]; // 列數不固定

        p1[2] = m[2]; // 列數不固定

        printf("p1[1][2]=%d/n", p1[1][2]);

 

        p2[0] = m[0]; // 列數不固定

        p2[1] = m[1]; // 列數不固定

        p2[2] = m[2]; // 列數不固定

        printf("p2[1][2]=%d/n", p2[1][2]);

 

        p3 = m; // 列數固定

        printf("p3[1][2]=%d/n", p3[1][2]);

 

        delete []p1;

        return 0;

}

 

 

實際上,還可以當作一維數組,但仍然可以使用“int** p1;”、“int* p2[3];”和int (*p3)[3];”來操作,看下面的代碼:

#include 

 

int main()

{

        int n[9] = { 1,2,3, 4,5,6, 7,8,9 };

 

        int** p1;

        int* p2[3];

        int (*p3)[3];

 

        p1 = new int *[3];

        p1[0] = n;

        p1[1] = n + 3;

        p1[2] = n + 6;

        printf("p1[1][2]=%d/n", p1[1][2]);

 

        p2[0] = n;

        p2[1] = n + 3;

        p2[2] = n + 6;

        printf("p2[1][2]=%d/n", p2[1][2]);

 

        p3 = (int (*)[3])n; // 這里也可改成:p3 = (int (*)[3])&n;

        printf("p3[1][2]=%d/n", p3[1][2]);

 

        delete []p1;

        return 0;

}

 

二維數組同樣也可以當一維數組使用,如:

#include 

 

int main()

{

        int m[3][3] = { {1,2,3}, {4,5,6}, {7,8,9} };

 

        int *p = (int*)m; // 這里同樣也可以改成:int *p = (int*)&m;

        printf("p[1]=%d, p[3]=%d, p[6]=%d/n", p[1], p[3], p[6]);

        return 0;

}

7. 雙指針

int m[3]; int* p1; int** p2; int* p3[3]; int (*p4][3]);的本質是相同的,都表示一塊內存,只所以有區分,是為了編譯器能夠按照不同的方式去訪問這塊內存。更通俗點說,它們都是對內存訪問的協議。

 

從前面的例子不難看出,對于雙指針“int** p1;”在使用之前,總是會先做“new int*[]”操作。如果讓p1直接指向數組首地址是否可以了?

 

答案是不行的,假設有如下的代碼:

int m[9] = { 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9 };

int** pp = (int**)m;

 

pp[0]、pp[1]、pp[2]。。。是什么?用下面這段代碼來觀察:

#include 

 

int main()

{

        int** pp = NULL;

        int m[9] = { 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9 };

 

        pp = (int**)m;

        printf("pp[0]=%p, pp[1]=%p, pp[2]=%p, pp[3]=%p/n", pp[0], pp[1], pp[2], pp[3]);

        return 0;

}

 

上面這段代碼中的數組元素值特意使用了16進制,以便更好的觀察,它的實際輸出和機器的字節序,以及位數相關,在x86輸出為:

pp[0]=0x1, pp[1]=0x2, pp[2]=0x3, pp[3]=0x4

 

在x86_64上輸出為:

pp[0]=0x200000001, pp[1]=0x400000003, pp[2]=0x600000005, pp[3]=0x800000007

 

不要被雙指針“**”迷惑了,可對比下“int* p;”

#include 

 

int main()

{

        int* p = NULL;

        int** pp = NULL;

        int m[9] = { 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9 };

 

        pp = (int**)m;

        printf("pp[0]=%p, pp[1]=%p, pp[2]=%p, pp[3]=%p/n", pp[0], pp[1], pp[2], pp[3]);

 

        p = m;

        printf("p[0]=%d, p[1]=%d, p[2]=%d, p[3]=%d/n", p[0], p[1], p[2], p[3]);

        return 0;

}

 

因為pp是雙指針類型,因此它不能直接指向數組內存。

假設有一指針:int* p;,它的地址為x,則p[N]和*(p+N)都是取地址為“x+sizeof(int)”的內存數據;如果是“int** pp;”,設地址為y,則pp[N]和*(pp+N)是取地址為“y+sizeof(int*)”的內存數據。

8. 關系圖

8.1. 數組、指針和雙指針關系圖

8.2. 數組和雙指針關系圖

8.3. 演示代碼

#include 

 

int main()

{

        int m[] = { 1,2,3,4,5,6,7,8,9 };

        int* p = m;

        int** pp = &p;

 

        printf("sizeof(p)=%d/n", sizeof(p));

        printf("sizeof(*p)=%d/n", sizeof(*p));

 

        printf("m=%p/n", m);

        printf("&p=%p/n", &p);

        printf("*p=%lx/n", *pp);

        printf("**p=%d/n", **pp); // 這實際是“*((*pp)+0))”而不是“*(*(pp+0))”

        printf("*((*p)+0)=%d/n", *((*pp)+0));

        printf("pp=%p/n", pp);

        printf("pp+1=%p/n", pp+1);

 

        // 不要將“pp[0][1]”理解成:**(pp+0+1),

        // 這里的1實際是sizeof(*pp),也就是sizeof(int*),

        // 而pp是p的地址,注意不是m的地址

        printf("&m[1]=%p/n", &m[1]);

        printf("&pp[0][1]=%p/n", &pp[0][1]); // p[0]也就是*(p+0)

        printf("pp[0][1]=%d/n", pp[0][1]); // p[0][1]也就是*((*(pp+0))+1))

        printf("*((*(pp+0))+1)=%d/n", *((*(pp+0))+1));

 

        printf("*((*pp)+1)=%d/n", *((*pp)+1)); // 正確,*pp是m的地址

        printf("**(pp+1)=%d/n", **(pp+1)); // 越界了,因為pp的值是p的地址,不是m的地址

        return 0;

}

9. 相關參考

《進一步理解指針:一維數組和二維數組轉換》:

http://blog.chinaunix.net/uid-20682147-id-4967871.html

《常見指針定義解讀》

http://blog.chinaunix.net/uid-20682147-id-4344901.html


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 高清国产在线 | 成片免费观看大全 | 亚洲精品久久久久久久久久久 | 干少妇av | 欧美成人自拍 | 草草视频在线播放 | 在线观看免费精品 | 91精品国产91久久久 | 中文字幕在线视频网站 | 成人免费一区二区 | 99影视在线视频免费观看 | 线观看免费完整aaa 欧美在线一级 | 青青草成人免费视频在线 | 欧美a级毛片 | 狠狠干五月天 | 蜜桃精品视频 | 免费a级作爱片免费观看欧洲 | 91色综合综合热五月激情 | 欧美成人黄色小视频 | 精品xxxx户外露出视频 | 免费黄色小网站 | 一级美女大片 | 狠狠操夜夜爱 | 精品国产一区二区三区久久久蜜月 | 婷婷一区二区三区 | 久久久日韩精品一区二区三区 | 成人在线观看免费 | 日本aaa一级片 | 国产精品免费久久久久 | 高清国产福利 | 日本黄色一级视频 | 欧美人人干 | 欧美大荫蒂xxx | 成人在线高清视频 | 国产剧情在线观看一区二区 | 亚洲国产馆 | 黄色网址免费在线播放 | 综合网天天色 | 男女羞羞在线观看 | 色视频欧美 | 久久综合伊人 |