在上节内容中,我们使用符号常量解决了数组元素个数可维护性的额外负担。然而数组有一种不指定元素个数的形态,通常是用于有固定元素个数的数据,这种情况下很少为其单独定义符号常量。如果要用循环遍历数组或非要为其定义符号常量,那可以通过数数的方式来进行。
假定你采取了数数的方式,一旦增加或减少数组元素个数,与该数组有关的流程就存在发生BUG的可能性。很明显这可以采用更合理的方式解决,这便是sizeof。
sizeof运算符在C语言中,一个char类型的变量占用一个字节的存储空间,那int类型与float类型呢?这可以通过使用sizeof运算符来测量。
使用sizeof运算符时,需要提供变量或类型参数(如果是表达式,则按表达式结果的类型计算),返回该变量或类型以byte为单位所占用的空间大小。
- 如果是实参是类型,那么sizeof得到的结果是此类型的大小;
- 如是实参是变量,那么sizeof得到的结果是此变量的类型的大小,这个值永远会比0大。
这里有两点需要注意:
- sizeof是运算符而不是函数。
- 不管传递给sizeof是的变量还是类型,最终计算的是类型占据的大小。
因此测试一个int类型变量的大小与测试int类型自身得到的结果是一致的,这里的程序显示了在32位环境下,我们学习的已知变量类型的大小。
测试数组
关于sizeof需要牢记的便是:不管传递给sizeof是的变量还是类型,最终计算的是类型占据的大小。因此我们将一个数组对象传递给sizeof运算符,它便会计算出整个数组元素所占用的字节数。
根据第一个程序的结果我们知道sizeof(int)=4,那么这里sizeof(a)=4(字节)*9(元素)=36个字节。同样sizeof(c)=8。知道了数组对象的总大小,除以元素的类型,便是数组元素的个数,下面是程序运行结果。
需要注意在计算数组a的元素个数时,我们采用的表达式为:sizeof(a)/sizeof(int);而数组c则采用的是传递变量的形式sizeof(c)/sizeof(c[0])。使用第二种方式的优势在于,当你改变数组类型时,则不必改变求值表达式。假设采用方式一,你现在将数组a由int型改为float型,那表达式需要相应的更改为:sizeof(a)/sizeof(float)。
抢答送分题
思考一下:在表达式sizeof(c)/sizeof(c[0])中,为什么使用数组的第一个元素,而不是其它元素,使用其它元素行吗?
只要你使用的元素没有越界,那么使用数组哪个元素都是可行的。之所以使用0号元素,因为数组也存在只有一个元素的情况,如果你使用sizeof(c[1]),就会在不经意间造成越界访问。之所以能够使用任何一个未越界的元素,另一个深层的原因是:数组是存放同一类型数据的集合,这在数组的特性中提到过,并且sizeof最终计算的是类型占据的大小,sizeof(c[0])与sizeof(c[5])都是测试sizeof(char)类型占用的空间。
确认数组类型再次重申一下,不管传递给sizeof是的变量还是类型,最终计算的是类型占据的大小。
以测试数组中的例子而言,sizeof遇到a之后,它知道a是一个含有9个int型数据的数组,c则是一个含有8个字符的char型数组。sizeof(a)事实上相当于测试sizeof(int[9]),sizeof(c)就是sizeof(char[8]),所以a的类型是int[9], c的类型是char[9]。你可以把下列代码加入到程序中,会发现这两种类型占用的存储空间与我们程序表述的一致。
当然,如果使用C ,我们可以很轻松的看到数据的真实类型。下列程序使用typeid取得变量的类型对象,并打印出类型名称。
,