有关数组和指针的sizeof、strlen计算问题,我们有时会做错,今天通过仔细地分析,通过验证,加深理解。
以上结果均已经过验证,读者也可以自行验证。
在这里,主要涉及以下知识:
1.数组名的含义:
在C语言中,只有在两种情况下数组名代表整个数组:(1)sizeof(数组名),数组名前后什么都没有(2)&数组名
在其它情况下,均代表数组首元素的地址。
2.数组的降维问题
数组在传参时,都降级为指向其内部元素的指针。对于一维数组来说,降级为其内部一个元素的地址。对于二维数组来说,可以看成是由一维数组组成的一维数组。它的内部元素是一维数组,传参时就降级为指向一维数组的指针。
在最后一张图中,a[0]就代表第一行,sizeof(a[0])就指整个第一行,a[0]可以看成是一维数组名(这个一维数组实际上是二维数组的元素)。sizeof(a[0]+1)中,根据1,a[0]代表&a[0][0],所以a[0]+1就是&a[0][1].
3.strlen函数的参数
原型:size_t strlen( const char *string );
所以strlen的参数为char *型,所以每当我们遇到与strlen有关的问题时,先看传参时参数的类型是否符合,不符合就会报错。其次,就要判断结果是准确值还是随机值,这取决于我们传参的内容中是否本身含有'\0',如果没有,则为随机值,否则就是准确值。
4.读者可能会对最后一个小题感到疑惑,定义的二维数组只有三行四列,下标应从a[0][0]到a[2][3],是否访问越界了呢?其实没有,在printf("%d\n",sizeof(a[3]))中,a[3]代表第四行的元素。在标准规定中,允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但不允许与指向第一个元素前面的那个内存位置的指针比较。而在访问数组元素时,我们通常用指针访问,所以我们可以访问a[3].
5.指针的“+”问题
对指针的加减,实际上是加上其所指向数据类型的大小。对地址的加也是如此。如&arr+1,arr在这里指的是整个数组,所以加的是整个数组的大小,而&arr[0]+1,就是对首元素的地址加上首元素所占字节数,即变为&arr[1]。