C 语言学习 第四章 运算符、表达式和语句

 本章将会学习 C 语言的运算符、表达式和语句。并且将会介绍选择和循环结构的使用。欢迎大家一起学习。上章入口:【C 语言学习 第三章 格式化输入/输出(I/O) 】

  • 1. 运算符和表达式

    • 1.1 运算符

    • 基本运算符

    •  C 使用运算符(operator)来代表算术运算。

    • 几个术语:数据对象、左值、右值、和操作数
              “数据对象”(data object)是泛指数据存储区的术语,数据存储区能用于保存值。例如,用于保存变量或数组的数据存储区是一个数据对象。
              C 的术语左值 (Ivalue)指用于标识一个特定的数据对象的名字或表达式。例如,变量的名字是一个左值。所以对象指的是实际的数据存储,但是左值是用于识别或定位那个存储的标识符。
              术语“右值”(rvalue)指的是能赋给可修改的左值的量。
              在您学习事物的名称时,我们称之为“项目”的东西(比如在“符号=左边的项目”中的“项目”)的正确术语是“操作数”(operand)。操作数是运算符操作的对象。
      1.加、减法运算符:+、-
            
      “加法运算符”(addition operator)使得在它两侧的值被加到一起。
            “减法运算符”(subtraction operator)从它前面的数中减去它后面的数。
            这时,这两个运算符被称为二元(binary)或双值(dyadic)运算符,这代表它们需要两个操作数。
      2.符号运算符:- 和 +
             
      负号可以用于指示或改变一个值的代数符号。正号不改变它知道操作数的值或符号。
             这时,这两个运算符被称为一元运算符(unary operator),这代表它们只需要一个操作数。
      3.乘法运算符:*
             
      乘法由符号*表示。
      4.除法运算符:/
             
      除法由符号/表示。/左边的值被右边的值除。
             整数型的除法运算和浮点型的除法运算有很大不同。浮点类型的除法运算得出一个浮点数结果,而整数除法运算则产生一个整数结果。整数不能有小数部分,这使得用3去除5很让人头痛,因为结果有小数部分。在C中,整数除法结果的小数部分都被丢弃。这个过程被称截尾(truncation)。例如:

      a=3/5;
      b=3.0/5.0;

      结果是,a = 0 ,b = 0.6 。同时,在截尾的过程中是“趋零截尾”,即 -3.4 的截尾是 -3 ,靠近 0 的。
      5.取模运算符:%
              取模运算符(modulus operator)用于整数运算。该运算符计算出它右边的整数去除它左边的整数得到的余数。

      6.赋值运算符
              在 C 里,符号 = 不代表“相等”,而是一个赋值运算符。比如:

      a=2024;

              相当于把 2024 的值赋给 a ;而

      2024=a;

              是不正确的。
              同时,符号 = 可以和上述几个符号连用。比如:+=、-=、/=、*=、%= 。
              以 += 举例,a+=b 相当于 a=a+b 。类似的其他的一样。

    • 位运算符

    • 任何数据在计算机存储器内都是以二进制数的形式存在的。
    • 1.按位与运算符:&
             按位与运算是对两个操作数逐位“求与”,当它们都为 1 时,结果为 1 ,否则为 0 。例如:
      (10010011)&(00111101)

      的结果值是:
      (00010001)。
      2.按位或运算符:|
             按位或运算符是对两个操作数逐位“求或”,当它们都为 0 时,结果为 0 ,否则为 1 。例如:
      (10010011)&(00111101)
      的结果值是:
      (10111111)
      3.按位异或运算符:^
             按位异或运算符是对两个操作数逐位“求异或”,当它们不同时为 1 ,相同时为 0 。例如:
      (10010011)&(00111101)
      的结果是:
      (10101110)
      4.按位取反运算符:~
             按位取反运算符是对一个操作数逐位“取反”,当为 1 时变为 0 , 当为 0 时变为 1 。例如:
      ~(10011010)
      的结果是:
      (01100101)
      5.二进制左移运算符:<<
             
      二进制左移运算符是将数据向左移动若干位,移出左边界的所有位丢失,右侧新增加的位为 0 。例如:
      (00000001)<< 2
      结果是:
      (00000100)
      6.二进制右移运算符:>>
             
      二进制右移运算符是将数据向右移动若干位,移出右边界的所有位丢失,左侧新增加的位的补充遵循下面的规则:
             1)对于无符号数,右移时左侧的新位一律补 0 ,称为“逻辑右移”。
             2)对于有符号数,若符号位是 0,则左侧新位一律补 0 ;若符号位是 1 ,则左侧新位一律补 1 ,称为“算数右移”。
      例如:
      (00001000)>> 2
      的结果是:
      (00000010)

    • 其他运算符

    • 1.sizeof 运算符
             
      sizeof 运算符以字节位单位返回其操作数的大小。操作数可以是一个具体的数据对象(例如一个变量名),或者一个类型。如果它是一个类型(如 float ),操作数必须被括在圆括号里。
      2.增量和减量运算符:++ 和 --
             
      增量运算符(increment operator)完成简单的任务,即将其操作数的值增加 1 。这是以两种方式出现的。在第一种方式中,++ 出现在它作用的变量的前面,这是前缀(prefix)模式。在第二种方式中,++ 出现在它作用的变量的后面,这是后缀(postfix)模式。这两种模式的区别在与值的增加这一动作发生的准确时间是不同的。例如:
      程序 1:
      #include<stdio.h>
      int main(void)
      {
          int a=0,b=0;
          a++;
          ++b;
          printf("%d %d\n",a,b);
          printf("%d %d\n",a++,++b);
          printf("%d %d\n",a,b);
          return 0;
      }

      结果是:
      1 1
      1 2
      2 2
      显然,前置 ++ 是先 +1 后使用,而后置 ++ 是先使用后 +1。
             类似的,减量运算符(decrement operator)与增量运算符对应。
      3.逻辑运算符:&&、||、!
             && 运算符是对两个操作数进行“逻辑与”,即同为真时才为真,其他为假。
              || 运算符是对两个操作数进行“逻辑或”,即同为假时才为假,其他为真。
              !运算符是对一个操作数进行“逻辑非”,即假时变为真,真时变为假。
              在 C 语言中,非 0 值的表达式视为逻辑真,0 值视为逻辑假。
              补充:
              当使用 && 或 || 时,若前一个操作数就能够判断出结果时,后一个操作数不进行运算。例如:

      #include<stdio.h>
      int main(void)
      {
          int a = 0, b = 0, c = 0;
          c = a++ && b++;
          printf("%d %d %d\n", a, b, c);
          c = ++b && a++;
          printf("%d %d %d\n", a, b, c);
          c = a-- || b--;
          printf("%d %d %d\n", a, b, c);
          c = --b || a--;
          printf("%d %d %d\n", a, b, c);
          return 0;
      }

      结果是:
      1 0 0
      2 1 1
      1 1 1
      0 0 1
      4.关系运算符:<、<=、==、>=、>、!=
      <运算符是对两个操作数进行“小于”关系判断。
      <=运算符是对两个操作数进行“小于或等于”关系判断。
      ==运算符是对两个操作数进行“等于”关系判断。
      >=运算符是对两个操作数进行“大于或等于”关系判断。
      >运算符是对两个操作数进行“大于”关系判断。
      !=运算符是对两个操作数进行“不等于”关系判断。

    • 1.2 表达式和语句

    • 表达式

    •        表达式(expression)是由运算符和操作数组合构成的。最简单的表达式是一个单独的操作数,以此作为基础可以建立复杂的表达式。而每一个表达式都有一个值。
    • 语句

    •        语句(statement)是构造程序的基本成分。程序(program)是一系列带有某种必需的标点的语句集合。
             一个语句是一条完整的计算机指令。在 C 中,语句用结束处的一个分号标识。
             语句有简单语句和复合语句。
             简单语句(simple  statement)以一个分号结束。
             复合语句(compound statement)是使用花括号组织起来的两个或更多的语句;它也被称为一个代码块(block)。
  • 2. 运算符的混合运算

    • 2.1 自动类转换

    •        语句和表达式通常应该只使用一种类型的变量和常量。然而,如果您混合使用类型,C 不会像 Pascal 那样停在那里死掉。相反,它使用一个规则集合来自动完成类型转换。这可能很方便,但是它也很危险,尤其是在您无意地混合使用类型的情况下(许多 UNIX  系统都有自带的 lint 程序可以检查类型“冲突”。如果您选择了一个更高的错误等级,许多非 UNIX 的 C 编译器将报告可能的类型问题)。您最好能有一些类型转换规则的知识。基本的规则如下:
             1. 当出现在表达式里时,有符号和无符号的 char 和 short 类型都将自动被转换为 int,在需要的情况下,将自动被转换为 unsigned int(如果 short 与 int 有相同的大小,那么 unsigned short 比 int大:在那种情况下,将把 unsigned short 转换为 unsigned int)。在 K&RC 下,但不是当前的 C 下,float 将被自动转换为 double 。因为是转换成较大的类型,所以这些转换被称为提升(promotion).
             2. 在包含两种数据类型的任何运算里,两个值都被转换成两种类型里较高的级别。
             3.类型级别从高到低的顺序是 long double 、double 、float 、unsigned long long 、long long 、unsignedIong 、Iong 、unsigned int 和 int 。一个可能的例外是当 long 和  int 具有相同大小时,此时 unsigned int 比 long 的级别更高。
             4.在赋值语句里,计算的最后结果被转换成将要被赋予值的那个变量的类型。像规则 1 中一样,这个过程可能㝵致提升;但也可能㝵致降级(demotion),降级是将一个值转换成一个更低级的类型。
             5. 当作为函数的参数被传递时,char 和 short 会被转换为 int , float 会被转換为 double。可以通过函数原型来阻止自动提升的发生。
             当然在 C 语言中可以强制类型转换:
             表达式为:     (类型名) 表达式
    • 2.2 运算符的优先级

    •        像数学一般,C 语言也有运算符的优先级,如下表所示:

  • 3. 循环语句和选择语句

    • 3.1 循环语句

    •        循环结构是在给定条件下,反复执行某个语句,这个语句叫循环语句。 C 语言中有三个循环语句:for 循环、while 循环、do while 循环。
    • while 循环

    •         结构样式:
              while(表达式 1)
               {
                       循环体;
               }
    •          说明:
               1)作为循环条件的表达式 1 中一般至少包括一个能够改变表达式的变量,这个变量称为循环变量。
               2)当条件表达式为真时,执行循环体,为假时退出循环。while(1) 表示无限循环
               3)当循环体不需要实现任何功能时,可以用空语句作为循环体。
      while((ch=getchar())!='\n');

               4)循环语句应有出口(通过循环语句的条件或循环体中的 break 语句)。
               5)对于循环变量的初始化应在 while() 语句之前进行,通过适当的方式给循环变量赋初值。

    • 程序 1:

      /*0~99 的累加*/
      #include<stdio.h>
      int main(void)
      {
          int i = 0,s=0;
          while (i < 100)
          {
              s += i;
              i++;
          }
          printf("%d", s);
          return 0;
      }

      结果:
      4950

    • for 循环

    •        结构样式:
             for(表达式 1 ;表达式 2 ;表达式 3 )
              {
                      循环体
              }
    •         其中,表达式 1 用于进入循环前给某些变量赋初值;表达式 2 表明循环的条件;表达式 3 用于循环,并依次对某些变量的值进行修改。
    •         for 循环通常用于构造“初值、终值、步长”型循环。
    •         注意:
              1)表达式 1 、表达式 2 、表达式 3 可以全部或部分省略,但分号是不能省略的。for(;;) 等同于 for(;1;)。
              2)循环体也可以空语句,如:
      for(int i=0;i<100;i++);
      或
      for(int i=0;i<100;i++) {}

              3)不可在循环体中修改循环变量,防止失控。
              4)建议 for 语句的循环控制变量的取值采用“半开半闭区间”写法。如上。

    • 程序 2:

      /* 0~99 的累加*/
      #include<stdio.h>
      int main(void)
      {
          int i = 0,s=0;
          for (i = 0; i < 100; i++)
          {
              s += i;
          }
          printf("%d", s);
          return 0;
      }

      结果:
      4950

    • do-while 循环

    •         结构样式:
              do
               {
                       循环体;
               }while(表达式 1);
    •          其中,表达式 1 表明循环的条件。
    •           1)while 、do-while 、for 循环是可以相互转换的。但是一般而言,do-while 循环比 for 循环要用得少得多。
                2)do-while 循环体类型于 while 循环,不同之处是,它们执行循环体于计算表达式的先后顺序不同。do-while 循环要至少执行一次循环体。
                3)与 while 循环和 for 循环不同,do-while 循环在最后要加一个分号,而这往往容易忘记。
    • 程序 3:
      /* 0~99 的累加*/
      #include<stdio.h>
      int main(void)
      {
          int i = 0,s=0;
          do {
              s += i;
              i++;
          } while (i < 100);
          printf("%d", s);
          return 0;
      }

      结果:
      4950

    • 3.2 选择语句

    • if 语句

    •         结构样式 1:
              if(表达式 1 )
               {
                        语句 1;
               }
    •          结构样式 2:
               if(表达式 1 )
                {
                        语句 1;
                }
               else
                {
                        语句 2;
                }
    •          结构样式 3:
               if(表达式 1 )
                {
                        语句 1;
                }
               else if(表达式 2)
                 {
                        语句 2;
                 }
                ......
               else
                 {
                        语句 n;
                 }
    •            以结构样式 3 来说明,C 语言从上往下开始读取,若表达式 1 为真则执行语句 1 且结束该 if 语句,若为假则跳过语句 1 去判断表达式 2 ,真则执行语句 2 且结束该 if 语句,假则跳过继续往下判断,…… ,若以上均为假则执行 else 中的语句 n 结束该 if 语句。
    • 程序 4:
      #include<stdio.h>
      int main(void)
      {
          char s;
          s = getchar();
          if (s <= '9' && s >= '0')
              printf("数字\n");
          else if (s <= 'z' && s >= 'a' || s <= 'Z' && s >= 'A')
              printf("字母\n");
          else
              printf("go away!\n");
          return 0;
      }

      结果:
      b
      字母

    • switch 语句

    •        结构样式:
             switch(表达式 1)
             {
              case n1:语句 1;
                       break;
              case n2:语句 2;
                       break;
              ......
              default:语句 n;
                       break;
             }
    •        当其整数值等于一个数 nk 时,则执行 case nk 所对应的语句 k 且结束 switch 语句。若均不满足,则执行 default 所对应的语句 n 结束 switch 语句。
    •         注意:
              1)各个 case 和 default 的顺序可以是任意的,但各个 case 后的值必须不一样。
              2)表达式 1 的结果必须为一个整数值且 case 后的 n1、n2、... 、n 均为常数。
              3)case 语句往往配合 break 语句一起使用,如果不加 break 则程序会按顺序执行下一个 case 语句。 
              4)default 语句不是必需的。
    • 程序 5:
      #include<stdio.h>
      int main(void)
      {
          char s;
          s = getchar();
          switch (s)
          {
          case 'y':
              printf("yes\n");
              break;
          case 'n':
              printf("no\n");
              break;
          default:
              printf("go away!\n");
              break;
          }
          return 0;
      }

      结果:
      s
      go away!

    • 条件运算符 ? :

    •        结构样式:
             表达式 1?表达式 2:表达式 3;
    •        若表达式 1 为真则执行表达式 2 ,否则执行表达式 3 。
    •        这往往用于简单的条件选择应用。
    • 程序 6:
      #include<stdio.h>
      int main(void)
      {
          int a = 3, b = 6;
          printf("%d", a > b ? a : b);
          return 0;
      }

      结果:
      6

  • 4. 辅助控制语句

    • 4.1 break

    •        break 语句不能用于循环体语句和 switch 语句之外的任何其他语句。
             1)可以使流程跳出 switch 结构,继续执行 switch 下面的语句。
             2)可以用来从循环体内跳出循环体,即结束当前循环,执行循环下面的语句。
             注意:一个 break 语句只能跳出一层循环。 
    • 4.2 continue

    •        结束本次循环,即跳过循环体尚未执行的语句,接着继续下一次是否执行循环的判定。
             continue 语句和 break 语句的区别: continue 语句只是结束本次循环,而不是中止整个循环,而 break 语句则是结束整个循环过程,不在判断执行循环的条件是否成立。
    • 程序 7:
      #include<stdio.h>
      #include<math.h>
      #define PI 3.1415926
      int main(void)
      {
          double r, area;
          while (1)
          {
              printf("input the radius:");
              scanf("%lf", &r);
              if (fabs(r) <= 1e-5) break;
              else if (r < 0.0)
              {
                  printf("the input is error\n");
                  continue;
              }
              area = PI * r * r;
              printf("the area is:%lf\n", area);
          }
          return 0;
      }

      结果:
      input the radius:-1
      the input is error
      input the radius:1
      the area is:3.141593
      input the radius:0

    • 4.3 goto

    •        结构样式:
             goto  标号;
             …
             标号:语句;
    •        goto 语句的功能是,把程序控制转移到标号指定的语句处。即执行 goto 语句后,程序从指定标号处继续执行。
              注意:goto 语句常用来退出多重循环。但是本章不建议在学习中使用 goto 语句,因为使用 goto 语句很容易出现各种问题,解决起来会非常麻烦。
    • 程序 8:
      #include<stdio.h>
      #include<math.h>
      #define PI 3.1415926
      int main(void)
      {
          double r, area;
          while (1)
          {
              printf("input the radius:");
              scanf("%lf", &r);
              if (fabs(r) <= 1e-5) goto note;
              else if (r < 0.0)
              {
                  printf("the input is error\n");
                  continue;
              }
              area = PI * r * r;
              printf("the area is:%lf\n", area);
          }
          note:
          return 0;
      }

      结果:
      input the radius:-1
      the input is error
      input the radius:1
      the area is:3.141593
      input the radius:0

 参考书籍:《C Primer Plus》【美】 Stephen Prata 著

                         《程序设计教程 用 C/C++ 语言编程》 周纯杰 何顶新 周凯波 彭刚 张惕远 编著

 

  • 27
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值