一
此程序在X86环境下运行
由于还没学习结构体,这里告知结构体的大小是20个字节
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x000000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
printf("%d\n",sizeof(struct Test));
printf("%p\n", p);// 0x000000
//此时的p为struct Test*类型,+1跳过20个字节
printf("%p\n", p + 0x1);//0x000014 - 20
//p为unsigned long类型,长整形,+1
printf("%p\n", (unsigned long)p + 0x1);//0x000001
//p为unsigned int*类型,+1跳过四个字节
printf("%p\n", (unsigned int*)p + 0x1);//0x000004
return 0;
}
二
//小端存储,低位在低地址,高位在高地址
//计算机读取的顺序是从低地址到高地址
int main()
{
int a[4] = { 1, 2, 3, 4 };
/*
低 高地址
0x000002
01 00 00 00
0x000006
02 00 00 00
03 00 00 00
04 00 00 00
所以读取00 00 00 02
故*ptr2的结果为00 00 00 02
*/
int* ptr1 = (int*)(&a + 1);
// a为数组名,代表数组首元素地址,假设为0x000001
// 则(int)a的值为0x000001
// (int)a + 1为 0x000002
// (int*)((int)a + 1)代表0x000002为int*类型
// 所以*ptr2是从0x000002开始读取int类型长度的数据
int* ptr2 = (int*)((int)a + 1);
// 0x02 00 00 00
printf("%d,%x", ptr1[-1], *ptr2);
return 0;
}
三
#include <stdio.h>
int main()
{
//里面的括号是逗号表达式***********
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
/*
int *p = a[0]-- int*类型
↓
1 3
5 0
0 0
*/
int* p;
p = a[0];
printf("%d", p[0]);//1
// p[0] --> *(p+0) --> *(a[0] + 0)
return 0;
}
四
int main()
{
int a[5][5];
int(*p)[4];
p = a;
/*
-4
10000000 00000000 00000000 00000100 原码
11111111 11111111 11111111 11111011 反码
11111111 11111111 11111111 11111100 补码 -4在内存中的存储形式
一.以%d的形式打印
C语言会将11111111 11111111 11111111 11111100看成一个有符号数在内存中存储
二.以%p的形式打印
C语言会将11111111 11111111 11111111 11111100看成一串地址
FF FF FF FC
----------
*/
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//-4
/*
//第一种理解,公式法
&p[4][2] - &a[4][2]
&*(p[4]+2) - &*(a[4]+2)
p[4]+2 - (a[4]+2)
p[4]+2-a[4]-2
p[4]-a[4]
*(p+4) - *(a+4)
因为p = a,假设他们的初始地址为0
因为p是int(*)[4]类型,故p+4走过16个int
因为a是int(*)[5]类型,故a+4走过20个int
16-20 = -4
故&p[4][2] - &a[4][2]之间相差-4个int
----
*/
/*
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);//-4
//第二种理解
p的类型是int(*)[4],是一个数组的指针,该数组有四个元素,每个元素int类型
假设p=a,他们的初始地址为0
p[4]--> *(p+4),其中 p+4 代表跳过4个int(*)[4]类型的大小,也就是跳过16个int的地址
此时地址从0变为0+16*4=64, 但p+4的类型仍为int(*)[4]类型,
但*(p+4)为int*类型,
p[4][2]--> *(p+4)[2] --> *(*(p+4)+2)
因为*(p+4)为int*类型,所以*(p+4)+2向后跳过2个int*类型,来到64+2*4=72
*(p+4)+2仍然为int*类型
*(*(p+4)+2) 为int类型,表示地址为72,这个int类型元素的数值
&p[4][2] --> &(*(*(p+4)+2))
因为*(*(p+4)+2) 为int类型,所以&(*(*(p+4)+2))为int*类型
故&p[4][2]为int*类型,地址为72
==================================================================================================
==================================================================================================
&a[4][2]
a为int(*)[5]类型,是指向数组的指针,该数组有五个元素,每个元素为int类型
a[4] --> *(a+4) 0+4*5*4 = 80
a+4是 int(*)[5]类型
*(a+4)是int*类型
a[4][2] --> *(*(a+4)+2) 80+4*2=88
*(a+4)+2是int*类型
*(*(a+4)+2)是int类型
&a[4][2] int*类型
==================================================================================================
==================================================================================================
(72-88)/4 = -4
----------------
*/
return 0;
}
五
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* ptr1 = (int*)(&aa + 1);
int* ptr2 = (int*)(*(aa + 1));
printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//10,5
return 0;
}
六
// 假如一个类型是int*类型,该类型+1跳过1个int
int main()
{
// a[]是一个指针数组,有三个元素,每个元素为char*类型
// a是数组名,代表首元素地址,首元素为char*类型,故a为char**类型
//
char* a[] = { "work","at","alibaba" };
char** pa = a;
pa++;
printf("%s\n", *pa);//at
//int a[10];
//int(*p)[10] = &a;
数组指针指针
//int(**p2)[10] = &p;
return 0;
}
七
int main()
{
char* c[] = { "ENTER","NEW","POINT","FIRST" };
/*
c[]是指针数组,有4个元素,每个元素为char*类型,用来存放char类型的地址
c数组名,代表数组首元素地址,首元素类型为char*类型,故c为char**类型,用于存放char*类型的地址
cp[]是指针数组,有三个元素,每个元素用来存放char*类型的地址,每个元素的类型为char**
cp为数组名,代表首元素地址,首元素为char**类型,故cp为char***类型
*/
char** cp[] = { c + 3,c + 2,c + 1,c };//cpp
char*** cpp = cp;
/*
++cpp --> cpp+1
cpp为char***类型,cpp+1跳过一个char**类型的大小,
cp[]的每个元素为char**类型,故cpp+1跳到元素c+2,cpp+1存储元素c+2的地址,为char***类型
*(cpp+1)为char**类型, 因为cpp+1中是c+2的地址,故*(cpp+1)为c+2,类型为char**
c+2 c是char**类型 c+2跳过2个char*来到"POINT"的首地址,也就是P的地址,P的地址为char*类型
c+2中为P的地址的地址
*(c+2)为p的地址
-----------------
*/
// 先运行++ 在解引用
printf("%s\n", **++cpp);//POINT
/*
此时cpp指向的位置是cp[1] --> c+2(int**类型)
++cpp --> (cpp+1) --> cpp此时指向的是cp[2] --> c+1(int**类型)
即cpp = (c+1)的地址
*++cpp = *(c+1的地址) = c+1 = cp[2]
-- * ++cpp = --cp[2]= c+1-1 = c(int**类型,存储c[]首元素的地址) 注意cp[2]内的值也改了
*-- * ++cpp = *(c)=数组c[]的首元素 = c[0](char*类型)
*-- * ++cpp + 3 = c[0] + 3 = c[0]向后跳过3个char
------
*/
printf("%s\n", *-- * ++cpp + 3);//ER
/*
此时cpp指向的元素是cp[2];
cpp[-2] = *(cpp-2),
cpp-2:cpp向后跳过2个char**类型的元素,此时cpp指向的元素为cp[0]
*(cpp-2) = c+3
*cpp[-2] = *(*(cpp-2) ) = *(c+3)
c+3 = c[3]的地址
*(c+3) = c[3]
*cpp[-2] + 3 = c[3] + 3
-------
*/
printf("%s\n", *cpp[-2] + 3);//ST
/*
此时cpp指向的位置是cp[2]
cpp[-1] = *(cpp-1)
cpp-1指向的元素是cp[1]
*(cpp-1) = cp[1] = c+2
cpp[-1][-1] = *(*(cpp-1)-1) = *(c+2-1) = *(c+1)
c+1指向的元素为c[1]
*(c+1) = c[1]
cpp[-1][-1] + 1 = c[1]+1
-------------
*/
printf("%s\n", cpp[-1][-1] + 1);//EW
return 0;
}
八
int main()
{
int arr[] = { 1,5,9,22 };
int* p = arr;
printf("%d", --*++p + 1);
return 0;
}