指针和数组笔试题解析:涉及strlen与sizeof的多组详细辨析
文章目录
1. 一维数组
关于数组名:
数组名是数组首元素的地址, 但是, 有两个例外:
- sizeof(数组名) - 数组名表示整个数组,计算的是整个数组的大小,单位是字节
- &数组名 - 数组名也表示整个数组,取出的是整个数组的地址
- 除了这两个例外,见到的所有数组名都表示首元素的地址
int main()
{
int a[] = { 1,2,3,4 };
int* p = a;
int(*p)[4] = &a;
//差4
p;
p + 1;
//相等
pa;
pa + 1;
//a - int*
//&a - int(*)[4]
printf("%d\n", sizeof(a));//16,a作为数组名单独存放在sizeof内部,计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(a + 0));//a并非单独存放在sizeof内部,也没有&,所以数组名a就是首元素的地址
//a+0还是数组首元素的地址,是地址大小就是4/8个字节
printf("%d\n", sizeof(*a));//a是首元素的地址,*a就是首元素,sizeof(*a)算的就是首元素的大小 - 4
//a - int*
//*a - int
printf("%d\n", sizeof(a + 1));//a是首元素的地址,a+1是第二个元素的地址,sizeof(a+1)计算的是指针的大小 - 4/8
//a - int*
//a+1,跳过一个int
printf("%d\n", sizeof(a[1]));//a[1]就是数组的第二个元素,sizeof(a[1])的大小 - 4个字节
printf("%d\n", sizeof(&a));//&a取出数组的地址,也是地址 - 4/8个字节
printf("%d\n", sizeof(*&a));//&a是数组的地址,是是指指针类型,*&a是对数组指针解引用,访问一个数组的大小 - 16字节
//sizeof(*&a) ==> sizeof(a) =16
printf("%d\n", sizeof(&a + 1));//&a数组的地址,&a+1跳过整个数组,&a+1还是地址,是4/8个字节
printf("%d\n", sizeof(&a[0]));//a[0]是数组的第一个元素,&a[0]是第一个元素的地址,是4/8个字节
printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一个元素的地址,&a[0]就是第二个元素的地址,是4/8个字节
//&a[0] - int*
//&a[0]+1 - &a[1]
return 0;
}
& - 取地址操作符; * - 解引用操作符
1.1 字符数组{}型
1.1.1 sizeof(arr)
- sizeof是计算对象或者类型创建的对象所占空间的大小,单位是字节
- sizeof是操作符,不是函数
char arr[] = { 'a','b','c','d','e','f' };//6个元素
printf("%d\n", sizeof(arr));//arr是数组名,并且是单独放在sizeof内部,计算的是数组总大小,单位是字节 - 6
printf("%d\n", sizeof(arr + 0));//arr是数组名,并非单独放在sizeof内部,arr表示首元素的地址
//是地址大小就是4/8
printf("%d\n", sizeof(*arr));//arr是首元素的地址,*arr就是首元素,sizeof计算的是首元素的大小 - 1字节
printf("%d\n", sizeof(arr[1]));//arr[1]是数组的第二个元素,sizeof(arr[1])计算的是第二个元素的大小 - 1字节
printf("%d\n", sizeof(&arr));//&arr - char(*)[6]
//取出的是数组的地址,计算数组地址的大小,是地址就是4/8字节
printf("%d\n", sizeof(&arr + 1));//&arr是数组的地址,&arr + 1跳过整个数组,指向'f'的后边,
//&arr+1的本质还是地址,是地址就是4/8字节
printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]是'a'的地址,&arr[0] + 1是’b'的地址也是4/8个字节
1.1.2 strlen(arr)
- strlen 求字符串长度的,计算的是字符串中\0之前出现的字符的个数
- 统计到\0为止,如果没有看到\0,会继续往后找
- strlen 是库函数
- 字符串的结束标志是’\0’,ASCII码值是0
printf("%d\n", strlen(arr));//随机值,arr是数组名,但是没有放在sizeof内部,也没&,arr就是首元素的地址
//strlen得到arr后,从arr数组首元素的地方开始计算字符串的长度,直到\0,但是arr数组中没有\0,arr内存的后面是否有\0
//在什么位置是不确定的,所以\0之前出现的字符是随机的
printf("%d\n", strlen(arr + 0));//arr是数组首元素的地址,arr+0还是首元素的地址 - 随机值
printf("%d\n", strlen(*arr));//arr是数组首元素的地址,*arr是首元素 - 'a' - 97
//strlen就把'a'的ASCII码值97当成了地址
//error 会非法访问内存
printf("%d\n", strlen(arr[1]));//err arr[1] - 'b' - 98
printf("%d\n", strlen(&arr));//随机值,&arr是数组的地址,数组的地址也是指向数组的起始位置,和第一个案例一样
printf("%d\n", strlen(&arr + 1));//随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
1.2 字符数组“”
1.2.1 sizeof(arr)
char arr[] = "abcdef";//7
printf("%d\n", sizeof(arr));//4/8
printf("%d\n", sizeof(arr + 0));//1
printf("%d\n", sizeof(*arr));//1
printf("%d\n", sizeof(arr[1]));//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
1.2.2 strlen(arr)
printf("%d\n", strlen(arr));//6
printf("%d\n", strlen(arr + 0));//6
printf("%d\n", strlen(*arr));//err
printf("%d\n", strlen(arr[1]));//err
printf("%d\n", strlen(&arr));//6
printf("%d\n", strlen(&arr + 1));//随机
printf("%d\n", strlen(&arr[0] + 1));//5
1.3 char*
1.3.1 sizeof ( p )
小结:*p == *(p+0) == p[0]
int arr[10];
int* p=arr;//p == arr
arr[i] --> p[i]//arr[i]能写的p[i]也能写
char* p = "abcdef";
printf("%d\n", sizeof(p));//计算一个指针变量的大小 - 0x0012ff40 - 4/8
printf("%d\n", sizeof(p + 1));//4/8 - 0x0012ff41
printf("%d\n", sizeof(*p));//1 - char*解引用
printf("%d\n", sizeof(p[0]));//*p == *(p+0) == p[0] -第一个元素的大小 - 1字节
printf("%d\n", sizeof(&p));//0x9912ff40 - 4/8
printf("%d\n", sizeof(&p + 1));//跳过整个p - 4/8
printf("%d\n", sizeof(&p[0] + 1));//指向b - 4/8
//类比:
int* p2;
// p2+1 跳过一个int
char* p;
char* *pp=&p;
// pp+1 跳过一个char*对象
1.3.2 strlen ( p )
printf("%d\n", strlen(p));//6
printf("%d\n", strlen(p + 1));//5
printf("%d\n", strlen(*p));//指向a - 传值97 - err
printf("%d\n", strlen(p[0]));//指向第一个元素 - 97 - err
printf("%d\n", strlen(&p));//如0x0012ff40 - 并不知道何时遇到\0 - 随机值
printf("%d\n", strlen(&p + 1));//跳过&p整体 - 并不知道何时遇到\0 - 随机值
printf("%d\n", strlen(&p[0] + 1));//指向b的地址,再向后数 - 5
2. 二维数组
二维数组也是数组,a就是数组名
2.1 sizeof
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));//a是二维数组的数组名,数组单独放在sizeof内部,计算的是数组的总大小,单位是字节
//3*4*4=48
printf("%d\n", sizeof(a[0][0]));//a[0][0]是一个整型元素,大小是四个字节
printf("%d\n", sizeof(a[0]));//把二维数组的每一行看作一维数组的时候,a[0]是第一行的数组名,第一行的数组名单独放在sizeof内部
//计算的是第一行的总大小 - 16字节
printf("%d\n", sizeof(a[0] + 1));//a[0]虽然是第一行的数组名,但是没有单独放在sizeof内部
//a[0]是第一行的数组名,不表示第一行整个数组,而是第一行首元素的地址,a[0]-->&a[0][0]
//a[0] + 1,跳过一个int,是a[0][1]的地址
printf("%d\n", sizeof(*(a[0] + 1)));//a[0] + 1是第一行第二个元素的地址,所以*(a[0] + 1)就是a[0][1] - 4字节
printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,没有单独放在sizeof内部,也没有&,所以a就是数组首元素的地址
//二维数组,我们把它想成一维数组,它的第一个元素就是二维数组的第一行
//a就是第一行的地址 int(*)a[4]
//a+1就是第一行的地址 - 4字节
//a - &a[0]
//a+1 - &a[1]
//a+2 - &a[2]
printf("%d\n", sizeof(*(a + 1)));//a + 1是第二行的地址,*(a+1)找到的就是第二行 - 16字节
//*(a+1) --> a[1]
printf("%d\n", sizeof(&a[0] + 1));//&a[0]是第一行的地址,&a[0] + 1就是第二行的地址 - 4/8
printf("%d\n", sizeof(*(&a[0] + 1)));//&a[0] + 1第二行的地址,*(&a[0] + 1)拿到第二行 - 16
//*(&a[0] + 1)-> a[1]
printf("%d\n", sizeof(*a));//a表示首元素的地址,就是第一行的地址 - &a【0】
//*a -> *(a+0) -> a[0]
//*a 拿到第一行
printf("%d\n", sizeof(a[3]));//类型是:int [4]
//二维数组的第四行,虽然没有第四行,但是可判断出类型是int [4]
//任何一个表达式都有两个属性
//2+7
//值属性:8
//类型属性:int
return 0;
}
2.1.1 截断,对a[3]作出解释
int main()
{
short num = 20;
int a = 1;
//sizeof内部表达式不参与运算
printf("%d\n", sizeof(num = a + 5));//2
//在编译期间被处理,因此只看类型 - num类型为short - 2字节
printf("%d\n", num);//20
return 0;
}
2.1.2 总结:
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。