【C语言进阶】sizeof、strlen详解

1. 学习关键字sizeof:

提示:sizeof(数组名)——其中数组名表示整个数组,而sizeof(数组名)计算的是整个数组的大小。

&数组名——数组名表示整个数组,&数组名取出的是整个数组的地址。

 除此之外,数组名都是数组首元素的地址(二维数组中数组名是数组第一行的地址)。

我们平时计算字节时总是会出现各种形形色色的小错误,归根结底,还是理解的不够深刻,今天小编就带大家深入了解一下sizeof这个关键字! 

注意一点:sizeof (地址)在不同的平台计算的字节是不同的,在x86平台当中计算结果是4个字节,在x64平台当中计算结果是8个字节。

 众所周知,我们都知道sizeof(数组名)计算的是整个数组的大小,例如: 

1bd1d52a299c465ea7ba18c16bcf953b.png

 但 sizeof 的用法不止于此,小编觉得空讲不如例题带给我们的理解深刻,所以我们接下来就深入学习一下吧!直接上代码:>

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int main()
{
	int arr[] = {1,2,3,4};//定义一个整型数组

	printf("result = %d\n", sizeof(arr + 0));//在这里arr + 0并不满足sizeof(数组名),所以arr在这里只代表首元素的地址,故arr+0同样也是元素1的地址。result = 4或者8

	printf("result = %d\n", sizeof(*arr));//*arr中,同上arr即为首元素地址,*arr解引用等于1,result = 4

	printf("result = %d\n", sizeof(&arr));//&arr取出的是整个数组的地址,但终究是地址,result = 4或者8

	printf("result = %d\n", sizeof(*&arr));//&arr取出整个数组的地址,然后解引用,计算的整个数组的大小,即result=16

	printf("result = %d\n", sizeof(&arr + 1));//&arr+1最终依旧是地址,所以result=4或者8

	return 0;
}

这里要详细解释一下&arr + 1 ,&arr取出的是数组的地址,当它再加上1时,是跳过一个数组大小,而不是一个元素的大小!

1f5b1496980f46ad966fd0742c512f4c.png

小编我用的是x86平台,所以计算sizeof(地址)的结果为4 ,公布上述答案:>

9ae938d3cc814710b32335884405aef9.png

那我们再看一个字符串的例题吧!>

int main()
{
	//定义字符串数组
	char arr[] = "abcdef";//字符数组当中包含(a,b,c,d,e,f,\0)

	printf("result = %d\n", sizeof(arr));//字符串数组当中默认包含'\0',sizeof(arr)计算的范围包含'\0' result = 7

	printf("result = %d\n", sizeof(arr+0));//这里arr是数组首元素地址,arr+0依旧是地址,result = 4或者8

	printf("result = %d\n", sizeof(*arr));//arr是首元素地址,*arr解引用后结果为a,即result = 1

	return 0;
}

公布上述答案:> 38c2c6f9e93d4f31bc8f380ff7ddd405.png

下面就是小编监视窗口当中字符串数组arr的元素 ,其中就包含了 ‘ \0 ’

 fc939b6b73c84f1ea24e0887eb431b62.png

 大家是不是觉得上面的太简单呀,那小编接下来难度要增加哦,小伙伴们准备好,上代码:>

int main()
{
	char* poi = "abcdef";

	printf("result = %d\n", sizeof(poi));//poi是一个指针,poi内存放的是字符串首元素a的地址,而这里测的是指针的大小,所以result=4或者8

	printf("result = %d\n", sizeof(poi + 1));//poi+1存放着字符串中b地址,但依旧还是一个指针,即result=4或8

	printf("result = %d\n", sizeof(poi[0]));//因为数组名其实就是指向数组第一个元素的指针,所以这里的指针poi就可以当数组名使用使用,即poi[0]==*(poi+0),即result=1

	printf("result = %d\n", sizeof(&poi));//&poi取出的指针poi的地址,result=4或8

	printf("result = %d\n", sizeof(&poi+1));//&poi+1依旧是地址 result=4或8
	return 0;
}

其中&poi是取得指针的地址,切不可理解为取得数组的地址!而&poi+1是取指针地址的基础上向右移动1字节,与数组arr无关.      如图:

4d7c65fb00194a10955f2c5018ad8ffa.png

 公布上述答案:0cba3efb2570432fa9aa565ebc2d5dc1.png

 接下来小编给大家详细介绍一下二维数组当中的sizeof难点吧!上代码之前先注意两点

 1.

2f0bd7713b6e486793a14c6c668d3605.png

 在一维数组中arr[2]就是数组名[i],其中i的变化范围是0~1,类比一下;在二维数组当中,arr[0][j]其中j的变化范围是0~2,那么arr[0]在二维数组中对应的哪一行当中就相当于是数组名了,同理arr[1]也是二维数组当中对应哪一行的数组名!

2.

sizeof不计算其括号内部的表达式!例如:

int main()
{
	short a = 4;
	int b = 6;
	printf("%d ", sizeof(a = b + 4));
	printf("%d ", a);
	return 0;
}

 如果sizeof括号内部计算,结果应该a=10,程序运行后:

 0160381493094e438f503224beaa2267.png

 结果a依旧等于4,所以sizeof不计算括号内部的表达式!!!

 当大家已经理解上面的,那接下来就上代码:>

int main()
{
	int arr[2][3] = { 0 };//定义一个整型数组

	printf("result = %d\n", sizeof(arr));//很简单,这里小编就不多解释这个,result=sizeof(int)*2*3=24

	printf("%d\n", sizeof(arr[0][0]));//第一行第一个元素

	printf("%d\n", sizeof(arr[0]));//当arr[0]单独放在sizeof当中时,arr[0]表示整个第一行的数组名 

	printf("%d\n", sizeof(arr[0] + 1));//arr[0]+1放在sizeof中时,arr[0]并没有单独放在sizeof中,所以arr[0]表示第一行首元素的地址,即arr[0]+1依旧还是地址

	printf("%d\n", sizeof(*(arr[0] + 1)));//*(arr[0]+1)代表着第一行第二个元素

	printf("%d\n", sizeof(arr + 1));//这里的arr没有单独放在sizeof当中,所以这里的arr表示二维数组当中第一行的地址,即arr+1表示第二行的地址

	printf("%d\n", sizeof(*(arr + 1)));//*(arr+1)其实等价与arr[1],那么相当于是第二行的数组名

	printf("%d\n", sizeof(&arr[0] + 1));//&arr[0]取出的是第一行的地址,&arr[0]+1,是取出第二行的地址,但终究是地址

	printf("%d\n", sizeof(*(&arr[0] + 1)));//&arr[0]+1表示第二行的地址,解引用后就相当于第二行的数组名

	printf("%d\n", sizeof(*arr));//*(arr+0)= arr[0],arr表示第一行的地址,解引用后表示第一行的数组名

	printf("%d\n", sizeof(arr[2]));//这里第三行不存在,但sizeof不计算括号内部的表达式,不会越界访问,但可以通过类型计算字节

	return 0;
}

 公布上述答案:>470e09cd042e48a49ca17403fb0970d5.png


2.学习库函数strlen:

提示:strlen是计算字符串(以'\0'结尾的字符数组)的函数

strlen括号内应该放地址!

 我们平时计算不同类型的字符串长度时会出现与自己想法不同的各种错误运算结果,这是为什么呢?

今天小编就运用上述sizeof中的代码带大家去深入了解strlen这个函数!

注意一点:字符数组要与字符串数组区分开,字符数组后面不带'\0',而字符串数组后面自带'\0'!

下面即为小编监视窗口,与字符串数组相比较后面没有自带‘\0’!

d97fa92aaad546258047d2c4660146f7.png

还是老规矩直接上代码:>

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };//定义一个字符数组(字符数组后不自带'\0')

	printf("%d ", strlen(arr));//这里arr为数组首元素地址(与sizeof区分)字符数组后面不自带\0,所以运算结果为一个随机数

	printf("%d ", strlen(arr + 0));//同样arr+0为数组首元素地址,计算结果为一个随机数

	printf("%d ", strlen(&arr));// &arr取出了整个数组的地址,但是strlen这个函数依旧会将其解读为该数组首元素的地址,结果为随机数

	printf("%d ", strlen(&arr + 1));//&arr取出了数组的地址,&arr+1即向后走该数组大小的距离,结果为随机数

	printf("%d ", strlen(&arr[0] + 1));//&arr[0]取出了数组首元素的地址,&arr+1即取出了元素b的地址,即结果依旧是随机数

	return 0;
}

公布上述答案:872982cd4cb94a72b465c8ed49999efc.png

由运行结果可知,全部为随机数!

运行结果为随机数的过程:

8fb7208b6fbc4769a17fc356b5cf73c7.png

 上图为包含数组的内存的其中一部分!

 函数strlen在读取数组长度时,获取数组首元素地址,依次往后计算,但字符数组没有自带‘\0’,所以会超出数组范围去读取内存,直到在内存上遇到一个‘\0’时停止计算。

int main()
{
	printf("%d ", strlen(*arr));//arr为数组首元素地址,解引用后为元素a,strlen内部要放地址,出错!

	printf("%d ", strlen(arr[1]));//同样,strlen内部放了元素b,出错!

	return 0;
}

上述代码无法运行,因为函数strlen括号内部应该放地址! 

接下来我们就看少量的自带‘\0’的字符串数组的代码,加深大家的理解。上代码>

int main()
{
	char arr[] = "abcdef";//定义字符串数组(后面自带\0)

	printf("%d ", strlen(arr));

	printf("%d ", strlen(&arr));

	printf("%d ", &arr[0] + 1);//取出元素b的地址

	return 0;
}

 公布上述答案:3c7000a2e1b04fbc9f602b709872e38f.png

 在学会上述代码后,那我们就开始学习关于指针的strlen函数吧!

int main()
{
	char* poi = "abcdef";

	printf("%d ", strlen(poi));//这里指针poi指向字符串首地址

	printf("%d ", strlen(poi + 1));//首地址+1,即为元素b的地址

	printf("%d ", strlen(*poi));//strlen内部应放地址,*poi不是地址,出错!

	printf("%d ", strlen(&poi));//这里去出的是指针poi的地址,所以计算的长度为包含指针poi内存上的长度,是一个随机数

	printf("%d ", strlen(&poi[0] + 1));//取出的是元素b的地址

	return 0;
}

***这里重点解释一下:printf("%d",strlen(&poi)); 

5e0db37dd5e74bfcb50286669d0261b0.png

 strlen函数当中放着的是指针poi的地址,所以计算长度不是从字符串首元素开始了,是从指针poi所在的内存位置开始,直到后面出现\0后结束。假如char型指针poi的地址为0x11223344,strlen函数从指针poi向后计算长度,每次访问一个字节,直到某时刻访问到地址当中出现00的时候,这时会默认为\0;终止计算长度!所以strlen计算出的结果为随机数。

公布上述答案:b66f29ba8c8f4f2196c5bb40a438528a.png 


 本人大一新生,第一次写博客,写的不好和错的地方,大家可以指正出来,我们共同进步 。希望大家谅解!

如果大家觉得我写的还行,帮小编点一个免费的赞和关注,我会持续更新出更好的博客,谢谢大家!

猜你喜欢

转载自blog.csdn.net/m0_73968621/article/details/128967996