第五章运算符表达式和语句


title: 第五章 运算符、表达式和语句
author: HardyDragon
tags: C Notes


第五章 运算符、表达式和语句

5.1 循环简介

5.2 基本运算符

5.2.1 赋值运算符:=

±*/

运算符优先级

优先级和求值顺序

5.3 其他运算符

5.3.1 sizeof 运算符和size_t类型

5.3.2 求模运算符:%

5.3.3 递增运算符:++ 递减运算符:–

优先级

不要自作聪明

5.4 表达式和语句

5.4.1 表达式

5.4.2 语句

5.4.3 复合语句(块)

5.5 类型转换

5.6 带参数的函数

5.7 示例程序

5.8 关键概念

5.9 本章小结

5.10 复习题

5.11 编程练习


5.1 循环简介

循环可以重复执行行为,让程序更有趣,更强大,更哲学,更 ♂(doge);

// shoes1.c -- 将鞋码转换成英寸
#include<stdio.h>
#define ADJUST 7.31
int main(int argc, char const *argv[])
{
    
    
    const double SCALE = 0.333; // const 变量
    double shoe ,foot;

    shoe = 9.0;
    foot = SCALE * shoe + ADJUST;
    printf("Shoe size (men's) foot length\n");
    printf("%10.1f %15.2f incher\n",shoe,foot);

    return 0;
}

result

Shoe size (men's) foot length
       9.0           10.31 incher

应用while循环 输出不同鞋码的脚长

// shoes2.c -- 计算多个不同鞋码对应的脚长
#include <stdio.h>
#define ADJUST 7.31
int main(int argc, char const *argv[])
{
    
    
    const double SCALE = 0.333;
    double shoe, foot;

    printf("Shoe size (men's)   foot length\n");
    shoe = 3.0;
    while (shoe < 18.5)
    {
    
    
        foot = SCALE * shoe + ADJUST;
        printf("%10.1f %15.2f inches\n",shoe,foot);
        shoe = shoe + 1.0;
    }
    printf("If the shoe fits,wear it.\n");
    

    return 0;
}

result:

Shoe size (men's)   foot length
       3.0            8.31 inches
       4.0            8.64 inches
       5.0            8.97 inches
       6.0            9.31 inches
       7.0            9.64 inches
       8.0            9.97 inches
       9.0           10.31 inches
      10.0           10.64 inches
      11.0           10.97 inches
      12.0           11.31 inches
      13.0           11.64 inches
      14.0           11.97 inches
      15.0           12.31 inches
      16.0           12.64 inches
      17.0           12.97 inches
      18.0           13.30 inches
If the shoe fits,wear it.

关于while 循环的原理,当程序第一次到达while循环时,会检查圆括号中的条件是否为真。

while语句下面的花括号内容就是要被重复执行的内容,花括号以及被花括号括起来的部分被称为

5.2 基本运算符

pow(3.5,2.2); 返回3.5的2.2次幂

= 的左侧必须是一个变量名,实际上赋值运算符左侧必须引用一个存储位置。最简单的就是变量名,当然指针也可用于指向一个存储位置。
赋值表达式语句的目的是为了将值存储到内存位置上。用于存储值的数据区域统称为数据对象。使用变量名是标识对象的一种方法。还可以指定数组的元素、结构的成员,指针表达式为对象。
左值是C语言的术语,用于标识对象的名称或表达式。因此,对象指的是实际的数据存储,而左值用于标识或定位存储位置的标签。
对于早期的C而言,提到左值意味着:

  1. 它指定一个对象,所以引用内存的地址;
  2. 它可以在赋值运算符的左侧,左值中的1源自left。

但是由于const的出现导致第二条有时不符合了。便改为了可修改的左值 用于 标识可修改的对象。
右值指的是能赋值给可修改左值的量,且本身不是左值。

// golf.c -- 高尔夫锦标赛积分卡
#include<stdio.h>
int main(int argc, char const *argv[])
{
    
    
    int jane,tarzan,cheeta;
    cheeta = tarzan = jane = 68;
    printf("                    cheeta  tarzan  jane\n");
    printf("First round score %4d %8d %8d\n",cheeta,tarzan,jane);

    return 0;
}

result:

                    cheeta  tarzan  jane
First round score   68       68       68

C语言的三重赋值是可以的,且赋值顺序是从右往左,首先把86赋值给jane,然后再赋给tarzen,最后赋给cheeta。
C99新加的一元+运算符:

dozen = +12;

以前是不被允许的。

打印1-20的平方:

// squares.c-- 计算1-20的平方
#include <stdio.h>
int main(int argc, char const *argv[])
{
    
    
    int num = 1;
    while (num < 21)
    {
    
    
        /* code */
        printf("%4d %6d\n", num, num * num);
        num += 1;
    }

    return 0;
}

result:

   1      1
   2      4
   3      9
   4     16
   5     25
   6     36
   7     49
   8     64
   9     81
  10    100
  11    121
  12    144
  13    169
  14    196
  15    225
  16    256
  17    289
  18    324
  19    361
  20    400

除法运算符: /
整数除法的结果是整数,浮点数除法的结果是浮点数。整数除法结果的小数部分被截断

// divide.c -- 演示除法
#include <stdio.h>
int main(int argc, char const *argv[])
{
    
    
    printf("5/4 = %d \n", 5 / 4);
    printf("6/3 = %d \n", 6 / 3);
    printf("7/4 = %d \n", 7 / 4);
    printf("7./4 = %1.2f \n", 7. / 4);
    printf("7./4 = %1.2f \n", 7. / 4);
    
    return 0;
}

result:

5/4 = 1
6/3 = 2
7/4 = 1
7./4 = 1.75
7./4 = 1.75

混合整数和浮点数计算的结果是浮点数,计算机不能真正的用浮点数除以整数,编译器会把两个运算对象转换成相同的类型。在除法运算前,整数会被转换为浮点数。
C99规定整数除法的结果不对小数部分四舍五入,直接截断小数部分。
运算优先级:先乘除,后加减,括号强
5.3 其他运算符

  • sizeof 运算符 和 size_t 类型

    sizeof 运算符 以字节为单位返回运算对象的大小,建议对变量和类型都用括号。

    sizeof 返回的是 size_t 类型的值,是一个无符号的整数类型,C语言将size_t 作为 unsigned int或unsigned long 的别名,可以使用typedef 实现。
    C99 新加了 %zd 转换说明用于printf() 显示size_t 类型的值。如果不支持%zd ,可使用 %u 或 %lu 来替代。

  • 求模运算符:%(对整数的求余数)

    // min_sec.c -- 把秒数转换为分和秒
    #include <stdio.h>
    #define SEC_PER_MIN 60
    int main(int argc, char const *argv[])
    {
          
          
        int sec, min, left;
        printf("enter seconds:\n");
        scanf("%d", &sec);
        while (sec > 0)
        {
          
          
            /* code */
            min = sec / SEC_PER_MIN;  // 截断分钟
            left = sec % SEC_PER_MIN; // 剩下的秒数
            printf("%d seconds is %d minutes,%d seconds.\n", sec,
                   min, left);
            printf("enter seconds:\n");
            scanf("%d", &sec);
        }
        printf("Done!");
    
        return 0;
    }
    
    

    result:

    enter seconds:
    154
    154 seconds is 2 minutes,34 seconds.
    enter seconds:
    567
    567 seconds is 9 minutes,27 seconds.
    enter seconds:
    0
    Done!
    

    如果不支持C99的标准,可以对a和b两个整数使用 a - (a/b) *b 来计算a%b 的值。

  • 递增运算符:++/递减运算符:–

    注意++/–的位置,放在对象前面就是先加后执行语句,放在对象后面就是先执行后加值。对于递减也是如此。

    // add_one.c -- 递增:前缀和后缀
    #include <stdio.h>
    int main(int argc, char const *argv[])
    {
          
          
        int ultra = 0, super = 0;
        while (super < 5)
        {
          
          
            /* code */
            super++;
            ++ultra;
            printf("super = %d ,ultra = %d \n", super, ultra);
        }
    
        return 0;
    }
    
    

    result:

    super = 1 ,ultra = 1
    super = 2 ,ultra = 2
    super = 3 ,ultra = 3
    super = 4 ,ultra = 4
    super = 5 ,ultra = 5
    

    递增递减运算符让程序更简洁,提高可读性。例如:

    shoe = 3.0;
    while (shoe < 18.5)
    {
          
          
        foot = SCALE * shoe + ADJUST;
        printf("%10.1f %15.2f inches\n",shoe,foot);
        shoe = shoe + 1.0;
    }
    

    可以修改成这样

    shoe = 2.0;
    while (++shoe < 18.5)
    {
          
          
        foot = SCALE * shoe + ADJUST;
        printf("%10.1f %15.2f inches\n",shoe,foot);
    }
    

    在上面的代码中,将变量的递增过程放入while循环的条件中,这种结构在C语言中很貌似很普遍。

    注意变量赋值时候使用要注意其值的变化。

    // post_pre.c -- 前缀和后缀
    #include <stdio.h>
    int main(int argc, char const *argv[])
    {
          
          
        int a = 1, b = 1;
        int a_post, pre_b;
    
        a_post = a++; //后缀递增
        pre_b = ++b;  // 前缀递增
        printf("a a_post b pre_b \n");
        printf("%ld %5d %5d %5d\n", a, a_post, b, pre_b);
    
        return 0;
    }
    
    

    result:

    a a_post b pre_b
    2     1     2     2
    

    a和b递增了1,但是a_post 是a递增前的值,而 b_pre 是b 递增之后的值。

    如果使用前缀或后缀会对代码产生不好的影响,就不要使用,例如:

    b = ++i;
    

    应该替换成

    ++i;
    b = i;	// 如果第一行使用 i++ 也不影响b的值
    
  • 关于递增递减运算符的优先级

    只有圆括号的优先级高于它们。例如:x*y++ 表示 的是 (x) * (y++) 。

  • 不要自作聪明

    编译器可以自行选择先对那个函数中的参数求值,或许可以提高效率,但是如果参数使用了递增运算符就会遇到一些问题。编译器可能会先计算递增的变量就导致输出结果异常。So,应当遵循以下规则来避免出现类似问题,以及正确规范的使用递增递减运算符,提高程序的可读性。

    • 如果一个变量出现在一个函数的多个参数中,不要对该变量使用递增或递减运算符;
    • 如果一个变量多次出现在一个表达式中,不要对该变量使用递增递减运算符

5.4 表达式和语句

  • 表达式

    表达式由运算符和运算对象组成,每个表达式都有一个值。

  • 语句

    一条语句相当于一条完整的计算机指令,大部分语句以分号;结尾。最简单的语句是空语句

    C把表达式加上一个分号的表达式都看作是一条语句,例如:

    8;
    3 + 4;
    
    // addemup.c -- 几种常见的语句
    #include<stdio.h>
    int main(int argc, char const *argv[])
    {
          
          
        int count=0,sum=0;  // 声明
        while (count++<20)  // 迭代语句
        {
          
          
            /* code */
            sum += count;
        }
        printf("sum = %d\n",sum);
        
        return 0;   // 跳转语句
    }
    
    
  • 副作用和序列点

    副作用是对数据对象或文件的修改。例如:printf() 的返回值是待显示字符的个数,这个就是副作用。

    序列点是程序执行的点,在这个点上,所有的副作用都在进入下一步前发生。C语言中的分号标记了一个序列点,意思是,赋值运算符、递增/递减运算符对运算对象的改变必须要在程序执行下一条语句前完成。任何一个完整表达式的结束也是一个序列点。例如while语句中的条件表达式就是完整的表达式,这个就是一个序列点,要在下一条程序执行前先作用完成。例如:

    #include <stdio.h>
    #include<limits.h>
    #include<string.h>
    int main()
    {
          
          
        int y,x;
        x = 0;
        y = (4 + x++) + (6 + x++);
        
        printf("y = %d\n",y);
        
        return 0;
    }
    
    

    result:

    y = 11
    

    应该避免编写这样的语句,因为 (4 + x++) 并不是一个完整的表达式,所以C无法保证在 (4 + x++) 求值后立即递增x,所以结果会有所不同。

     y = (4 + x++) + (6 + x++);
    

    5.5 类型转换

    在特定情况一些类型会自动被转换升级/降级。

    • 强制转换

      应该避免自动类型转换,使用强制类型转换,稳。

      #include <stdio.h>
      int main()
      {
              
              
          
          int mice;
          mice = (int)1.6 + (int)1.7;
      
          printf("mice = %d\n",mice);
          // printf("%2.2e",1201.0);
      
          return 0;
      }
      
      

      result:

      mice = 2
      

5.6 带参数的函数

// pound.c -- 定义一个带一个参数的函数
#include<stdio.h>
void pound(int n); // ANSI函数原型声明
int main(int argc, char const *argv[])
{
    
    
    int times = 5;
    char ch = '!';  // ANSI码 33
    float f = 6.0f;

    pound(times);   // int 
    pound(ch);      // pound((int)ch); 
    pound(f);       // pound((int)f); 
    
    return 0;
}
void pound(int n){
    
    
    while (n-->0)
    {
    
    
        /* code */
        printf("#");
    }
    printf("\n");
    
}


result:

#####
#################################
######

函数若不接受任何参数,就应该在圆括号中写上关键字 void。声明参数称为形式参数(形参),传入的参数被称为实际参数(实参)。
遇到参数和函数的形参类型不匹配的情况,程序的函数原型就会自动将实参转换为对应的类型以满足函数的要求。应当避免这种不正常的情况,因为遇到了参数太大,超过了int的取值范围就会拉闸。

5.7 示例程序

5.8 关键概念

5.9 本章小结

只需要一个运算对象的运算符称为一元运算符,需要两个运算对象的运算符称为二元运算符。

5.10 复习题

猜你喜欢

转载自blog.csdn.net/qq_44880154/article/details/115104730
今日推荐