上一节,我们了解了sizeof计算符和strlen函数的定义,接下来我们加强对它们的理解
首先,写一串代码,分析程序执行的结果,并分析原因
int main()
{
char arr[] = "abcdef";
printf("%d\n", sizeof(arr)); 1
printf("%d\n", sizeof(arr+0)); 2
printf("%d\n", sizeof(*arr)); 3
printf("%d\n", sizeof(arr[1])); 4
printf("%d\n", sizeof(&arr)); 5
printf("%d\n", sizeof(&arr+1)); 6
printf("%d\n", sizeof(&arr[0]+1)); 7
return 0;
}
一:7 首先,sizeof(arr)中的arr表示整个数组,数组内部的元素是字符串,所以内部的元素实际上是"abcdef/0"; 6个字母加上一个/0 ,一共七个元素,因为元素类型是char类型,所以一个元素所占的字节数为1,7个元素所占的字节数就为7.
二:4(32位平台) sizeof(arr+0)不表示整个数组,只有严格格式的sizeof(arr)中的arr才表示整个数组,所以这里的arr表示数组首元素的地址,既然是指针,一个指针所占的字节数为4(32位平台)
三:1 arr表示数组首元素的地址,*arr表示数组首元素,数组首元素为a,类型是char型,所以a所占的字节数为1
四:1 arr[1]表示数组第二个元素,第二个元素为b,类型为char型,所以所占的字节数也为1
五:4 &+数组名表示数组的地址,这里将数组的地址传递过去,既然是指针,所占的字节数就为4
六:4 &arr表示数组的地址,数组的地址+1表示跳过整个数组 但还是地址,所以占的字节数为4
七:4 &arr[0]表示数组首元素的地址,首元素地址+1表示数字第二个元素的地址,是地址,所以占的字节数就为4
所以打印的结果应该是 7 4 1 1 4 4 4
结果正确
同样的数组,我们使用strlen函数验证一下
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr)); 1
printf("%d\n", strlen(arr+0)); 2
printf("%d\n", strlen(*arr)); 3
printf("%d\n", strlen(arr[1])); 4
printf("%d\n", strlen(&arr)); 5
printf("%d\n", strlen(&arr+1)); 6
printf("%d\n", strlen(&arr[0]+1)); 7
return 0;
}
代码如图所示
我们继续分析
一:6 strlen在计算时,是不计入/0的,/0只是strlen函数结束的标志,我们把数组首元素的地址传递过去,strlen函数运行,直到发现/0 一共六个元素,abcdef,每个元素所占的字节数都为1,所以结果为6
二:6 分析的过程和结果都和1相同
三:报错 arr表示数组首元素的地址,*表示对它进行解引用,*arr是数组首元素,数组首元素为a,strlen函数一般识别的是地址,a对应的ascii码是97,97对应的地址不在我们使用的范围内,形成越界访问,所以报错,结果如图所示
四:报错 arr[2]表示数组第二个元素,数组第二个元素为b,b对应的ascii码值为98 ,98对应的地址不在我们的使用范围内,所以会形成越界访问,和三的结果相同
五:6 但会发生警告 ,因为&arr表示数组的地址,用代码表示就是char(*)[7],strlen函数的参数是(const char*),两个的类型不相同,不兼容,但依然能够强行赋值
六:随机值 &arr表示数组的地址,+1表示跳过数组的地址,也就是跳过了/0,下一个/0的位置是未知的,所以是随机值,也会产生和五相同的警告,警告的原因也是相同的,因为strlen函数的参数与我们的数组指针不兼容
七:5 &arr[0]表示数组首元素的地址,+1表示数组第二个元素的地址,也就是从b开始,到/0结束,一共是五个char类型的元素,所以是五个字节
int main()
{
char*p = "abcdef";
printf("%d\n", sizeof(p)); 1
printf("%d\n", sizeof(p+1)); 2
printf("%d\n", sizeof(*p)); 3
printf("%d\n", sizeof(p[0])); 4
printf("%d\n", sizeof(&p)); 5
printf("%d\n", sizeof(&p+1)); 6
printf("%d\n", sizeof(&p[0]+1)); 7
return 0;
}
首先,要对char*p = "abcdef";进行解释
答: "abcdef"(char型)一共占用六个字节,但是正常的指针只占用4个字节,所以不能按照正常的解释:这里的"abcdef";是常量字符串:可以被访问,不允许通过解引用操作更改 这里的p是对应的是首元素的地址,即a的地址。
一:4 p这里表示首元素的地址,即a的地址,一个指针占四个字节,
二:4 p+1的得到的是数组第二个元素的地址,一个指针占四个字节
三:1 这里我们可以这样解释 :数组的第二个元素正常情况下应该怎样表示,有两种表示方法,1:arr[1] 2:*(arr+1) 类比可得*p=*(p+0)=arr[1] 所以这里表示数组首元素,数组首元素为a,所占的字节数为1
四:1 这里也可以类比 arr[0]表示数组首元素 所以p[0]也表示数组首元素,所占的字节数为1
五:4 &p可以类比&arr,所以这里表示数组的地址,无论是什么地址,所占的字节数都是固定的
六:4 &p表示数组的地址,&p+1表示跳过p数组的地址,因为是地址,所占的字节数不变。
七:4 &p[0]等价于&arr[0]表示数组首元素的地址,首元素的地址+1表示数组第二个元素的地址,因为是地址,所以所占的字节数为4
总结:遇到这种常量字符串对应的指针(p),可以用他们类比于arr计算
int main()
{
char*p = "abcdef";
printf("%d\n", strlen(p)); 1
printf("%d\n", strlen(p+1)); 2
printf("%d\n", strlen(*p)); 3
printf("%d\n", strlen(p[0])); 4
printf("%d\n", strlen(&p)); 5
printf("%d\n", strlen(&p+1)); 6
printf("%d\n", strlen(&p[0]+1)); 7
return 0;
}
对结果进行分析
这里的p是数组首元素的地址
一:6 p在这里的意思是首元素的地址 从a到/0一共6个元素,占6个字节
二:5 p+1表示第二个元素的地址
三:err 在这里表示首元素 因为strlen只能接收地址,所以发生错误
四:err 在这里也表示数组首元素
五:随机值 p是首元素的地址,&p表示到地址内部,例如p的地址是0x000016 ,,如果是小端存储,就是16 00 00 0x 第二个就是/0 /0所以根据地址的不同而发生变化 所以是随机值
六:随机值
七:4 &p[0]表示数组首元素的地址 +1表示数组第二个元素的地址