注意我的环境是:win10下的VS2019-X86环境
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
最后输出
2,5
注意这是在在VS2019,x86环境
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
结构体是20个字节,p是一个结构体指针,0x1是一个数组,相当于对指针+1,跳过结构体指针所指向元素大小,也就是20个字节
最后打印 100014
p的地址是0x100000,强制转为为一个无符号的长整形,此时就会把0x100000当做16进制转换为无符号长整形
0x100000 转二进制 00010000 00000000 00000000 ,再+1就是 00010000 00000000 00000001
最后以%p的形式来打印,就会把这个二进制当做地址来打印,当然它是以16进制的形式打印
0x100001
最后一个printf,把结构体指针强制类型转换为无符号整形的指针,跳过4个字节,0x100004
最后打印
00100014
00100001
00100004
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}
int*
的指针,现在ptr1指向数组末尾的地址处int*
的地址ptr1[-1]
相当于(prt1+(-1))
,此时ptr1就指向了数组最后一个元素的起始地址,再以%x打印0x00000004
int*
的指针,解引用拿到后面四个字节0x02000000
最后打印
4,2000000
#include
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
return 0;
}
p[0]
相当于*(p+0)
输出
1
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
p是一个指针,指向了一个整形数组,数组有4个元素,把二维数组首元素也就是第一行一维数组的地址赋给p
p[4][2]
等价于*(*(p+4)+2)
,p是一个数组指针,指向的数组有4个元素,所以每加一次就会跳过4个元素
*(p+4)
相当于拿到了一个数组名,也就是数组的首地址,再+2就拿到这个数组第二个元素的地址,解引用就拿到第二元素
&p[4][2] - &a[4][2]
,指针和指针相减的绝对值拿到的是指针之间的元素个数,这里是小减大所以是-4
-4在内存中的补码
原码:10000000 00000000 00000000 00000100
反码:11111111 11111111 11111111 11111011
补码:11111111 11111111 11111111 11111100
再以%p的形式打印,而%p打印地址是无符号的,它就会认为-4存的内存中的补码就是原码直接以16进制打印
FFFF FFFC
而%d是打印有符号的整形就会直接打印-4
打印结果
FFFFFFFC,-4
int main()
{
int a[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&a + 1);
int* ptr2 = (int*)(*(a + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
int*
*(a+1)
跳过第一行,拿到整个第二行一维数组的地址,也就是第二行的数组名。再强制类型转换为int*
*(ptr1-1)
,ptr1是一个整形指针,-1往回走4个字节*(ptr2-1)
,同理往回走最后输出
10,5
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
char* a[]
数组里存的都是字符串第一个字符的地址char* a[]
首元素的地址pa++
,相当于指针+1,此时就指向了数组第二元素*pa
,pa指向数组第二元素,第二个元素是字符串的首地址,对它解引用就拿到了字符串最后输出
at
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
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);
return 0;
}
没有执行任何printf的指针指向图
**(++cpp)
,第一接引用拿到c数组第二个元素的地址,再解引用拿到第二元素所指向的字符串c+2
的地址++cpp
,让cpp指向下一个位置也就是c+1
元素,在解引用找到c+1
,--
修改c+1的指向,让它指向它的上一个元素,此时它指向的是一个字符串“ENTER”,再解引用拿到这字符串的首地址,再+3*cpp[-2]
等价于*(cpp-2)
,指向的是“FIRST”,再+3跳过3个字符cpp[-1][-1]
等价于*(*(cpp-1)-1)
,此时指向的是"NEW"最后输出
POINT
ER
ST
EW