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