#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
*/