指针和数组的重难点解析

#include <iostream>

void test()
{
    int a[5] = {1, 2, 3, 4, 5};
    int *ptr = (int *)(&a + 1);
    printf("%d,%d", *(a + 1), *(ptr - 1));
}
int main()
{
    test();
    return 0;
}

输出结果:2,5

对于数组而言,是一段连续存储的物理地址,里面的内容分别是1 2 3 4 5

 

1

2

3

4

5

&a+1

a指向的是首地址

&a也是指向首地址,但是对于&a而言,无论几维数组,&a+1之后,一定是整个数组的一个跨度.

所以*(ptr-1) ,就是&a+1的位置往左移一位,也就是5

*(a+1)就很简单了,就首地址往右移一位,也就是2

二、三维数组的偏移

void test2()
{
    int a[2][2][3] = {{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}};
    int *ptr = (int *)(&a + 1);
    printf("%d,%d", *(int *)(a + 1), *(ptr - 1));
}

输出结果

7,12
4,2
0x7ffeed1384b0
0x7ffeed1384b0
0x7ffeed1384b0
0x7ffeed1384b0

道理同上,差不多

不论几维数组,都可以等效为一个一维数组

{1,2,3},{4,5,6}

{7,8,9}

{10,11,12}

&a+1

可以看作是一个数组,有两个元素,每个元素又是一个2行3列的二维数组

*(int *)(a + 1) 其实就是把

{7,8,9}

{10,11,12}

转成一个int *数组,然后取第一个,也就是7

a是一个三级指针,是一个三维数组,a指向的是首地址

&a也是指向这个首地址

*a,取内容后降级为二维数组,也是二级指针,它指向的也是这个首地址

**a,取内容再取内容,降级为一级指针, 它指向的也是这个首地址

a+1可以看成a[2]后面跨度[2][3]也就是6个元素

*a+1可以看成a[2][2]后面跨度[3]也就是3个元素

**a+1可以看成a[2][2][3]后面跨度[1]也就是1个元素

三、指针偏移

void test3()
{
    static const char *s[] = {"black", "white", "pink", "violet"};
    const char **ptr[] = {s + 3, s + 2, s + 1, s}, ***p;
    p = ptr;
    ++p;
    printf("%s\n", **p + 1);
}

输出结果:ink

解析:

static const char *s[] = {"black", "white", "pink", "violet"};
const char **ptr[] = {s + 3, s + 2, s + 1, s}, ***p;
p = ptr;

上面3句对象下面的表格

三级指针

二级指针

一级指针

内容

P+3

s

s[0]

black

p+2

s+1

s[1]

white

p+1

s+2

s[2]

pink

p

s+3

s[3]

violet

++p;

也就是指向了下面这一行

p+1 p

s+2

s[2]

pink

**p + 1

这一行业就是降为1级指针,也就是pink这个字符数组第二个位置开始,也就是ink

四、三维数组和二维数组指针的结合

void test4()
{
    int a[3][4] = {{1, 2, 3, 4},
                   {2, 3, 4, 5},
                   {3, 4, 5, 6}};

    int b[3][4] = {
        {10, 11, 12, 13},
        {11, 12, 13, 14},
        {12, 13, 14, 15}};

    int(*aa[2])[4] = {a, b};         // 三级指针  一个*两个[]
    int *p1[3] = {a[0], a[1], a[2]}; // 二级指针 一个*一个[]
    int *p2[3] = {b[0], b[1], b[2]}; // 二级指针 一个*一个[]
    int **pp[2] = {p1, p2};          // 三级指针 两个*一个[]
    int ***p = pp;                   // 三级指针 三个*
    printf("%d\n", (*(*p + 2))[1]);
    printf("%ld\n", aa[1][2] - aa[1][0]); // aa是三级,[1][2]就是降两级变成一级,一级减一级,其实就是指针减指针,肯定是数据元素的一个偏移
}

输出

4 8

pp/p/aa

a/p1

a[0]

1

2

3

4

a+1

a[1]

2

3

4

5

a+2

a[2]

3

4

5

6

pp+1/aa+1

b/p2

b[0]

10

11

12

13

b+1

b[1]

11

12

13

14

b+2

b[2]

12

13

14

15

通过上图,printf("%d\n", (*(*p + 2))[1]);相当于就是a[2][1]=4

printf("%ld\n", aa[1][2] - aa[1][0]);

aa[1][2],期中aa[1]相当于b,最终就是b[2]-b[0]=个元素

五、赋值之后指针指向内容突变

void test5()
{
    const char *ptr[] = {"Welcome", "To", "Beautiful", "Beijing"};
    const char **p = ptr + 1;

    ptr[0] = (*p++) + 2; //
    ptr[1] = *(p + 1);   //
    ptr[2] = p[1] + 3;   //
    ptr[3] = p[0] + (ptr[2] - ptr[1]);

    printf("%s\n", ptr[0]);
    printf("%s\n", ptr[1]);
    printf("%s\n", ptr[2]);
    printf("%s\n", ptr[3]);
}
    const char *ptr[] = {"Welcome", "To", "Beautiful", "Beijing"};
    const char **p = ptr + 1;

对应如下

二级

一级

原值

新值

ptr

ptr[0]

Welcome

空值

ptr+1/p

ptr[1]

To

Beijing

ptr+2/p++后新的p

ptr[2]

Beautiful

jing

ptr+3

ptr[3]

Beijing

g

ptr[0] = (*p++) + 2;// 后置++  限执行再自加,对于ptr[0]而言,其实就是*p+2,也就是 To 取o后面的,也就是空
ptr[1] = *(p + 1);//由于上面p++,这里的p其实指向ptr[2],*(p+1)也就是ptr[3]的值 Beijing
ptr[2] = p[1] + 3;//jing
ptr[3] = p[0] + (ptr[2] - ptr[1]); // p[0] +(jing的地址-Beijing的地址) = p[0]+3=jing的地址+3=g

 六、多级指针多维数组指针偏移运算

void test6()
{
    const char *c[] = {"Welcome", "To", "Beautiful", "Beijing"};
    const char **cp[] = {c + 3, c + 2, c + 1, c};
    const char ***cpp = cp;

    printf("%s\n", **++cpp);
    printf("%s\n", *--*++cpp + 3);
    printf("%s\n", *cpp[-2] + 3);
    printf("%s\n", cpp[-1][-1] + 1);
}

const char *c[] = {"Welcome", "To", "Beautiful", "Beijing"};

const char **cp[] = {c + 3, c + 2, c + 1, c};

const char ***cpp = cp;

可以得出如下表:

三级

二级

一级

原值

cp+3

c

c[0]

Welcome

cp+2

c+1

c[1]

To

cp+1

c+2

c[2]

Beautiful

cp/cpp

c+3

c[3]

Beijing

这样就很简单了 **++cpp=**(cp+1)=*(c+2)=c[2]=Beautiful

之后的表为:

三级

二级

一级

原值

cp+3

c

c[0]

Welcome

cp+2

c+1

c[1]

To

cp+1/cpp

c+2

c[2]

Beautiful

cp

c+3

c[3]

Beijing

*--*++cpp + 3 = *--*(cp+2)+3 = *--(c+1)+3 = *c +3 =c[3]+3=come

之后的表为:

三级

二级

一级

原值

cp+3

c

c[0]

Welcome

cp+2/cpp

c+1

c[1]

To

cp+1

c+2

c[2]

Beautiful

cp

c+3

c[3]

Beijing

printf("%s\n", *cpp[-2] + 3); 注意上面一行*--*++cpp对于cpp来,做的前置++才改变了cpp的指向,最终结果也就是上表

*cpp[-2]+3 = *(c+3)+3 =c[3]+3=jing

printf("%s\n", cpp[-1][-1] + 1); 也就很简单了,cpp[-1][-1]+1 = (c+2)[-1]+1=c[1]+1=o

#include <iostream>

using namespace std;

void test()
{
    int a[5] = {1, 2, 3, 4, 5};
    int *ptr = (int *)(&a + 1);
    printf("%d,%d\n", *(a + 1), *(ptr - 1));
}
/*
输出结果:2,5

对于数组而言,是一段连续存储的物理地址,里面的内容分别是1 2 3 4 5
12345&a+1
a指向的是首地址
&a也是指向首地址,但是对于&a而言,无论几维数组,&a+1之后,一定是整个数组的一个跨度.
所以*(ptr-1) ,就是&a+1的位置往左移一位,也就是5
*(a+1)就很简单了,就首地址往右移一位,也就是2
 */

void test2()
{
    int a[2][2][3] = {{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}};
    int *ptr = (int *)(&a + 1);
    printf("%d,%d\n", *(int *)(a + 1), *(ptr - 1));
    printf("%d,%d\n", *(int *)(*a + 1), *(int *)(**a + 1));
    cout << a << endl;
    cout << &a << endl;
    cout << *a << endl;
    cout << **a << endl;
}
/*
7,12
4,2
0x7ffeed1384b0
0x7ffeed1384b0
0x7ffeed1384b0
0x7ffeed1384b0

道理同上,差不多
不论几维数组,都可以等效为一个一维数组
{1,2,3},{4,5,6} | {7,8,9}{10,11,12} | &a+1

可以看作是一个数组,有两个元素,每个元素又是一个2行3列的二维数组
*(int *)(a + 1) 其实就是把
{7,8,9}{10,11,12}
转成一个int *数组,然后取第一个,也就是7

a是一个三级指针,是一个三维数组,a指向的是首地址
&a也是指向这个首地址
*a,取内容后降级为二维数组,也是二级指针,它指向的也是这个首地址
**a,取内容再取内容,降级为一级指针, 它指向的也是这个首地址

a+1可以看成a[2]后面跨度[2][3]也就是6个元素
*a+1可以看成a[2][2]后面跨度[3]也就是3个元素
**a+1可以看成a[2][2][3]后面跨度[1]也就是1个元素
 */

void test3()
{
    static const char *s[] = {"black", "white", "pink", "violet"};
    const char **ptr[] = {s + 3, s + 2, s + 1, s}, ***p;
    p = ptr;
    ++p;
    printf("%s\n", *(*p + 1)); // violet
    printf("%s\n", **p + 1);   // ink
}

/*
输出结果:
violet
ink

上面3句对象下面的表格
三级指针二级指针一级指针内容P+3ss[0]blackp+2s+1s[1]whitep+1s+2s[2]pinkps+3s[3]violet

++p;
也就是指向了下面这一行
p+1   ps+2s[2]pink

**p + 1
这一行业就是降为1级指针,也就是pink这个字符数组第二个位置开始,也就是ink

*/

void test4()
{
    int a[3][4] = {{1, 2, 3, 4},
                   {2, 3, 4, 5},
                   {3, 4, 5, 6}};

    int b[3][4] = {
        {10, 11, 12, 13},
        {11, 12, 13, 14},
        {12, 13, 14, 15}};

    int(*aa[2])[4] = {a, b};         // 三级指针  一个*两个[]
    int *p1[3] = {a[0], a[1], a[2]}; // 二级指针 一个*一个[]
    int *p2[3] = {b[0], b[1], b[2]}; // 二级指针 一个*一个[]
    int **pp[2] = {p1, p2};          // 三级指针 两个*一个[]
    int ***p = pp;                   // 三级指针 三个*
    printf("%d\n", (*(*p + 2))[1]);
    printf("%ld\n", aa[1][2] - aa[1][0]); // aa是三级,[1][2]就是降两级变成一级,一级减一级,其实就是指针减指针,肯定是数据元素的一个偏移
}
/*
输出
4
8

pp/p/aaa/p1a[0]1234a+1a[1]2345a+2a[2]3456pp+1/aa+1b/p2b[0]10111213b+1b[1]11121314b+2b[2]12131415
通过上图,printf("%d\n", (*(*p + 2))[1]);相当于就是a[2][1]=4

printf("%ld\n", aa[1][2] - aa[1][0]);
aa[1][2],期中aa[1]相当于b,最终就是b[2]-b[0]=个元素

 */

void test5()
{
    const char *ptr[] = {"Welcome", "To", "Beautiful", "Beijing"};
    const char **p = ptr + 1;

    ptr[0] = (*p++) + 2; // 空
    ptr[1] = *(p + 1);   // Beijing
    ptr[2] = p[1] + 3;   // jing
    printf("ptr[2]的地址:%p,ptr[1]的地址:%p,相减的结果为:%ld\n", ptr[2], ptr[1], ptr[2] - ptr[1]);
    ptr[3] = p[0] + (ptr[2] - ptr[1]); // p[0] +(jing的地址-Beijing的地址) = p[0]+3=jing的地址+3=g

    printf("ptr[0]=%s\n", ptr[0]);
    printf("ptr[1]=%s\n", ptr[1]);
    printf("ptr[2]=%s\n", ptr[2]);
    printf("ptr[3]=%s\n", ptr[3]);
}
/*
ptr[0] = (*p++) + 2;// 后置++  限执行再自加,对于ptr[0]而言,其实就是*p+2,也就是 To 取o后面的,也就是空
ptr[1] = *(p + 1);//由于上面p++,这里的p其实指向ptr[2],*(p+1)也就是ptr[3]的值 Beijing
ptr[2] = p[1] + 3;//jing
ptr[3] = p[0] + (ptr[2] - ptr[1]); // p[0] +(jing的地址-Beijing的地址) = p[0]+3=jing的地址+3=g

 */

void test6()
{
    const char *c[] = {"Welcome", "To", "Beautiful", "Beijing"};
    const char **cp[] = {c + 3, c + 2, c + 1, c};
    const char ***cpp = cp;

    printf("%s\n", **++cpp);
    printf("%s\n", *--*++cpp + 3);
    printf("%s\n", *cpp[-2] + 3);
    printf("%s\n", cpp[-1][-1] + 1);
}
int main()
{
    test();
    cout << "------------------------分隔符------------------------" << endl;
    test2();
    cout << "------------------------分隔符------------------------" << endl;
    test3();
    cout << "------------------------分隔符------------------------" << endl;
    test4();
    cout << "------------------------分隔符------------------------" << endl;
    test5();
    cout << "------------------------分隔符------------------------" << endl;
    test6();
    return 0;
}
/*
2,5
------------------------分隔符------------------------
7,12
4,2
0x7ffee1618450
0x7ffee1618450
0x7ffee1618450
0x7ffee1618450
------------------------分隔符------------------------
violet
ink
------------------------分隔符------------------------
4
8
------------------------分隔符------------------------
ptr[2]的地址:0x10e5e8eb4,ptr[1]的地址:0x10e5e8eb1,相减的结果为:3
ptr[0]=
ptr[1]=Beijing
ptr[2]=jing
ptr[3]=g
------------------------分隔符------------------------
Beautiful
come
jing
o
 */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值