🐱作者:一只大喵咪1201
🐱专栏:《C语言学习》
🔥格言:你只管努力,剩下的交给时间!
经过前面四篇文章对指针详细讲解,相信各位小伙伴已经了解到了各种各样的指针以及它们的使用方法,下面本喵带着大家做一些习题来检验下学习成果吧。
习题一:
#include <stdio.h>int main()
{int a[] = { 1,2,3,4 };printf("%dn", sizeof(a));printf("%dn", sizeof(a + 0));printf("%dn", sizeof(*a));printf("%dn", sizeof(a + 1));printf("%dn", sizeof(a[1]));printf("%dn", sizeof(&a));printf("%dn", sizeof(*&a));printf("%dn", sizeof(&a + 1));printf("%dn", sizeof(&a[0]));printf("%dn", sizeof(&a[0] + 1));return 0;
}
我们知道,
一维数组的数组名的本质是数组首元素的地址。
但是有俩个特例
- &数组名
- sizeof(数组名)
这俩个特例中,数组名表示的是整个数组。
知道了这个知识点后便可以解决上面的代码,上面代码的输出结果是什么呢?可以自己尝试着做一下。
下面本喵进行一下详细的分析。
int a[] = { 1,2,3,4 };
该数组有4个元素,每个元素的整型。
printf("%dn", sizeof(a));
操作符sizeof中的操作数只有数组名,所以此时求的是整个数组所占内存空间的大小,结果是16,也就是16个字节。
printf("%dn", sizeof(a + 0));
- 操作数是数组名加一个整型0,所以不是单独的一个数组名,此时数组名的本质就是数组首元素的地址。
- 首元素地址加一个0得到的还是首元素的地址。
- 首元素的地址是一个int*类型的指针变量,所以其结果是4或者8,在32位平台上是4,在64位平台上是8。
printf("%dn", sizeof(*a));
- 操作数是数组名解引用,不是单独的数组名。
- 此时数组名的本质是数组首元素的地址。
- 对首元素地址解引用后得到的是数组中第一个元素。
- 所以它的大小是一个整型的大小,结果是4。
printf("%dn", sizeof(a + 1));
- 操作数是数组名加整型1,不是单独的数组名
- 此时数组名的本质是数组首元素的地址。
- 加1后变成了数组中第二个元素的地址,也就是元素2的地址。
- 该地址是int*类型的指针变量。
- 所以大小是4或者8个字节(32位平台是4,64位平台是8)。
printf("%dn", sizeof(a[1]));
- 操作数是数组中下标为1的元素,也就是第二个元素。
- 其大小是4个字节,所以结果是4。
printf("%dn", sizeof(&a));
- 操作数是&数组名,此时取出的是整个数组的地址。
- 该地址的数据类型是int (*)[4],是一个数组指针变量类型。
- 归根到底还是一个地址,所以结果是4或者8。
printf("%dn", sizeof(*&a));
- 操作数是*&a。
- 解引用操作符*和取地址操作符&相互抵消,剩下的只有数组名。
- sizeof的操作数只有数组名时,其本质是整个数组。
- 结果是16。
printf("%dn", sizeof(&a + 1));
- 操作数是&a+1
- &a得到的是整个数组的地址,该指针针的类型是int (*)[4]。
- 加1后跳过了整个数组,指向了内存中下一个int (*)[4]的地址。
- 归根到底还是一个地址,所以结果是4或者8。
printf("%dn", sizeof(&a[0]));
- 操作数是&a[0]。
- a[0]得到的是数组中的第一个元素,再对其取地址。
- 得到的就是数组首元素的地址。
- 所以结果是4或者8。
printf("%dn", sizeof(&a[0] + 1));
- 操作数是&a[0]+1。
- &[0]得到的是数组首元素的地址。
- 加1后得到的是数组中第二个元素的地址
- 数据类型是int*类型的指针变量。
- 所以结果是4或者8。
综合上面的分析,由于本喵使用的编译器是32位的,将每行代码所分析的结果注释到对应代码的后面
可以看到输出的结果与我们所分析的一致。
习题一:
int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%dn", sizeof(arr));printf("%dn", sizeof(arr + 0));printf("%dn", sizeof(*arr));printf("%dn", sizeof(arr[1]));printf("%dn", sizeof(&arr));printf("%dn", sizeof(&arr + 1));printf("%dn", sizeof(&arr[0] + 1));return 0;
}
char arr[] = { 'a','b','c','d','e','f' };
这是一个字符数组,数组中有6个元素。
printf("%dn", sizeof(arr));
- 操作数是数组名。
- 此时数组名的本质是整个数组。
- 所以结果是整个数组的大小,结果是6。
printf("%dn", sizeof(arr + 0));
- 操作数是arr+0
- 并不是一个单独的数组名,此时数组名的本质是数组首元素的地址
- 加0后仍然是数组首元素的地址
- 该地址是char*类型的指针
- 结果是4或者8
printf("%dn", sizeof(*arr));
- 操作数是*arr,不是单独的数组名
- 此时数组名的本质是数组首元素的地址
- 解引用后得到的是数组中的第一个元素
- 该元素的数据类型是char类型
- 结果是1
printf("%dn", sizeof(arr[1]));
- 操作数是arr[1]
- 得到是数组中下标为1的元素
- 该元素的数据类型是char类型
- 结果是1
printf("%dn", sizeof(&arr));
- 操作数是&arr,取出的是整个数组的地址
- 数据类型是char (*)[6],是一个数组指针
- 归跟到底还是一个地址
- 结果是4或者8
printf("%dn", sizeof(&arr + 1));
- 操作数是&arr+1
- &arr取出的是整个数组的地址,是一个数据类型是char (*)[6]类型的指针
- 加1后跳过了整个数组,指向了下一个char (*)[6]类型数组的地址
- 下一个数组的地址归根到底还是一个地址
- 结果是4或者8
printf("%dn", sizeof(&arr[0] + 1));
- 操作数是&arr[0]+1
- &arr[0]得到的是数组首元素的地址
- 加1后得到的是数组中第二个元素的地址
- 数据类型是char*类型的指针
- 所以结果是4
综合上面的分析,由于本喵使用的编译器是32位的,将每行代码所分析的结果注释到对应代码的后面
可以看到输出的结果与我们所分析的一致。
习题二:
#include <string.h>int main()
{char arr[] = { 'a','b','c','d','e','f' };printf("%dn", strlen(arr));printf("%dn", strlen(arr + 0));printf("%dn", strlen(*arr));printf("%dn", strlen(arr[1]));printf("%dn", strlen(&arr));printf("%dn", strlen(&arr + 1));printf("%dn", strlen(&arr[0] + 1));return 0;
}
- 这段代码中使用的是strlen()库函数来求字符串的长度。
- strlen库函数的本质是寻找字符串中的字符结束标志
- 然后将 之前的字符个数统计出来
char arr[] = { 'a','b','c','d','e','f' };
这是一个字符数组,有6个元素,每个元素都是char类型的。
printf("%dn", strlen(arr));
- 实参是arr,并不是特例中的情况
- 此时数组名的本质是数组首元素的地址
- 由于该数组中没有 ,所以strlen函数找不到统计结束的标志
- 所以结果是一个随机数,但是这个随机数一定大于等于6
printf("%dn", strlen(arr + 0));
- 实参是arr+0
- arr是数组首元素的地址,加0后仍然是数组首元素的地址
- 所以结果与上语句代码的结果一样
printf("%dn", strlen(*arr));
- 实参是*arr
- 此时的arr是数组首元素的地址
- 解引用后得到的是数组中的第一个元素,也就是字符’a’
- 此时将字符a当作是一个地址传参给了strlen库函数
- 因为字符a的ASCII码值是97,所以相当于传参了一个char*类型的指针,其值是97
- 地址为97的内存空间是供内核使用的,用户没有访问权限,所以编译器就会报错。
- 十进制97转化成16进制后便是61
- 报错内容中告诉我们访问地址0x00000061时发生错误
- 就是说这个内存空间是不允许我们访问的
printf("%dn", strlen(arr[1]));
- 实参是arr[1]
- 得到的是数组中第二个元素,也就是’b’
- 字符b的ASCII码值是98,转化成16进制后是62
- 与上面的代码一样,同样是将62作为地址传给了strlen库函数
- 而0x00000062的内存空间同样是不可访问的,也会报错
printf("%dn", strlen(&arr));
- 实参是&arr,是特例中的一种情况
- 取出的是整个数组的地址
- 但是整个数组的地址表现形式就是数组首元素的地址,其值与arr一样
- 虽然&arr的数据类型是char (* )[6],但是在传给strlen库函数后会被强制转化成为cahr* 类型的指针
- 所以结果也是一个随机值,结果大于等于6,与第一个输入语句结果相同。
printf("%dn", strlen(&arr + 1));
- 实参是&arr+1
- &arr取出的是整个数组的地址
- 加一后就跳过了该数组,指向了下一个char (*)[6]类型数组的地址
- 由于并不知道此时指向数组中的元素分布情况,所以得出的结果是一个随机值。
printf("%dn", strlen(&arr[0] + 1));
- 实参是&arr[0]+1
- &arr[0]得到的是数组首元素的地址
- 加1后得到的是数组第二个元素的地址
- 将此地址传给strlen库函数后,由于没有 ,所以仍然不知道要统计到哪里结束
- 但是这个随机值要必上面的随机值小一个数。
综合上面的分析,将每行代码所分析的结果注释到对应代码的后面
结果与我们所分析的一致。
该代码在指向过程中会报一些警告,我们直接忽略就好了,有兴趣的小伙伴可以尝试修复一下。
习题三:
int main()
{char arr[] = "abcdef";printf("%dn", sizeof(arr));printf("%dn", sizeof(arr + 0));printf("%dn", sizeof(*arr));printf("%dn", sizeof(arr[1]));printf("%dn", sizeof(&arr));printf("%dn", sizeof(&arr + 1));printf("%dn", sizeof(&arr[0] + 1));return 0;
}
char arr[] = "abcdef";
这是一个字符串数组,数组中有7个元素,每个元素都是char类型。
相当于
char arr[] = { 'a','b','c','d','e','f','