sizeof和strlen的具体使用+指针和数组笔试题详解-篇1


前言

本文详细介绍指针和数组的笔试题,具体以一维数组和指针数组为例,其他数组用到的方法是不变的,重要的是读者学会方法,举一反三


提示:以下是本篇文章正文内容,下面案例可供参考

一、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字节


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

劲夫学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值