前言:
除了sizeof()单独放数组名和&数组名,其他的数组名都仅仅代表首元素地址,
接下来我们就靠一些练习来巩固一下对指针的学习吧.
int main()
{
//一维数组
int a[] = { 1,2,3,4 };//4个元素,每个元素是int类型
printf("%d\n", sizeof(a));
//sizeof里面直接放数组名,计算的是整个数组的大小,所以是16
printf("%d\n", sizeof(a + 0));//这里数组名表示的是首元素地址,地址都是4或者8个字节
printf("%d\n", sizeof(*a)); //4个字节,相当于a[0]
printf("%d\n", sizeof(a + 1));//表示第二个元素的地址,所以是4个或者8个字节
printf("%d\n", sizeof(a[1]));//第二个元素的大小,4个字节
printf("%d\n", sizeof(&a));//取到的是整个数组的地址,由于是地址,所以是4/8个字节
printf("%d\n", sizeof(*&a)); //16 对数组指针解引用访问一个数组的大小,单位是字节,等价于
sizeof(a)
printf("%d\n", sizeof(&a + 1));//由于&a是一个指针数组类型,+1跳过一个数组,指向最后数组的后一个元素的地址,所以是4/8
printf("%d\n", sizeof(&a[0]));//取出的是第一个元素的地址,地址的大小是4/8
printf("%d\n", sizeof(&a[0] + 1));//取出的是第二个元素的地址,地址的大小是4/8
return 0;
}
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr)); //数组的大小,6个字节
printf("%d\n", sizeof(arr + 0));//首元素地址+1,是地址就是4/8个字节
printf("%d\n", sizeof(*arr));//首元素的大小,类型是char,所以是1个字节
printf("%d\n", sizeof(arr[1]));//第二个元素的大小,一个字节
printf("%d\n", sizeof(&arr));//整个数组的地址,4/8字节
printf("%d\n", sizeof(&arr + 1));//跳过整个数组后面的地址,地址就是4/8字节
printf("%d\n", sizeof(&arr[0] + 1));//跳过第一个元素的地址,地址就是4/8字节
//strlen是求字符串长度的,统计的是\0之前所有的元素个数
printf("%d\n", strlen(arr)); //arr是首元素地址,因为字符数组中没有手动添加\0,所以我们不知道后面到什么地方才会有\0出现,所以大小是随机值 大于等于6
printf("%d\n", strlen(arr + 0)); //随机值,同上
printf("%d\n", strlen(*arr)); // *arr是首元素,等价于字符a->97,strlen就把97当做一个地址
//97作为地址直接进行访问就是非法访问
printf("%d\n", strlen(arr[1])); //字符b,同样是非法访问
printf("%d\n", strlen(&arr)); //把数组指针传给了char*,类型发生变化但是值没变,随机值
printf("%d\n", strlen(&arr + 1)); //随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); //加上\0,一共7个字节
printf("%d\n", sizeof(arr + 0));//地址的大小就是4/8字节
printf("%d\n", sizeof(*arr));//a的大小是1个字节
printf("%d\n", sizeof(arr[1]));//b大小也是一个字节
printf("%d\n", sizeof(&arr));//取出整个数组的地址,地址就是4/8字节
printf("%d\n", sizeof(&arr + 1));//跳过数组,也是4/8字节
printf("%d\n", sizeof(&arr[0] + 1));//地址,4/8字节
printf("%d\n", strlen(arr)); //6字节
printf("%d\n", strlen(arr + 0));//同上
printf("%d\n", strlen(*arr)); //传进去的是97会报错
printf("%d\n", strlen(arr[1]));//同上
printf("%d\n", strlen(&arr));//6字节
printf("%d\n", strlen(&arr + 1));//跳过了整个数组,所以是随机值
printf("%d\n", strlen(&arr[0] + 1));//从第二个元素开始,所以是5字节
char* p = "abcdef";
//把字符串的首地址存在p里面
printf("%d\n", sizeof(p)); //首元素地址,所以是4/8字节
printf("%d\n", sizeof(p + 1)); //4/8 本质上就是地址+1,仍然是地址
printf("%d\n", sizeof(*p)); //1 *p == 'a'
printf("%d\n", sizeof(p[0])); //同上
printf("%d\n", sizeof(&p)); //4/8 p变量的起始地址 类型是char**二级指针类型
printf("%d\n", sizeof(&p + 1)); //跳过一个char*,还是地址,4/8
printf("%d\n", sizeof(&p[0] + 1)); //地址,4/8
printf("%d\n", strlen(p)); //6字节
printf("%d\n", strlen(p + 1)); //跳过首元素,所以是五个字节
printf("%d\n", strlen(*p)); //err
printf("%d\n", strlen(p[0])); //err
printf("%d\n", strlen(&p)); //char**,这个地址有没有\0不可知,所以是随机值
printf("%d\n", strlen(&p + 1)); //随机值
printf("%d\n", strlen(&p[0]+1)); //5
int a[3][4] = { 0 };
printf("%zd\n", sizeof(a)); //48 数组名单独放在sizeof内部,表示整个数组,所以计算的是整
个数组的大小,单位是字节 48
printf("%zd\n", sizeof(a[0][0]));//4
printf("%zd\n", sizeof(a[0])); //16 二维数组是数组的数组,a[0]单独放在sizeof内部,就计算的
是整个第一行的大小
printf("%zd\n", sizeof(a[0] + 1)); //4/8 a[0]并非单独放在sizeof内部,所以a[0]表示数组首元
素的地址, 也就是第一行第一个元素的地址,a[0] <-->&a[0][0],所以 a[0]+1表示&a[0][1]
printf("%zd\n", sizeof(*(a[0] + 1)));//4 对第一行第二个元素进行解引用
printf("%zd\n", sizeof(a + 1)); //4/8 第二行地址
printf("%zd\n", sizeof(*(a + 1))); //16 第二行的大小
printf("%zd\n", sizeof(&a[0] + 1)); //4/8 第二行的地址
printf("%zd\n", sizeof(*(&a[0] + 1)));//16 第二行的大小
printf("%zd\n", sizeof(*a)); //16 第一行大小
printf("%zd\n", sizeof(a[3])); //16 不会越界,因为编译器会根据变量的类型直接进行判断,并不会
真的去访问
//表达式有两个属性,一个是值属性,一个是类型属性
总结:
数组名的意义:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. & 数组名,这里的数组名表示整个数组,取出的是整个数组的地址。其他数组名都表示首元素的地址.
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//a这里表示首元素的地址,+就是第二个元素的地址,解引用得到2
//ptr指向数组的最后一个元素的后面的一个int的地址,-1则指向最后一个元素,解引用答案是5
//程序的结果是什么?
//2 5
//注:默认是x86的环境
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
//考点:指针+1加几个字节? 取决于指针的类型
//注:十六进制
printf("%p\n", p + 0x1); //0x00100014
printf("%p\n", (unsigned long)p + 0x1); //0x00100001
printf("%p\n", (unsigned int*)p + 0x1); //0x00100004
return 0;
}
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);
//默认小端字节序
//内存 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
//ptr2指向01后面的00 Ox 02 00 00 00 还原出来就是2000000
//答案 4,2000000
return 0;
}
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]); //1
return 0;
}
int main()
{
int a[5][5];
int(*p)[4];
p = a;
//类型不合适
//a - int(*)[5]
//p - int(*)[4]
//画图
printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//%p打印就是把-4转成补码形式再转16进制
//指针相减是表示两个指针之间的元素个数
//10000000000000000000000000000100
//11111111111111111111111111111011
//11111111111111111111111111111100 -->地址FFFFFFFC
//答案是FFFFFFFC,-4
return 0;
}
7.6 难度: **
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 main()
{
char* a[] = { "work","at","alibaba" };
//a的每个元素是char*的,存的是首字符地址
//答案 at
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
int main()
{
//++的优先级高于*号
char* c[] = { "ENTER","NEW","POINT","FIRST" };
char** cp[] = { c + 3,c + 2,c + 1,c };
char*** cpp = cp;
printf("%s\n", **++cpp); //p的地址 POINT
printf("%s\n", *-- * ++cpp + 3); //得到的是e的地址再+3打印出来就是ER
printf("%s\n", *cpp[-2] + 3); //ST
printf("%s\n", cpp[-1][-1] + 1);//EW
return 0;
}