Further understood that the pointer 2: the double pointer, array pointer and pointer array

table of Contents

Contents 1

1. The concept of 1

1.1. Double pointer 1

1.2. Pointer Array 1

1.3. Array Pointer 1

2. The difference between the 2

3. Compatibility 2

4. Why is the number of columns to be equal? 2

5. Initialization 3

6. Conversion 4

7. The double pointer 6

8. Diagram 8

8.1. Array, pointer and double pointer diagram 8

8.2. Array diagram and the double pointer 9

8.3. Demo Code 9

9. Related Reference 10

 

1.  concept

1.1.  Double pointer

Pointing a pointer to a pointer.

1.2.  Pointer Array

Composed of an array of pointer values, i.e. data type of each element of the array values ​​are pointer type, such as: int * p [2];

1.3.  Array pointer

A point array pointers.

2.  difference

 

 

Rows

Number of columns

Explanation

int** p1;

Double pointer

Is not fixed

Is not fixed

The number of columns and rows is uncertain, and may vary the number of columns per row.

int* p2[3];

Pointer array

fixed

Is not fixed

A total of three lines, uncertain how many columns per row , and each row can vary the number of columns.

int (*p3)[3];

Array pointer

Is not fixed

fixed

A total of three columns uncertain how many lines.

3.  Compatibility

int** p1;

int* p2[3];

int (*p3)[3];

int p4[2][3];

int p5[3];

 

// Compatibility

p1 = p2;

p3 = p4;

p3 = & p5; // p5 number of columns and the number of columns must be the same as the p3

 

p1 = p2; // determine the number of both of which are not compatible with

 

" The number of columns is equal to " or " columns uncertainty " Lead is compatible, as described above P3 , P4 and p5 number of three columns are the same.

4.  Why is the number of columns to be equal?

Pointer support subtraction operation, such as:

int m[3][3];

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

 

The second row m refers to the two-dimensional array "int m [3] [3 ];" first address in memory, such as: 0x7fff82521370. And this " 1 " refers to the size of this two-dimensional array of line, i.e. "int m [3];" size. Thus, pm values: 0x7fff82521370 + 12 is  = 0x7fffd5afd94c.

 

If the sequence is not equal, the subtraction operation can not be performed, it is necessary , "the number of columns equal." Assumptions:

int** b1;

int** b2 = b1 + 1;

 

The above-mentioned " 1 " is actually much? This depends b1 What type is that? Here, B1 is a double pointer, i.e. a pointer to a pointer. It is essentially a pointer, thus 32 on the platform position its value is 4 , at 64 the value of its bit platform 8 .

5.  Initialization

How to initialize dual-pointers, pointer arrays and array pointer? Direct look at the following code:

#include <stdio.h>

 

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)

        {

                size_t num_cols_p1 = i + 1; // 列数不固定,可运行时设定

                p1[i] = new int[num_cols_p1];

                for (j=0; j<num_cols_p1; ++j)

                        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)

        {

                size_t num_cols_p2 = i + 1; // 列数不固定,可运行时设定

                p2[i] = new int[num_cols_p2];

                for (j=0; j<num_cols_p2; ++j)

                        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)

        {

                for (j=0; j<num_cols_p3; ++j)

                        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 <stdio.h>

 

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 <stdio.h>

 

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 <stdio.h>

 

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 <stdio.h>

 

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 <stdio.h>

 

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 <stdio.h>

 

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

 

Guess you like

Origin www.cnblogs.com/aquester/p/11469893.html