C语言学习第二十天。
2.12 运算符优先级与求值次序
如下表,同一行中的各运算符具有相同的优先级,各行间从上往下优先级逐行降低。
运 算符 结合性
() [] -> . 从左至右
! ~ ++ -- + - * & (type) sizeof 从右至左
* / % 从左至右
+ - 从左至右
<< >> 从左至右
< <= > >= 从左至右
== != 从左至右
& 从左至右
^ 从左至右
| 从左至右
&& 从左至右
|| 从左至右
?: 从右至左
= += -= *= /= %= &= 从右至左
^= |= <<= >>=
, 从左至右
位运算符&、^、与|的优先级比运算符==与!=的低。这意味者,位测试表达式,如
if ((x & MASK) == 0) ...
必须用圆括号括起来才能得到正确的结果。
同大多数语言一样,C语言没有指定同一运算符中多个操作数的计算顺序,例如,在形如
x = f() + g();
的语句,f()可以在g()之前计算,也可以在g()之后计算。因此,如果函数f或g改变了另一个函数所使用的变量,那么x的结果可能会依赖于这两个函数的计算顺序。为了保证特定的计算顺序,可以把中间结果保存在临时变量中。
类似的,C语言也没有指定函数各参数的求值顺序。因此,下列语句
printf("%d %d\n", ++n, power(2, n)); /* 错 */
在不同的编译器中可能产生不同的结果,这取决于n的自增运算在power调用之前还是之后执行。解决的办法是把该语句改写成下列形式:
++n;
prinf("%d %d", n, power(2, n));
在任何一种编程语言中,如果代码的执行结果与求值顺序相关,则都是不好的程序设计风格。很自然,由必要了解那些问题需要避免,但是,如果不知道这些问题在各种机器上是如何解决的,就最好不要尝试运用某种特殊的实现方式。
3.1 语句与程序块
在x=0、i++或printf(...)这样的表达式之后加上一个分号(;),它们就变成了语句。例如
x = 0;
i++;
printf(...);
在C语言中,分号是语句结束符。
用一对花括号"{"与"}"把一组声明和语句括在一起就构成了一个符合语句(也叫做程序块),复合语句在语法上等价与单条语句。函数体中被花括号括起来的语句便是明显一例。if、else、while与for之后被花括号括住的多条语句也是类似的例子。(在任何程序块中都可以声明变量)右花括号用于结束程序块,其后不需要分号。
3.2 if-else语句
if-else语句用于条件判定。其语法如下所示:
if (表达式)
语句1
else
语句2
其中else部分是可选的。该语句执行时,先计算表达式的值,如果其值位真(即表达式的值为非0),则执行语句1;如果其值位假(即表达式的值为0),并且该语句包含else部分,则执行语句2.
因为if-else语句的else部分时可选的,所以在嵌套的if语句中省略它的else部分将导致歧义。如下:
if (n > 0)
if (a > b)
z = a;
else
z = b;
else部分与内层的if匹配,我们通过程序的缩进结构也可以看出来。如果这不符合我们的意图,则必须使用花括号强制实现正确的匹配关系:
if (n > 0) {
if (a > b)
z = a;
} else
z = b;
歧义性在下面这种情况下尤为有害:
if (n >= 0)
for (i = 0; i < n; i++)
if(s[i] > 0) {
printf("...");
return i;
}
else /* 错 */
printf("error -- n is negative\n");
程序的缩进结构明确地表明了设计意图,但编译器无法获得这一信息,它会将else部分与内层的if配对。这种错误很难发现,因此我们建议在有if语句嵌套的情况下使用花括号。
3.3 else-if语句
在C语言中我们会经常用到下列结构:
if (表达式)
语句
else if (表达式)
语句
else if (表达式)
语句
else if (表达式)
语句
else
语句
这种if语句序列时编写多路判定最常用的方法。其中的各表达式将被依次求值,一旦某个表达式结果为真,则执行与之相关的语句,并终止整个语句序列的执行。同样,其中各语句既可以时单条语句,也可以时用花括号括住的复合语句。
最后一个else部分用于处理“上述条件均不成立”的情况或默认情况。有时候并不需要针对默认情况执行显式的操作,这种情况下,可以把该结构末尾的
else
语句
部分省略掉;该部分也可以用来检查错误,以捕获“不可能” 的条件。
这里通过一个折半查找函数说明三路判定程序的用法。该函数用于判定已排序的数组 v中是否存在某个特定的值x。数组v的元素必须以升序排列。如果v中包含x,则该函数返回x在v中的位置(介于0~n-1之间的一个整数);否则,该函数返回-1。
在折半查找时,首先将输入值x与数组v的中间元素进行比较。如果x小于中间元素的值,则在该数组的前半部分查找;否则,在该数组的后半部分查找。在这两种情况下,下一步都是将x与所选部分的中间元素进行比较。这个过程一直进行下去,直到找到指定的值或查找范围为空。
/* binsearch函数: 在v[0] <= v[1] <= v[2] <=...<=v[n-1]中查找x */
int binsearch1(int x, int v[], int n) {
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high) {
mid = (low+high) / 2;
if (x < v[mid])
high = mid - 1;
else if (x > v[mid])
low = mid + 1;
else /* 找到了匹配的值 */
return mid;
}
return -1; /* 没有匹配值 */
}