前言
本文详细介绍指针和数组的笔试题,具体以一维数组和指针数组为例,其他数组用到的方法是不变的,重要的是读者学会方法,举一反三
提示:以下是本篇文章正文内容,下面案例可供参考
一、sizeof
1.1一维数组
学习该部分前,我们先来回顾几个知识点:
1.sizeof(数组名)-计算的是整个数组的大小
2.&数组名-数组名表示整个数组,取出的是整个数组的地址
3.除1和2两种情况,其他所有的数组名都是数组首元素的地址
代码如下(示例):
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));
//数组共4个元素,每个元素都是整形占4个字节,打印16
printf("%d\n", sizeof(a+0));
//sizeof(a+0),数组名并没有单独放sizeof内部,这里是a是作为数组首元素地址
//a+0还是首元素地址,大小为4或8个字节,4或8取决于当前环境是32位还是64位
printf("%d\n", sizeof(*a));
//*a,a是数组首元素地址,对其解引用也就是数组第一个元素1,占4个字节
printf("%d\n", sizeof(a+1));
//a是数组首元素地址,地址加1,也就是数组第二个元素地址,占4或8个字节
printf("%d\n", sizeof(a[1]));
//a[1]即数组第2个元素2,占4个字节
printf("%d\n", sizeof(&a));
//&a是,a表示的是整个数组
//这里要注意的是,即使是整个数组的地址,它本质任然是个地址,占4个字节
printf("%d\n", sizeof(*&a));
//&a是数组的地址,*&a也就是对数组的地址进行解引用,得到的是整个数组大小,为16
//类别sizeof(a),打印也是16,*&a也就是拿出地址,再找到地址里的东西,地址里的东西就是a
printf("%d\n", sizeof(&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));
//同上,是取出首元素地址再加1,到第二个元素地址,地址大小4或8
return 0;
}
ps:为什么地址都是占4或8个字节?
解释:地址只是计算机中内存的一个编号,不管你是什么整形、浮点型、等等类型,甚至是数组的地址,它都只是一个编号,统一是占4或8个字节(4或8取决于当前环境是32位还是64位)。
代码如下(示例):
1.2字符数组
#include<stdio.h>
int main()
{
char arr[6] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
//数组共6个元素,每个元素都是字符型占1个字节,打印6
printf("%d\n", sizeof(arr + 0));
//sizeof(arr+0),数组名并没有单独放sizeof内部,这里是arr是作为数组首元素地址
//arr+0还是首元素地址,大小为4或8个字节,4或8取决于当前环境是32位还是64位
printf("%d\n", sizeof(*arr));
//arr是首元素地址,对其解引用,得到字符a,a占1个字节
printf("%d\n", sizeof(arr[1]));
//数组首元素a,占1个字节
printf("%d\n", sizeof(&arr));
//对数组取地址,本质任然是地址,占4或8个字节
printf("%d\n", sizeof(&arr+1));
//对数组取地址,数组的地址+1是跳过一个数组得到一个地址,地址占4或8个字节
printf("%d\n", sizeof(&arr[0]+1));
//对数组第一个元素a取地址,地址再加1到元素b的地址,地址占4或8字节
return 0;
}
1.2.1字符串去初始化数组
对比2,我们很容易发现,字符数组的两种初始化方法一种是{a,b,c,d,e,f},一种是"abcdef"
那么差异在哪里呢?用"abcdef"去初始化的时候,abcdef的末尾会自动加一个\0
也就是说,数组arr中除了abcdef这6个字符,还有\0这一个字符,共7个字符
代码如下(示例):
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
//sizeof求整个数组大小,arr共7个字节即abcdef和\0
printf("%d\n", sizeof(arr + 0));
//arr没有单独放sizeof内部,所以这里的arr是作为数组首元素地址出现,+0仍然是首元素地址,地址大小4或8
printf("%d\n", sizeof(*arr));
//arr是首元素地址,*arr对首元素地址解引用得到a,占1个字节
printf("%d\n", sizeof(arr[1]));
//arr[1]是数组第二个元素b,占1个字节
printf("%d\n", sizeof(&arr));
//&arr,得到数组arr地址,本质仍然是地址,占4或8字节
printf("%d\n", sizeof(&arr+1));
//&arr+1跳过一个数组长度得到一个地址,本质仍然是地址,占4或8字节
printf("%d\n", sizeof(&arr[0]+1));
//对数组第一个元素a取地址,地址再加1到元素b的地址,地址占4或8字节
return 0;
}
二、strlen
关于strlen这个库函数,我们要知道,它是用来求字符串长度的。给它一个起始地址,它会自己往后找,那找到哪里停呢?到\0出现的时候,strlen结束寻找
2.1一般数组初始化
代码如下(示例):
#include<stdio.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(arr));
//这里会打印一个随机值
//因为我们数组arr开辟了一块空间里面放abcdef,但是内存中arr后面的空间有什么,我们是不知道的,所以对于\0什么时候出现,我们也是不知道的
printf("%d\n", strlen(arr + 0));
//arr+0,数组首元素地址+0,任然是数组首元素地址,strlen从arr开始往后数,到出现\0结束,但我们仍不知道\0何时出现,所以这里也是随机值
printf("%d\n", strlen(*arr));
//arr是数组首元素a的地址,*arr即对a地址解引用得到a
//那我们知道strlen是给一个地址往后找,直到\0出现
//给一个字符‘a’是什么意思?——字符a在ascll码表中对应号码97,计算机会自认为是地址97,然后从97这个地址往后找\0,所以这里也是随机值
printf("%d\n", strlen(arr[1]));
//这里同理,arr[1]是b,其ascll码为98,计算机会自认为是地址98,然后从98这个地址往后找\0,所以这里也是随机值
printf("%d\n", strlen(&arr));
//这里&arr,得到数组arr的地址,然后strlen往后找\0,是随机值
printf("%d\n", strlen(&arr+1));
//数组的地址加1,是跳过一个数组的地址,然后strlen往后找\0,是随机值,该随机值和上一个随机值会差6(1个数组长度)
printf("%d\n", strlen(&arr[0]+1));
//a的地址加1,跳过一个字符到b的地址,往后找\0,也是一个随机值
return 0;
}
ps1:关于strlen(&arr),我们在查找strlen这个具体库函数时会发现,函数定义是
strlen(char * ),也就是说,它接收的是char*型的指针,而&arr传过来的是char( * )[]
类型的指针。编译器虽然会报警告,但是这个指针仍然是可以传的,在传过去之后,会进行强制类型转换,而这个地址是数组arr的地址,我们知道,数组arr的地址和数组首元素a的地址本质是不一样的,但是地址是相同的,编译器会认为这个地址是字符a的地址,然后向后找,直到找到\0
ps2:在我们越界访问内存时,编译器可能会报错,上述例子是为了让读者清楚的学习,具体编程操作时要意识到问题出在哪里。
2.2字符串去初始化数组
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr));
//因为数组arr初始化方法为"abcdef",所以f后会自动跟一个\0,而strlen即是找到\0结束,所以这里是6
printf("%d\n", strlen(arr + 0));
//arr+0,是a的地址,从a的地址开始找,到\0结束,这里是6
printf("%d\n", strlen(*arr));
//*arr拿到字符a,ascll码97
//注意!!!:这里找到的是一个野指针,是会报错的
printf("%d\n", strlen(arr[1]));
//arr[1]是b,ascll码98,同上,也是一个野指针
printf("%d\n", strlen(&arr));
//&arr取出的是数组的地址,类型char(*)[]但传过去会被强制类型转换,被默认为是字符a的地址,从a到\0共6字符
printf("%d\n", strlen(&arr+1));
//&arr+1取出数组地址后再往后跳一个数组长度得到地址,该地址后什么时候出现\0是未知的,所以是随机值
printf("%d\n", strlen(&arr[0]+1));
//&arr[0]+1是先取出数组首元素地址,往后跳一个元素地址,也就是b的地址,从b往后找到\0,是5
return 0;
}
ps:注意这里strlen(*arr)和sizeof(*arr)的区别:
strlen(*arr):
*arr拿到字符a,ascll码97,然后从97这个地址往后找,我们之前并没有使用过97这个地址,所以不知道97这个地址里放了什么,它之后有什么,这就是一个典型的野指针,编译器会报错。
sizeof(*arr):
*arr拿到字符a,sizeof计算的是这个字符a的大小,是1字节