目录:
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,结果为随机值