5.3.1 sizeof运算符和size_t类型
sizeof运算符以字节为单位返回其操作数的大小(在C中,1个字节被定义为char类型所占用空间的大小。在过去,1个字节通常是8位,但是一些字符集可能使用更大的字节)。
操作数可以是一个具体的数据对象,或者一个类型。如果它是一个类型,操作数必须被括在圆括号里。
程序清单5.8 sizeof.c程序
//sizeof.c使用sizeof运算符
//使用c99的%z修饰符,如果不能使用%zd,请使用%u或%lu
#include
int main()
{
int n=0;
size_t intsize;
intsize=sizeof(int);
printf("n=%d,n has %zd bytes;all ints have %zd bytes.\n",n,sizeof n,intsize);
return 0;
}
C规定sizeof返回size_t类型的值。
这是一个无符号整数类型,它不是一个新的类型。相反,与可移植类型(int32_t等)相同,它是根据标准类型定义的。
c99更进一步,把%zd作为用来显示size_t类型值的printf()说明符,如果你的系统没有实现%zd,您可以试着使用%u或%lu代替它。
5.3.2 取模运算符
用于整数运算,该运算符计算出用它右边的整数去除它左边的整数得到的余数。
不要对浮点数使用该运算符,那将是无效的。
一个常见的用途是帮助您控制程序的流程。
程序清单5.9 min_sec.c程序
/*min_sec.c--把秒转换为分钟和秒*/
#include <stdio.h>
#define SEC_PER_MIN 60
int main()
{
int sec,min,left;
printf("Convert seconds to minutes and seconds!\n");
printf("Enter the number of seconds (<=0 to quit ):\n");
scanf("%d",&sec);
while (sec>0)
{
min=sec/SEC_PER_MIN; //截尾后得到的分钟数
left=sec%SEC_PER_MIN; //剩下的秒数
printf("%d seconds is %d minutes,%d seconds.\n",sec,min,left);
printf("Enter next value (<=0 to quit):\n");
scanf("%d",&sec);
}
printf("Done!\n");
return 0;
}
负数的取模运算应该遵照什么样的规则?在C99为整数除法规定“趋零截尾”规则之后,如果第一个操作数为负数,那么得到的模也是负数;如果第一个操作数是正数,那么得到的模也是正数。
如果a和b都是整数值,不管在什么情况下,您都可以能过从a中减去(a/b)*b来计算a%b。
-11%5= -11-(-11/5)*5=-11-(-2)*5=-11-(-10)=-1
5.3.3 增量和减量运算符:++和--
“增量运算符”完成简单的任务,即将其操作数的值加1.
这个运算符以两种方式出现。
第一种方式,++出现在它作用的变量的前面,这是前缀模式。
第二种方式,++出现在它作用的变量的后面,这是后缀模式。
这两种模式的区别在于值的增加这一动作发生的准确时间是不同的。
程序清单 5.10 add_one.c
/*add_one.c--增量:前缀和后缀*/
#include <stdio.h>
int main()
{
int ultra=0,super=0;
while (super<5)
{
super++;
++ultra;
printf("super=%d,ultra=%d\n",super,ultra);
}
return 0;
}
shoe=2.0;
wihle (++shoe<18.5)
{
foot=SCALE*size+ADJUST;
printf("%10.1f %20.2f inches\n",shoe,foot);
}
这里已经将增量的过程和while循环的比较合并成一个表达式。
这种方法有什么好处?它更简洁,更重要的是它在一个地方集中了处理循环的两个过程:
主要处理过程是判断是否继续循环,在本例中是查看鞋子的鞋码是否小于18.5;附带的处理过程是改变判断的元素,在本例中是增加鞋子的鞋码。
在同一个位置执行循环的判断和循环的改变可以防止您忘记更新循环。
增量运算符的另一个优点是它通常产生更高效的机器语言代码,因为它与实际的机器语言指令相似。
程序清单5.11 post_pre.c
/*post_pre.c 后缀和前缀*/
#include <stdio.h>
int main ()
{
int a=1,b=1;
int aplus,plusb;
aplus=a++; //后缀
plusb=++b; //前缀
printf("a aplus b plusb \n");
printf("%1d %5d %5d %5d\n",a,aplus,b,plusb);
return 0;
}
输出示例
a aplus b plusb
2 1 2 2
像我们所能预料到的,a和b都增加了1.然而,aplus具有a改变之前的值,而plusb具有b改变之后的值。
aplus = a++; //后缀:使用a的值之后改变a
plusb = ++b; //前缀:使用b的值之前改变b.
当单独使用这些增量运算符之一时,您使用哪种形式无关紧要。然而,当运算符及其操作数是一个更大的表达式的一部分时,比方说在鞋码转换的示例中,选择就很重要了。
++shoe<18.5,如果您使用shoe++而不是++shoe,shoe的值将达到19,因为shoe将在比较之后而不是之前增加。
5.3.4 减量运算符:--
每种形式的增量运算符都有一种减量运算符与之对应,只须使用--来代替++。
5.3.5 优先级
增量和减量运算符有很高的优先级;只有圆括号比它们的优先级高。
不要将这两个运算符的优先级与求值顺序相混淆。
y=2;
n=3;
nextnum=(y + n++)*6;
用值来代替可以得到
nextnum=(2 + 3)*6=5*6=30
只有当使用了n之后,n的值才增加到4.
当n++是表达式的一部分时,您可以认为它表示“先使用n;然后将它的值增加”,另一方面,++的意思是“先将n的值增加,然后再使用它”。
5.3.6 不要太聪明
如果您企图一次使用太多的增量运算符,可能连自己也会被弄糊涂。
通过以下这些原则,您可以避免这些问题:
**如果一个变量出现在同一个函数的多个参数中,不要将增量或减量运算符用于它上面;
**当一个变量多次出现在一个表达式里时,不要将增量或减量运算符用到它上面;