zoukankan      html  css  js  c++  java
  • 《C程序设计语言》 第三章 控制流


    3.1 语句与程序块

    在表达式之后加上一个分号(;),它们就变成了语句。
    用一对花括号“{”与“}”把一组声明和语句括在一起就构成了程序块,在语法上等价于单条语句。


    3.2 if-else语句

    每个else与最近的前一个没有else配对的if进行匹配。

    if (n > 0)
         if (a > b)
              z = a;
    else
         z = b;

    程序的缩进结构明确表明了设计意图,但编译器无法获得这一信息,它会将else部分与内层的if配对。


    3.3 else-if语句

    /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
    int binsearch(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     /* found match */
                   return mid;
         }
         return -1;
    }

    练习3-1     上面折半查找的例子中,while循环语句内执行了两次测试。重写该函数,
    使循环内部只执行一次测试。比较两种版本函数的运行时间。
    答:
    while (low <= high) {
         mid = (low + high) / 2;
         if (x < v[mid])
              high = mid +1;
         else
              low = mid + 1;
    }
    if (x == v[mid])
         return mid;
    else
         return -1;


    3.4 switch语句

    case的作用只是一个标号,从某个分支中的代码执行完后,程序将进入下一分支继续执行。
    跳出switch语句最常用的方法是使用break和return语句。

    作为一种良好的程序设计风格,在switch语句最后的default分支后面也加上一个break语句。
    这样做在逻辑上没有必要,但当我们需要向该switch语句后添加其他分支时,这样会降低犯
    错误的可能性。

    练习3-2     编写一个函数escape(s, t),将字符串t复制到字符串s中,并在复制过程中将换行符、
    制表符等不可见字符分别转换为\n、\t等相应可见的转义字符。再编写一个相反功能的函数。
    答:
    #include <stdio.h>
    void escape(char s[], char t[])
    {
         int i, j;
         for (i = 0, j = 0; s[i] != '\0'; i++) {
              switch (s[i]) {
              case '\n':
                   t[j++] = '\\';
                   t[j++] = 'n';
                   break;
              case '\t':
                   t[j++] = '\\';
                   t[j++] = 't';
                   break;
              default:
                   t[j++] = s[i];
                   break;
              }
         }
         t[j] = '\0';
    }
    void escape2(char s[], char t[])
    {
         int i, j;
         for (i = 0, j = 0; s[i] != '\0'; j++) {
              switch (s[i]) {
              case '\\':
                   if (s[i+1] == 'n') {
                        t[j] = '\n';
                        i += 2;
                   }
                   else if (s[i+1] == 't') {
                        t[j] = '\t';
                        i += 2;
                   }
                   else {
                        t[j] = s[i];
                        i++;
                   }
              default:
                   t[j] = s[i++];
                   break;
              }
         }
    }
    main()
    {
         char s[] = "this is     cdai";
         char t[20];
         escape(s, t);    
         printf("%s\n", t);

         char t2[20];
         escape2(t, t2);
         printf("%s\n", t2);
    }


    3.5 while循环与for循环

    for (表达式1; 表达式2; 表达式3)
         语句

    等价于=>

    表达式1;
    while (表达式2) {
         语句
         表达式3;
    }

    逗号运算符“,”在for语句中经常用到。被逗号分隔的一对表达式将按照从左到右的顺序进行求值,
    分隔函数参数的逗号,分隔声明中变量的逗号等不是逗号运算符,不保证从左至右顺序求值。

    /* reverse: reverse string s in place */
    void reverse(char s[])
    {
         int c, i, j;
         for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
              c = s[i], s[i] = s[j], s[j] = c;
    }

    练习3-3     编写函数expand(s1, s2),将字符串s1中类似于a-z一类的速记符号在字符串s2中
    扩展为等价的完整列表abc...xyz。该函数可以处理大小写字母和数字,并可以处理a-b-c、
    a-z0-9与-a-z等类似的情况。作为前导和尾随的-字符原样排印。
    答:
    #include <stdio.h>
    void expand(char s1[], char s2[])
    {
         int i, j, k;
         i = j = 0;
         while (s1[i] != '\0') {
              if (s1[i] == '-' && 0 < i && s1[i+1] != '\0' &&
                   s1[i-1] != '-' && s1[i+1] != '-') {
                   j--;     // avoid duplicate letter
                   for (k = s1[i-1]; k <= s1[i+1]; k++, j++)
                        s2[j] = k;
                   i += 2;
              } else {
                   s2[j++] = s1[i++];
              }
         }
         s2[j] = '\0';
    }
    main()
    {
         char s1[] = "-a-b-hAbC-G0-8---";
         char s2[100];
         expand(s1, s2);
         printf("before expand:%s\nafter expand: %s\n", s1, s2);
    }


    3.6 do-while循环

    /* itoa: convert n to characters in s */
    void itoa(int n, char s[])
    {
         int i, sign;
         
         if ((sign = n) < 0)               /* record sign and make n positive */
              n = -n;

         i = 0;
         do {                                   /* generate digits in reverse order */
              s[i++] = n % 10 + '0';     /* convert number to char */
         } while ((n /= 10) > 0);
         
         if (sign < 0)
              s[i++] = '-';
         s[i] = '\0';
         reverse(s);
    }

    这里使用do-while语句会方便一些,因为即使n为0,也至少要把一个字符放到数组s中。
    do-while中只有一条语句,(没有必要)但扔用花括号括起来,因为可以避免将while误认为
    是另个while循环的开始。

    练习3-4     在数的对二的补码表示中,上面的itoa函数不能处理最大的负数-2的(字长-1)次方
    的情况。解释其原因,并修改函数使它在任何机器上运行时都能打印出正确的值。
    答:
    例如char字长为8位,则对二补码范围为-128~127。值为-128的char,n=-n;后值仍为-128。
    128的二进制源码为01111111,通过补码的负数转换规则得到10000000,即-128二进制码为80(可用prinf("%hhx);验证)。

    修改函数,不将n转为正数,而是将每次取模运算的结果转为正数。从而避开无法将最大负数转为正数的问题。
    #include <stdio.h>
    #define abs(x) ((x) < 0 ? -(x) : (x))
    void itoa(int n, char s[])
    {
         int i, sign;
         sign = n;

         i = 0;
         do {
              s[i++] = abs(n % 10) + '0';
         } while ((n /= 10) != 0);

         if (sign < 0)
              s[i++] = '-';
         s[i] = '\0';
         //reverse(s);     
    }
    main()
    {
         char s[20];
         itoa(10, s);
         printf("%s\n", s);
         itoa(-128, s);
         printf("%s\n", s);
    }

    练习3-5     编写函数itob(n, s, b),将整数n转换为以b为底的数,并将转换结果以字符的形式
    保存到字符串s中。例如,itob(n, s, 16)把整数n格式化为十六进制整数保存在s中。
    答:
    #include <stdio.h>
    #include "reverse.c"
    #define abs(x) (x) < 0 ? -(x) : (x)

    void itob(int n, char s[], int b)
    {
         int i, x, sign;
         sign = n;
         i = 0;
         do {
              x = abs(n % b);
              if (x >= 10)
                   s[i++] = (x - 10) + 'A';
              else
                   s[i++] = x + '0';
         } while ((n /= b) != 0);
         if (sign < 0)
              s[i++] = '-';
         s[i] = '\0';
         reverse(s);
    }
    main()
    {
         char s[20];
         itob(29, s, 2);     
         printf("%s\n", s);

         itob(-257, s, 16);
         printf("%s\n", s);
    }

    练习 3-6     修改itoa函数,使得该函数可以接收三个参数。第三个参数为最小字段宽度。
    为了保证转换后结果至少具有第三个参数指定的最小宽度,必要时在结果左边填充一定的空格。
    答:
    ...
    if (sign < 0)
         s[i++] = '-';
    while (i <= w-1)     // fill space
         s[i++] = ' ';
    ...


    3.7 break和continue语句


    3.8 goto语句与标号


  • 相关阅读:
    这个帖子主要总结数据库备份方面的问题
    Visual C#.Net 网络程序开发Socket篇
    数据库设计说明书参考模板
    用Visual C#开发WinForm的应用程序
    在ASP.NET页中读取文本文件
    如何通过 SQL Server 链接服务器和分布式查询使用 Excel
    ER概念模型
    SQL Server 存储过程的分页方案比拼
    读出某一个目录的文件和文件夹
    Linux中的定时任务简单操作实例
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157898.html
Copyright © 2011-2022 走看看