• C语言K&R圣经笔记 第3章控制流 3.1语句和块 3.2 if-else 3.3 else-if


    第3章控制流

    语言的控制流语句指定了计算执行的顺序。在前面的例子中,我们已经见过了大部分常见的控制流语句;这里我们会将它补全,并给出比之前更精确的说明。

    3.1 语句和块

    如 x = 0 或 i++ 或 printf(...) 这样的表达式,在末尾添加分号之后,就成为了语句,如

    1. x = 0;
    2. i++;
    3. printf(...);

    在C中,分号是语句的结束符,而不是分隔符(如Paslcal这样的语言中的分号是分隔符)。

    大括号 { 和 } 用来将一些声明和语句组合成复合语句,或者称为,这样它们在语法上和单条语句是等价的。一个显著的例子是用来包围函数内所有语句的大括号;而另一个例子是 if,else,while 和 for 后面包围多条语句的大括号。(变量可以在任意块中声明,这个将在第四章讨论。)块末尾的右大括号后面,没有分号。

    3.2 if-else

    if-else 语句用来表示决策。正式的语法为

    if (表达式)

            语句1

    else

            语句2

    其中 else 部分是可选的。对表达式求值;如果它为真(即表达式有非0值),则执行语句1。如果它为假(表达式为0)且存在 else 部分,则执行语句2。

    既然 if 只会简单地检查表达式的数值,则某些代码就能有简化写法。最明显的是写

    if (表达式)

    而不写

    if (表达式 != 0)

    有时这个写法是自然而且清晰的,而有时会令人费解。

    因为 if-else 的 else 部分是可选的,在嵌套的 if 序列内去掉 一个else 就会造成歧义。通过将 else 关联到最近一个没有 else 的 if,可以消解这个歧义。例如

    1. if (n > 0)
    2. if (z > b)
    3. z = a;
    4. else
    5. z = b;

    其中的 else 关联里面的 if,与我们的缩进一致。如果这不是你要的代码逻辑,就需要使用大括号来强制得到合适的关联:

    1. if (n > 0) {
    2. if (z > b)
    3. z = a;
    4. } else
    5. z = b;

    这种歧义在一些情况下特别恶劣,比如:

    1. if (n >= 0)
    2. for (i = 0; i < n; i++)
    3. if (s[i] > 0) {
    4. printf("...");
    5. return i;
    6. }
    7. else /* 错了!!! */
    8. printf("error -- n is negative\n");

    缩进明确表示了你想要什么,但编译器无法获取这个信息,并将 else 关联到内层的 if 。这种类型的 bug 很难找;而只要遇到嵌套的 if,就加上大括号,是个不错的主意。

    顺带一提【应该是给Pascal程序员看的】,下面的 z = a 后面有分号。

    1. if (n > 0)
    2. if (z > b)
    3. z = a;
    4. else
    5. z = b;

    这是因为在语法上,if 后面跟的是个语句,而表达式语句如 “ z = a; ” 总是以分号结尾。

    3.3 else-if

    1. if (expression)
    2. statement
    3. else if (expression)
    4. statement
    5. else if (expression)
    6. statement
    7. else if (expression)
    8. statement
    9. else
    10. statement

    上面这个结构在C程序中出现得如此频繁,因此值得将它单独拿出来简要地讨论一下。它是写多路选择的最常用的方式。其中的表达式(expression)被依次求值;如果任一表达式为真,则其关联的语句(statement)被执行,且整个链条结束。当然,其中的每个“语句”可以是单条语句,或者是大括号中的一组语句。

    当其他条件都不满足时,最后一个 last 部分用来处理“以上皆不是”或者说默认情况。有时对默认情况不需要做显式的动作,此时末尾的

    1. else
    2. statement

    就可以去掉,或者用来进行错误校验,捕获“不可能发生”的情况。

    下面这个二分查找函数用来确定一个特定的值 x 是否存在于一个已排序的数组 v 中,它演示了三路决策。v 的元素必须是升序的。如果 x 存在于 v 中,函数返回其所在的位置(0 到 n - 1之间的值),否则返回 -1。

    二分查找首先将输入值 x 与 数组 v 中间的元素进行比较。如果 x 小于中间的值,则搜索聚焦于数组的下半部分,否则聚焦于上半部分。不管是哪种情况,下一步是将 x 与 所选一半的中间值进行比较。这个过程持续地将范围一分为二,直到找到值,或者范围为空。

    1. /* 二分查找:在 v[0] <= v[1] <= ... <= v[n-1] 中找到x */
    2. int binsearch(int x, int v[], int n)
    3. {
    4. int low, high, mid;
    5. low = 0;
    6. high = n - 1;
    7. while (low <= high) {
    8. mid = (low + high) / 2;
    9. if (x < v[mid])
    10. high = mid -1;
    11. else if (x > v[mid])
    12. low = mid + 1;
    13. else /* 找到匹配值 */
    14. return mid;
    15. }
    16. return -1; /* 没找到 */
    17. }

    基本的决策是在每步要判断 x 是小于、大于或等于中间元素 v[mid] 的值;用 else-if 是很自然的。

    练习 3-1、我们的二分查找在循环中做了两次判断,而一个判断就足够了(代价是在外面做更多判断)。写个函数只在循环内做一次判断,并测量运行时间的差异。

  • 相关阅读:
    Linux:Socket套接字编程 | UDP
    pytorch加载darknet权重文件
    ubuntu服务器中运行flask
    mindspore-使用net(input)或者model.predict获取对应预测值,forward获取一次结果较慢
    【深度学习】基于卷积神经网络(tensorflow)的人脸识别项目(三)
    贴片电容材质的区别与电容的主要作用
    Microsoft SQL Server Management Studio(2022版本)启动无法连接到服务器
    使用Delaunay三角剖分进行数据分析与可视化
    pytorch 笔记:index_select
    零售业:用这个小技巧,轻松搞定业绩!
  • 原文地址:https://blog.csdn.net/baluzju/article/details/134280621