深入理解指针(6)
目录
1 sizeof和strlen的对⽐
1.1 sizeof
编辑1.2strlen
1.3 sizeof 和 strlen的对⽐
2 数组和指针笔试题解析
2.1 ⼀维数组
编辑
2.2 字符数组
3 指针运算笔试题解析
3.1 题⽬1:
编辑3.2 题目2
3.3 题目3
3.4 题目4
3.5 题目5
3.6 题目6
3.7 题目7
1 sizeof和strlen的对⽐
1.1 sizeof
sizeof 计算变量所占内存空间⼤⼩的,单位是字节,
如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的⼤⼩。
sizeof 只关注占⽤内存空间的⼤⼩,不在乎内存中存放什么数据。
1.2strlen
sizeof(数组名)
数组名表示整个数组,计算的是整个数组的大小
int main()
{
char arr1[3] = { 'a', 'b', 'c' };
char arr2[] = "abc";
printf("%zu\n", strlen(arr1));//随机值
printf("%zu\n", strlen(arr2));//3printf("%zu\n", sizeof(arr1));//3
printf("%zu\n", sizeof(arr2));//4
return 0;
}
1.3 sizeof 和 strlen的对⽐
sizeof1. sizeof是操作符2. sizeof计算操作数所占内存的⼤⼩,单位是字节3. 不关注内存中存放什么数据
strlen1. strlen是库函数,使⽤需要包含头⽂件 string.h2. srtlen是求字符串⻓度的,统计的是 \0 之前字符的个数3. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界
2 数组和指针笔试题解析
数组名的意义:1. sizeof(数组名),这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩。2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址。3. 除此之外所有的数组名都表⽰⾸元素的地址。
2.1 ⼀维数组
int main()
{
int a[] = { 1,2,3,4 };//4 * 4 = 16printf("%zu\n", sizeof(a));//16, a是数组名,数组名单独放在sizeof中,数组名表示整个数组,计算的是整个数组的大小,单位是字节
printf("%zu\n", sizeof(a + 0));//4/8,a是数组名,并没有单独放在sizeof内部,也没有&,所以a就是首元素的地址
//a+0,还是首元素的地址,sizeof(a + 0)计算的是一个地址的大小,4/8
printf("%zu\n", sizeof(*a));//a是数组名,并没有单独放在sizeof内部,也没有&,所以a就是首元素的地址
//*a就是首元素==a[0],就是整数1,sizeof(*a)就是4个字节
printf("%zu\n", sizeof(a + 1));//4/8, a就是首元素的地址,a+1就是第二个元素的地址,sizeof(a + 1)计算的是地址的大小
printf("%zu\n", sizeof(a[1]));//4,a[1]就是数组的第二个元素,大小是4个字节
printf("%zu\n", sizeof(&a));//&a-取出的是数组的地址,数组的地址也是地址呀,是地址大小就是4/8个字节
//&a 的特殊性体现在+-整数
//int (*p)[4] = &a;
printf("%zu\n", sizeof(*&a));//16,&a-取出的是数组的地址,他的类型是int(*)[4],对于数组指针解引用,访问的是这个数组,大小就是16个字节
//2. *&a == a, sizeof(*&a) == sizeof(a)
printf("%zu\n", sizeof(&a + 1));//4/8,&a是数组的地址,&a+1是跳过数组后的地址,是地址就是4/8个字节
printf("%zu\n", sizeof(&a[0]));//4/8,a[0]是第一个元素,&a[0]就是第一个元素的地址,大小就是4/8
printf("%zu\n", sizeof(&a[0] + 1)); //4/8, &a[0]就是第一个元素的地址,&a[0] + 1就是第二个元素的地址,大小就是4/8return 0;
}
2.2 字符数组
#include <stdio.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };printf("%zu\n", sizeof(arr));//6, arr表示整个数组,sizeof(arr)计算的是整个数组的大小
printf("%zu\n", sizeof(arr + 0));//4/8, arr就是首元素的地址,只要是地址大小就是4/8个字节
printf("%zu\n", sizeof(*arr));//1,arr就是首元素的地址,*arr就是首元素,sizeof(*arr)计算的是首元素的大小
printf("%zu\n", sizeof(arr[1]));//1, arr[1]是第二个元素,大小就是1个字节
printf("%zu\n", sizeof(&arr));//4/8,&arr取出的是数组的地址,数组的地址也是地址,大小就是4/8个字节
printf("%zu\n", sizeof(&arr + 1));//4/8, &arr取出的是数组的地址,&arr+1是跳过数组后的地址,跳过去后还是地址,大小就是4/8个字节
printf("%zu\n", sizeof(&arr[0] + 1));//4/8,&arr[0] + 1是数组第二个元素的地址,大小就是4/8个字节
return 0;
}
代码2:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%zu\n", strlen(arr));//随机值,arr是数组首元素的地址,字符串中没有\0
printf("%zu\n", strlen(arr + 0));//随机值,arr是数组首元素的地址,arr+0还是首元素的地址,字符串中没有\0
//printf("%zu\n", strlen(*arr));//arr是数组首元素的地址,*arr是首元素-'a'-97
//非法访问内存 - 程序就会崩溃
//printf("%zu\n", strlen(arr[1]));//err,非法访问内存,崩溃,arr[1] == 'b' == 98
printf("%zu\n", strlen(&arr));//随机值,&arr是数组的地址,从数组的地址也就是数组的起始位置开始向后数字符串的长度,要找\0,但是没有\0
//所以是随机值
printf("%zu\n", strlen(&arr + 1));//随机值,&arr+1是跳过整个数组后的地址,向后找\0,也是随机值
printf("%zu\n", strlen(&arr[0] + 1));//随机值,&arr[0] + 1是第二个元素的地址
return 0;
}
代码3:
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%zu\n", sizeof(arr));//7
printf("%zu\n", sizeof(arr + 0));//4/8
printf("%zu\n", sizeof(*arr));//1
printf("%zu\n", sizeof(arr[1]));//1
printf("%zu\n", sizeof(&arr));//4/8
printf("%zu\n", sizeof(&arr + 1));//4/8
printf("%zu\n", sizeof(&arr[0] + 1));//4/8
return 0;
}
代码4:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%zu\n", strlen(arr));//6
printf("%zu\n", strlen(arr + 0));//6
//printf("%zu\n", strlen(*arr));//err
//printf("%zu\n", strlen(arr[1]));//err
printf("%zu\n", strlen(&arr));//6
printf("%zu\n", strlen(&arr + 1));//随机值
printf("%zu\n", strlen(&arr[0] + 1));//5
return 0;
}
代码5:
#include <stdio.h>
int main()
{
char* p = "abcdef";
printf("%zu\n", sizeof(p));//4/8, p是指针变量
printf("%zu\n", sizeof(p + 1));//4/8, p+1就是b的地址
printf("%zu\n", sizeof(*p));//1
printf("%zu\n", sizeof(p[0]));//1, p[0]->*(p+0) -> *p
printf("%zu\n", sizeof(&p));//4/8, &p是指针变量p的地址,是一个二级指针
printf("%zu\n", sizeof(&p + 1));//4/8
printf("%zu\n", sizeof(&p[0] + 1));//4/8, &p[0] + 1是b的地址
return 0;
}
代码6:
#include <stdio.h>
#include <string.h>
int main()
{
char* p = "abcdef";
printf("%zu\n", strlen(p));//6
printf("%zu\n", strlen(p + 1));//5
//printf("%zu\n", strlen(*p));//err
//printf("%zu\n", strlen(p[0]));//err
printf("%zu\n", strlen(&p));//随机值,p的内容不确认,p变量在内存中后续的空间内容不确定
printf("%zu\n", strlen(&p + 1));//随机值
printf("%zu\n", strlen(&p[0] + 1));//5return 0;
}
2.3 ⼆维数组
int main()
{
int a[3][4] = { 0 };
printf("%zu\n", sizeof(a));//48
printf("%zu\n", sizeof(a[0][0]));//4
printf("%zu\n", sizeof(a[0]));//16,a[0]是第一行这个一维数组的数组名,单独放在sizeof内部了,a[0]表示第一行这个数组
//sizeof(a[0])计算的是第一行的大小
printf("%zu\n", sizeof(a[0] + 1));//4/8, a[0]就是第一行第一个元素的地址==&a[0][0], a[0]+1是第一行第二个元素的地址
printf("%zu\n", sizeof(*(a[0] + 1)));//4, *(a[0] + 1)是第一行第二个元素
printf("%zu\n", sizeof(a + 1));//4/8, a是二维数组的数组名,这里只能表示数组首元素的地址,也就是第一行的地址
//a+1 就是第二行的地址
//a --> int(*)[4]
printf("%zu\n", sizeof(*(a + 1)));//16,*(a + 1) == a[1]
//a[1]就是第2行的数组名,计算的是整个数组的大小
printf("%zu\n", sizeof(&a[0] + 1));//4/8
//a[0]是第一行的数组名
//&a[0]取出的是第1行的地址
//&a[0] + 1是第2行的地址
printf("%zu\n", sizeof(*(&a[0] + 1)));//16
printf("%zu\n", sizeof(*a));//16,a是二维数组的数组名,这里只能表示数组首元素的地址,也就是第一行的地址
//*a 就是第一行
printf("%zu\n", sizeof(a[3]));//16,不会有越界访问的
//sizeof在计算变量,数组的大小的时候,是通过类型来推导的,不会真实去访问内存空间return 0;
}
int main()
{
short s = 4;
int a = 10;
printf("%zu\n", sizeof(s = a + 2));
printf("s = %hd\n", s);
return 0;
}
3 指针运算笔试题解析
3.1 题⽬1:
#include <stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1);
printf("%d, %d", *(a + 1), *(ptr - 1));return 0;
}
3.2 题目2
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}* p = (struct Test*)0x100000;
//指针+-整数
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);return 0;
}
3.3 题目3
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
3.4 题目4
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>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]);
//-4
//10000000 00000000 00000000 00000100
//11111111 11111111 11111111 11111011
//11111111 11111111 11111111 11111100
//FF FF FF FCreturn 0;
}
|小地址 - 大地址| = 负数
随着数组下标的增长,地址是由低到高变化的
%d - 按照10进制的形式,打印有符号的整数
%d认为内存中存放的是有符号整数的补码
%p - 打印地址的
%p 认为内存放的补码就是地址
%p 打印地址是以16进制的形式打印的
3.5 题目5
#include <stdio.h>
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));return 0;
}
3.6 题目6
#include <stdio.h>
int main()
{
char* a[] = { "work","at","alibaba" };
char** pa = a;pa++;
printf("%s\n", *pa);
return 0;
}
3.7 题目7
#include <stdio.h>
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;
}
①
②
③
④
⑤