E29.【C语言】练习:sizeof和strlen的习题集(A)

目录:

Exercise 1:szioef 一维数组

Exercise 2:sizeof 字符数组

Exercise 3:strlen 字符数组

Exercise 1:sizeof 一维数组

求下列代码打印结果

#define CRT_NO_WARNINGNESS 1
#include <stdio.h>
int main()
{
	int a[] = { 1,2,3,4 };
	printf("%zd\n", sizeof(a));
	printf("%zd\n", sizeof(a + 0));
	printf("%zd\n", sizeof(*a));
	printf("%zd\n", sizeof(a + 1));
	printf("%zd\n", sizeof(a[1]));
	printf("%zd\n", sizeof(&a));
	printf("%zd\n", sizeof(*&a));
	printf("%zd\n", sizeof(&a + 1));
	printf("%zd\n", sizeof(&a[0]));
	printf("%zd\n", sizeof(&a[0] + 1));
	return 0;
}

答案速查:

x86环境

x64环境

分析:

☑ printf("%zd\n", sizeof(a));

在这篇文章40.【C语言】指针(重难点)(E) 曾经讲过:

*注意:“数组名就是数组首元素的地址”有两个例外:

1.sizeof(数组名):这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节

详细见20.5.【C语言】求长度(sizeof和strlen)的两种方式

2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址(不等同于数组首元素的地址)

sizeof(数组名);结果为16

☑printf("%zd\n", sizeof(a + 0));

注意这里的sizeof(a+0);不等于sizeof(a);!!!

a+0代表数组的首元素地址+0,因此sizeof(地址);,结果为4/8

4/8含义:4或8个字节

x86环境:4个字节

x64环境:8个字节

☑ printf("%zd\n", sizeof(*a));

a是数组名,是数组首元素的地址,*a解引用为数组首元素,因此sizeof(元素);,又因为int类型,结果为4

☑ printf("%zd\n", sizeof(a + 1));

a+0代表数组的首元素地址+1,+1跳过4个字节,为第2个元素的地址,因此sizeof(地址);,结果为4/8

☑ printf("%zd\n", sizeof(a[1]));

a[1]是数组的首元素,因此sizeof(元素);,又因为int类型,结果为4

☑ printf("%zd\n", sizeof(&a));

&a为取a的地址(整个数组的地址),因此sizeof(地址);,结果为4/8

☑ printf("%zd\n", sizeof(*&a));

*与&抵消,即*&a等于a,等同于printf("%zd\n", sizeof(a));sizeof(数组名);结果为16

☑ printf("%zd\n", sizeof(&a + 1));

&a为取a的地址(整个数组的地址),地址+1还是地址,因此sizeof(地址);,结果为4/8

☑ printf("%zd\n", sizeof(&a[0]));

&a[0]是取数组首元素的地址,因此sizeof(地址);,结果为4/8

☑ printf("%zd\n", sizeof(&a[0] + 1));

地址+1还是地址,因此sizeof(地址);,结果为4/8

Exercise 2:sizeof 字符数组

求下列代码打印结果

#include <stdio.h>
int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%zd\n", sizeof(arr));
	printf("%zd\n", sizeof(arr + 0));
	printf("%zd\n", sizeof(*arr));
	printf("%zd\n", sizeof(arr[1]));
	printf("%zd\n", sizeof(&arr));
	printf("%zd\n", sizeof(&arr + 1));
	printf("%zd\n", sizeof(&arr[0] + 1));
	return 0;
}

答案速查:

x86环境

x64环境

分析:

 ☑ printf("%zd\n", sizeof(arr));

sizeof(数组名);结果为6(char类型一个字符占一个字节,6*1==6)

 ☑ printf("%zd\n", sizeof(arr + 0));

解释同Exercise 1 ,结果为4/8

 ☑ printf("%zd\n", sizeof(*arr));

解释同Exercise 1 ,对arr解引用,代表首个字符'a',结果为1

 ☑ printf("%zd\n", sizeof(arr[1]));

sizeof(元素);,又因为char类型,结果为1

 ☑ printf("%zd\n", sizeof(&arr));

解释同Exercise 1 ,结果为4/8

☑ printf("%zd\n", sizeof(&arr + 1));

解释同Exercise 1 ,结果为4/8

☑ printf("%zd\n", sizeof(&arr[0] + 1));

解释同Exercise 1 ,结果为4/8

******一定要区分sizeof(地址);sizeof(元素);******

Exercise 3:strlen 字符数组

把Exercise 2代码中的sizeof全改成strlen并加上头文件#include <string.h>,求打印结果

附:strlen的声明和定义

_Check_return_
size_t __cdecl strlen(
    _In_z_ char const* _Str
    );

答案速查:

随机值

随机值

报错

报错

随机值

随机值

☑ printf("%zd\n", strlen(arr));

20.5.【C语言】求长度(sizeof和strlen)的两种方式 结果为随机值

☑ printf("%zd\n", strlen(arr + 0));

arr是首元素的地址,+0还是首元素的地址,strlen从该地址向后统计直至遇到\0(此处和sizeof不一样),结果为随机值

细节部分:由strlen的声明和定义知,strlen接收的是const char* str,而arr代表char(*)[6],因此会发生强制类型转换

★★★ printf("%zd\n", strlen(*arr));

先看运行结果,发生报错

注意细节:0x0000061有点眼熟,查询字符a的ASCII码值,发现恰好61!

把首元素改成字符A,看看结果

0x0000041恰好是字符A的ASCII码值!

显然strlen(*arr)的逻辑是:把*arr转换成首元素,把首元素转换成ASCII码值并将后者当成地址去访问内存空间(从该地址处向后统计字符串直到遇见\0)(为什么当成地址见本文的strlen的声明和定义)

总结:strlen(字符)==strlen(字符所对应的ASCII码)==sizoef(地址)

Q:按理说应该能访问,为什么会报错?

A:当前程序并没有运行在0x0000041和0x0000061处,因此访问会报错

☑ printf("%zd\n", strlen(arr[1]));

arr[1]是数组第二个元素,解释同上一个

☑ printf("%zd\n", strlen(&arr));

&arr是数组的地址,也是数组开始位置的编号,strlen从该地址向后统计直至遇到\0(同arr和arr+0),结果为随机值

☑ printf("%zd\n", strlen(&arr + 1));

&arr + 1跳过整个数组,strlen向后统计直至遇到\0,结果为随机值

☑ printf("%zd\n", strlen(&arr[0] + 1));

&arr[0]+1是第二个元素的地址,strlen从该地址向后统计直至遇到\0,结果为随机值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值