家人们欢迎来到小姜的世界,<<点此>>传送门 这里有详细的关于C/C++/Linux等的解析课程,家人们赶紧冲鸭!!!
客官,码字不易,来个三连支持一下吧!!!关注我不迷路!!!
指针和数组综合题
- 指针和数组笔试题详解
- (一)整型数组
- (二)字符串型
- (三)字符串指针
- (四)二维数组
- (五)归纳
- 总结
在本文的开始,我将会以图文代码结合的方式,给大家介绍利用指针和数组的操作看字节大小和字符串长度,大家要抓紧上车,车速较快,把稳方向盘哦!
指针和数组笔试题详解
先在进行算字节和字符串长度时,大家需要了解以下三个概念,这三个概念是进行计算字节和字符串长度的钥匙:
1.sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
2.&数组名,数组名表示整个数组,取出的是整个数组的地址
3.除上述两个以外,所有的数组名都是数组首元素的地址
(一)整型数组
在代码下附有画图解释,大家可以比对着图再根据代码中的解释一一理解。
//1.sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小,单位是字节
//2.&数组名,数组名表示整个数组,取出的是整个数组的地址
//除上述两个以外,所有的数组名都是数组首元素的地址
#include<stdio.h>
int main() {
int a[] = { 1,2,3,4 };
//sizeof(数组名),数组名表示整个数组,计算的是整个数组的大小
printf("%d\n", sizeof(a));//4*4=16个字节
//a+0是首元素地址,数组名不是单独放到sizeof内部,
//此时a表示首元素地址,所以a+0是数组第一个元素的地址
printf("%d\n", sizeof(a + 0));//4/8个字节
//a是数组首元素地址,所以*a是数组首元素大小,单位是字节,整型类型是四个字节
printf("%d\n", sizeof(*a));//4个字节
//a没有单独放到sizeof内部,所以a表示首元素的地址,
//+1表示跳过一个整型,所以a+1是第二个元素的地址
printf("%d\n", sizeof(a + 1));//4/8个字节
//a[1]就是数组第二个元素,计算的就是第二个元素的大小
printf("%d\n", sizeof(a[1]));//4
//取地址a是整个数组的地址,既然是地址,地址的大小就是4/8个字节
//&a ---> 类型:int(*)[4] --- 数组指针
printf("%d\n", sizeof(&a));//4/8个字节
//取地址a以后再解引用,先取出的是整个数组的地址,
//再解引用,取到的是整个数组的大小,
//所以*&a==a,a就是数组名, sizeof(*&a)==sizeof(a)
printf("%d\n", sizeof(*&a));//16个字节
//&a是整个数组的地址,再加1是跳过整个数组指向数组后面的空间,
//而cpu内部是还有空间的,是与a数组一样的数组,所以还是一个地址
printf("%d\n", sizeof(&a + 1));//4/8个字节
//a[0]就是首元素,再取个地址就是首元素地址,既然是个地址,
//那就是4/8个字节
printf("%d\n", sizeof(&a[0]));//4/8个字节
//&a[0]+1是第二个元素的地址
printf("%d\n", sizeof(&a[0] + 1));//4/8个字节
//sizeof的返回类型就是size_t,而size_t又是unsigned int,
//所以根本不需要理会后一个sizeof括号里的值,所以返回的就是size_t类型的字节
//size_t在X86环境下定义为unsigned int,所以是4个字节
//size_t在X64环境下定义为unsigned long,所以是8个字节
printf("%d\n", sizeof(sizeof(a + 1)));//4/8个字节
return 0;
}
第一个printf:
第二个printf:
第三个printf:
第四个printf:
第五个printf:
第六个printf:
第七个printf:
第八个printf:
第九个printf:
第十个printf:
第十一个printf:
(二)字符串型
在代码下附有画图解释,大家可以比对着图再根据代码中的解释一一理解。
#include<stdio.h>
#include<string.h>
int main() {
char arr[] = { 'a','b','c','d','e','f' };//a b c d e f 6个元素
//arr单独放在sizeof内部,计算的是整个数组的大小,单位是字节
printf("%d\n", sizeof(arr));//6个字节
//arr因为没有单独放在sizeof内部,所以是首元素地址,
//+0以后就还是首元素地址,是个地址那就是4/8个字节
printf("%d\n", sizeof(arr + 0));//4/8个字节
//arr没有单独放在sizeof内部,前面还有个*,所以此时的arr表示首元素地址
//*arr是数组的首元素,计算的是数组的首元素大小
printf("%d\n", sizeof(*arr));//1个字节
//arr[1]就是数组的第二个元素
printf("%d\n", sizeof(arr[1]));//1个字节
//取出的是整个数组的地址,同样是一个地址,所以是4/8个字节
printf("%d\n", sizeof(&arr));//4/8个字节
//跳过整个数组指向数组后面的空间的地址,还是个地址
printf("%d\n", sizeof(&arr + 1));//4/8个字节
//&arr[0]+1是第二个元素的地址,也是个地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8个字节
//arr是首元素地址,往后找不到'\0',因为像arr数组这样分装的数组末尾是没有'\0'的,
//这是取决于电脑的,'\0'找不到,那就是随机值了
printf("%d\n", strlen(arr));//随机值
//是arr的地址,是从第一个arr往后找'\0',但一直找不到
printf("%d\n", strlen(arr + 0));//随机值
//*arr是首元素,所以给strlen函数传递的是'a'---ASCII码值为97,
//97这块空间是没有被分配的,97这个地址不能进行访问,所以是非法访问
printf("%d\n", strlen(*arr));//err
//arr[1]是第二个元素,不是地址,所以传给strlen函数的是'b'---ASCII吗值为98
//我们在前面已经学过strlen所传递的是指针,接收的也是指针,所以就是地址,
//而现在传的是98这个非法的未开辟空间的地址,那肯定就是非法访问了
printf("%d\n", strlen(arr[1]));//err
//&arr虽然是数组的地址,但也是从数组起始位置开始的,计算的还是随机值
printf("%d\n", strlen(&arr));//随机值
//&arr+1是跳过整个数组的地址,更不知道什么时候找到'\0'了,也是随机值
printf("%d\n", strlen(&arr + 1));//随机值
//&arr[0]+1是从第二个元素的地址往后找'\0'求字符串长度,但往后找不到'\0'
//也是个随机值
printf("%d\n", strlen(&arr[0] + 1));//随机值
//sizeof只在乎占用内存空间的大小,单位是字节,不关心内存中存的是什么
//strlen是求字符串长度的,统计的是\0之前出现的字符个数,一定要找到'\0'才算结束,所以可能存在越界访问
//sizeof是操作符,strlen是库函数
//
char arr1[] = "abcdef";//a b c d e f '\0' 7个元素
//arr1数组名单独放在sizeof内部计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr1));//7个字节
//arr1没有单独放在sizeof内部,所以是首元素地址,+0表示是首元素的地址
printf("%d\n", sizeof(arr1 + 0));//4/8个字节
//*arr1是数组首元素,大小为1字节
printf("%d\n", sizeof(*arr1));//1个字节
//arr1[1]是数组第二个元素,大小是1字节
printf("%d\n", sizeof(arr1[1]));//1个字节
//&arr1是整个数组的地址,数组的地址也是地址
printf("%d\n", sizeof(&arr1));//4/8个字节
//&arr1+1是跳过整个数组的地址,那也是个地址
printf("%d\n", sizeof(&arr1 + 1));//4/8个字节
//&arr1[0]+1是数组第二个元素的地址
printf("%d\n", sizeof(&arr1[0] + 1));//4/8个字节
//arr1数组名表示首元素地址,strlen是从首元素开始统计'\0'之前出现的字符个数
printf("%d\n", strlen(arr1));//6
//arr1+0是数组首元素地址,所以也是找'\0'之前的字符数
printf("%d\n", strlen(arr1 + 0));//6
//*arr是字符'a'---ASCII码值97,传给strlen是个非法的地址,所以会非法访问
printf("%d\n", strlen(*arr1));//err
//arr1[1]是字符'b'---ASCII码值98,传给strlen是个非法的地址,所以会非法访问
printf("%d\n", strlen(arr1[1]));//err
//&arr1是取到的整个数组的地址,但在strlen的角度来讲你既然传地址给我了,
//我也知道首元素的地址了,从首元素地址往后找'\0'即可
printf("%d\n", strlen(&arr1));//6
//&arr1+1跳过整个数组,统计字符串的长度是随机值,因为找不到'\0'
printf("%d\n", strlen(&arr1 + 1));//随机值
//&arr[0]+1是从第二个字符往后统计字符串长度
printf("%d\n", strlen(&arr1[0] + 1));//5
return 0;
}
第一个printf:
第二个printf:
第三个printf:
第四个printf:
第五个printf:
第六个printf:
第七个printf:
第八个printf:
第九个printf:
第十个printf:
第十一个printf:
第十二个printf:
第十三个printf:
第十四个printf:
第十五个printf:
第十六个printf:
第十七个printf:
第十八个printf:
第十九个printf:
第二十个printf:
第二十一个printf:
第二十二个printf:
第二十三个printf:
第二十四个printf:
第二十五个printf:
第二十六个printf:
第二十七个printf:
第二十八个printf:
(三)字符串指针
在代码下附有画图解释,大家可以比对着图再根据代码中的解释一一理解。
#include<stdio.h>
#include<string.h>
int main() {
const char* p = "abcdef";
//p是指针变量,大小就是4/8个字节
printf("%d\n", sizeof(p));//4/8个字节
//p+1是b的地址,是地址就是4/8个字节
printf("%d\n", sizeof(p + 1));//4/8个字节
//*p就是字符a,因为p指针变量中存放的是a的地址,解引用就是字符a
//那就是字符的大小
printf("%d\n", sizeof(*p));//1个字节
//p[0]==*(p+0)==*p --- 所以还是a字符的大小
printf("%d\n", sizeof(p[0]));//1个字节
//&p取出的是一级指针p的地址,那不就是二级指针嘛,大小为4/8个字节
printf("%d\n", sizeof(&p));//4/8个字节
//&p+1是在p指针上进行操作,是跳过p指针变量后的结果,但还是个指针,所以大小为4/8个字节
printf("%d\n", sizeof(&p + 1));//4/8个字节
//p[0]==*(p+0)==*p *p就是数组中a的值,所以p[0]就是a的值,而&p[0]就是a的地址
//+1就是b的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&p[0] + 1));//4/8个字节
//是求字符串的长度
printf("%d\n", strlen(p));//6
//p+1是b的地址,求字符串长度是从b开始往后找'\0'
printf("%d\n", strlen(p + 1));//5
//*p -- 字符a 这地址给的是97,是非法地址
printf("%d\n", strlen(*p));//err
//p[0] == *(p+0) == *p 地址给的还是97,是个非法地址
printf("%d\n", strlen(p[0]));//err
//&p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值
printf("%d\n", strlen(&p));//随机值
//&p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值
printf("%d\n", strlen(&p + 1));//随机值
//&p[0]+1取出的是b的地址,从b的地址往后数字符串长度为5
printf("%d\n", strlen(&p[0] + 1));//5
return 0;
}
这个是char* p="abcdef“的p指针变量的解析:
第一个printf:
第二个printf:
第三个printf:
第四个printf:
第五个和第六个printf:
第七个printf:
第八个printf:
第九个printf:
第十个和第十一个printf:
第十二个和第十三个print:
第十四个printf:
(四)二维数组
在代码下附有画图解释,大家可以比对着图再根据代码中的解释一一理解。
#include<stdio.h>
int main() {
int a[3][4] = { 0 };//3行4列的整型数组
//a为数组名,表示整个数组的大小
printf("%d\n", sizeof(a));//48个字节=3*4*4
//就是第一个整形元素的字节数
printf("%d\n", sizeof(a[0][0]));//4个字节
//a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的是数组的大小
printf("%d\n", sizeof(a[0]));//16个字节=4*4
//a[0]作为第一行的数组名,没有单独放在sizeof内部,没有取地址,表示的是数组首元素地址,就是a[0][0]的地址
//a[0]+1就是第一行第二个元素的地址,是地址就是4/8个字节
printf("%d\n", sizeof(a[0] + 1));//4/8个字节
//第一行第二个元素的地址进行解引用,求的是第一行第二个元素的大小
printf("%d\n", sizeof(*(a[0] + 1)));//4个字节
//a是二维数组的数组名,数组名表示首行的地址,首行地址加1就是整个第二行的地址
//第二行的地址也是地址,是地址就是4/8个地址
//a+1的类型是:int(*)[4] -- 数组指针
printf("%d\n", sizeof(a + 1));//4/8个地址
//a+1是第二行的地址,*(a+1)表示的是整个第二行,*(a+1) == a[1],整个第二行的大小
printf("%d\n", sizeof(*(a + 1)));//16个字节
//&a[0]拿到的是第一行的地址,再加1则拿到的是第二行的地址,是地址就是4/8个字节
printf("%d\n", sizeof(&a[0] + 1));//4/8个字节
//同理,对第二行的地址解引用,得到的就是第二行的数组名,计算得到的就是第二行的大小
printf("%d\n", sizeof(*(&a[0] + 1)));//16个字节=4*4
//a是数组名,没有单独放到sizeof里,所以a就是首行的地址,所以*a就是数组第一行的所有元素
//计算的就是第一行的大小,*a --- *(a+0) --- a[0]
printf("%d\n", sizeof(*a));//16个字节=4*4
//虽然越界了,如果数组存在第四行,a[3]就是第四行的数组名,所以计算的是第四行的大小,
//数组名单独放在sizeof内部,计算的是第四行的大小,我们只是根据内部的类型进行计算的
printf("%d\n", sizeof(a[3]));//16个字节=4*4
return 0;
}
第一个printf:
第二个printf:
第三个printf:
第四个printf:
第五个printf:
第六个printf:
第七个printf:
第八个peintf:
第九个printf:
第十个printf:
第十一个print:
(五)归纳
数组名的意义:
- sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
- 除此之外所有的数组名都表示首元素的地址。
总结
这个指针和数组的综合题简直是干货满满,把所有的strlen和sizeof类型整理了一下,比较着来看更加能够理解这其中的深意,尤其是将代码和图形搭配着来讲解,是十分清晰易懂的,当大家觉得理解起来有困难,一定要画个图更好理解!!!
客官,码字不易,来个三连支持一下吧!!!