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

发布于 2021-04-11  84 次阅读


此章学习如何处理数据

5.1 循环简介

//  sjoes1.c    --把鞋码转换成英寸
#include<stdio.h>
#define ADJUST 7.31
int main(void)
{
    const double SCALE = 0.333;
    double shoe,foot;

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

    return 0;
}

file
拓展while改写

//  shoes2.c    --计算多个不同鞋码对应的脚长
#include<stdio.h>
#define ADJUST 7.31
int main(void)
{
    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.f %15.2f inches\n",shoe,foot);
        shoe = shoe +1.0;
    }
    printf("IF the shoe fits,wear it.\n");

    return 0;
}

file

原理简述:当程序第一次到达while循环时,会检查圆括号内的条件是否为真。为真进入块中继续执行,执行完块以后返回while入口检查条件,以此往复执行。为假,则跳出块继续向下执行。

5.2 基本运算符

C用运算符(operator)表示算术运算。基本运算符:=、+、-、*、/.(C语言没有指数运算符。不过C的标准数学库提供了一个pow(a,b)函数用于指数运算)

5.2.1 赋值运算符:=

在C语言中,=不意味着相等,而是一个赋值运算
bmw = 2020;
把值2020赋给变量bmw。C使用可修改的左值(modifiable lvalue)标记那些可赋值的实体。

几个术语:数据对象、左值、右值和运算符

赋值表达式语句的目的是把值存储到内存位置上。用于存储值的数据存储区域统称为 数据对象(data object)
左值(lvalue)是C语言的术语,用于标识特定数据对象的名称或表达式。对象指的是实际的存储对象,而左值是用于标识或定位存储位置的标签。
由于const限定符的出现,C标准新增加了“可修改的左值(modifiable lvalue)”
右值(rvalue)or表达式的值(value of an expression)
“吃”运算符操作“汉堡”运算对象。类似的说=运算符的左侧运算对象应该是可修改的左值。

//  golf.c  --高尔夫竞标赛记分卡
#include<stdio.h>
int main(void)
{
    int jane,tarzan,cheeta;

    cheeta = tarzan = jane = 68;
    printf("                           cheet tarzan   jane\n");
    printf("First round score %4d %8d %8d\n",cheeta,tarzan,jane);

    return 0;
}

file
C多重赋值是没右问题的。

5.2.2 加法运算符(addition operator):+

相加的对象(运算对象)可以是常量也可以是变量。
icome = salary + bribes;
中,income、salary和bribes都是可修改的左值。因为每个变量都标识了一个可被赋值的数据对象。但是,表达式salary+bribes是一个右值。

5.2.3 减法运算符(subtraction operator):-

+和-运算符都很成为二元运算符(binary operator),即这些运算符需要两个运算对象才能完成操作。

5.2.4 符号运算符:-和+

一元运算符(unary operator),顾名思义,一个运算对象。
file

5.2.5 乘法运算符

//  squares.c   --计算1~20的平方
#include<stdio.h>
int main(void)
{
    int i;

    i=1;

    while(i<21){
    printf("%d^2=%d\n",i,i*i);
    i++;
    }

    return 0;
}

1. 指数增长

//  wheat.c --国王智者小麦棋盘故事
#include<stdio.h>
#define SQUARES 64      //棋盘中的方格数
int main(void)
{
    const double CROP = 2E16;   //世界小麦年产谷粒
    double current,total;
    int count = 1;

    printf("squra  grains  total   ");
    printf("fraction of \n");
    printf("word total\n");
    total = current =1.0;       //从第一个谷粒开始
    printf("%4d %13.2e %12.2e %12.2e\n",count,current,total,total/CROP);
    while(count < SQUARES)
    {
        count = count+1;
        current = 2.0*current;
        total = total + current;
        printf("%4d %13.2e %12.2e %12.2e\n",count,current,total,total/CROP);
    }
    printf("That's all.\n");

    return 0;
}

选取部分截图
file

5.2.6 除法运算符:/

整数类型的数相除会发生截断(truncation)

//  divide.c    --演示除法
#include<stdio.h>
int main(void)
{
    printf("integer division:5/4 is %d \n",5/4);
    printf("integer division:6/3 is %d \n",6/3);
    printf("integer division:7/4 is %d \n",7/4);
    printf("integer division:7./4. is %d \n",7./4.);
    printf("integer division:7./4 is %d \n",7./4);

    return 0;
}

file

5.2.7 运算符优先级

file
file

5.2.8 优先级和求值顺序

//  rules.c     --优先级测试
#include<stdio.h>
int main()
{
    int top;

    top=score=-(2+5)*6+(4+3*(2+3));
    pritnf("top=%d,score=%d\n",top,score);

    return 0;
}

file

5.3 其他运算符

5.3.1 sizeof运算符和size_t类型

//  sizeof.c    --使用sizeof运算符
//  使用C99新增的%zd转换说明 --如果编译器不支持%zd,改为%u或者%lu
#include<stdio.h>
int main(void)
{
    int n = 0;
    size_t intsize;

    intsize = sizeof(int);
    printf("n= %d,n has %u bytes;all ints have %u bytes.\n",
            n,sizeof n,intsize);

    return 0;
}

file

typedef double real;
real就是double的别名。

5.3.2 求模运算符(modulus operator):%

求模运算给出其左侧整数除以右侧整数的余数(remainder)。
求模运算只能运于整数,不能运用于浮点数

//  min_see.c   --把秒数转换成分和秒
#include<stdio.h>
#define SEC_PER_MIN 60
int main(void)
{
    int sec,min,left;

    printf("Convert seconds to minutes and seconds!\n");
    printf("Enter the number of seconds(<=0 to quit):\n\n");
    scanf("%d",&sec);     //读取秒数
    while(sec>0)
    {
    min = sec / SEC_PER_MIN;        //截断的分钟
    left = sec % SEC_PER_MIN;       //剩下的秒数
    printf("%d seconds is %d minutes,%d seconds.\n",sec,min,left);
    printf("Enter next value(<= to quit):\n");
    scanf("%d",&sec);
    }
    printf("Done!\n");

    return 0;
}

file
a-(a/b)*b来计算a%b.

5.3.3 递增运算符(increment operator):++

前缀模式:++i
后缀模式:i++

//      add_one.c   --递增:前缀和后缀
#include<stdio.h>
int main(void)
{
    int ultra = 0, super = 0;

    while(super < 5)
    {
    super ++;
    ++ultra;
    printf("super = %d,ultra = %d \n",super,ultra);
    }

    return 0;
}

file
借用鞋子的例子可以这样子改写程序:
file
但是如果写成shoe++的话会导致多一个19,因为shoe++会先比较之后再++
区别:

//  post_pre,c      //--前缀和后缀
#include<stdio.h>
int main(void)
{
    int a = 1,b = 1;
    int a_post,pre_b;

    a_post = a++;
    pre_b = ++a;
    printf("a  a_post  b   pre_b \n");
    printf("%ld %5d %5d %5d\n",a,a_post,b,pre_b);

    return 0;
}

file
前缀先加后进行其他运算,而后缀是先进行其他运算再加。

b=i++;  //使用i++会导致别的结果
//尽量这样子写
++i;
b = i;

5.3.4 递减运算符(decrement operator):--

--count; //前缀形式
count++; //后缀形式

//  bottles.c
#include<stdio.h>
#define MAX 100
int main(void)
{
    int count = MAX+1;

    while(--count > 0){
    printf("%d bottles of spring water on the wall,"
    "%d bottles of spring water!\n",count,count);
    printf("Take one dowm and pass it around,\n");
    printf("%d bottles of spring water!\n\n",count-1);
    }

    return 0;
}

file
...
file
关系运算符(><)(relational operator)

5.3 优先级

如果n++是表达式的一部分, 可以将其视为“先使用n,再递增”;而++n则表示“先递增n,再使用”。

5.3.6 不要自作聪明

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

5.4 表达式和语句

术语表达式(expression)和语句(statement

5.4.1 表达式

表达式由运算符和运算对象组成。最简单的表达式是一个单独的运算对象。如:

4
-6
4+21
a*(b+c/d)/20
q=5*2
x=++q%3
q>3
表达式q=5*2作为一个整体的值是10.
q>3的值是?不是1就是0.条件为真则为1,条件为假则为0
file

5.4.2 语句

一条语句相当于一条完整的计算机指令。因此:

legs = 4

只是一个表达式而

legs = 4:
//为一条语句
//最简单的空语句
;
//在末尾加上分号的表达式都可以看作一个语句。
//更确切的说,语句可以改变值或调用函数
x = 6+(y=5);
//y = 5是一条完整的指令,但她只是语句的一部分。完整的指令不一定是一条语句。
//  addemup.c   --几种常见的语句
#include<stdio.h>
int main(void)      //计算前20个整数的和
{
    int count,sum;  //声明(在C语言中,声明不是语句,与C++不同)

    count = 0;      //表达式语句
    sum = 0;       //表达式语句
    while(count++<20)    //迭代语句
    {
        sum=sum+count;  
        printf("sum=%d\n",sum);       //表达式语句
    }
    return 0;       //跳转语句
}

file
声明语句删除分号不是表达式。
如果while语句中只有一个语句,那可以不用花括号。

副作用(side effict)和序列点(sequence point

副作用是对数据对象和文件的修改。
序列点是程序执行的点。
在C语言中,语句中的分号标记了一个序列点。(在一个语句中,赋值运算符、递增运算符和递减运算符对运算对象做的改变必须在程序执行下一条语句之前完成)

5.4.3 复合语句块

复合语句(compound statement)是用花括号括起来的一条或多条语句,复合块也称为块(block)。
file
另外一种风格的括号写法

    while(index++<10){
        sam = 10*index +2;
        printf("sam = %d\n",sum);
    }

总结
表达式:表达式由运算符和运算对象组成。
语句:简单语句和复合语句

5.5 类型转换

1.升级(从较小类型转换为较大类型)
2.设计到两种类型的运算,两个值会被分别转换成两种类型的更高级别
3.类型的级别从高到低:long double、double、float、unsigned long long、long long、unsigned long、long、unsigned int、int
4.在赋值表达式语句中,计算的最终结果会被转换成被赋值变量的类型。
5.在作为函数参数传递时,char 和 short被转换成int,float 被转换成了double
file

//  convert.c   --自动类型转换
#include<stdio.h>
int main(void)
{
    char ch;
    int i;
    float f1;

    f1 = i = ch = 'C';
    printf("ch = %c,i = %d,f1 = %2.2f\n",ch.i.f1);
    ch=ch+1;
    i=f1+2*ch;
    f1=2.0*ch+i;
    printf("ch = %c,i = %d,f1 = %2.2f\n",ch.i.f1);
    ch=1107;
    printf("Now ch = %c\n",ch);
    ch=80.89;
    printf("Now ch = %c\n",ch);

    return 0;
}

5.5.1 强制类型转(cast)换运算符(cast operator)

通用形式:
(type)
用实际需要的,(long)替换type即可。
如:

int mice;
mice = 1.6+1.7;             //自动类型转换,3.3转换为int为3
mice = (int)1.6+(int)1.6;   //强制类型转换1+1=2;

其他运算符。。
sizeof
(type)9..

5.6 带参数的函数

#include<stdio.h>
void butler(void);
int main(void)
{
    ..;
    vultle();
    ..;
}
void butler(void)
{
    ...;
}
//  pound.c --定义一个带参数的函数
#include<stdio.h>
void pound(int n);
int main(void)
{
    int times = 5;
    char ch = '!';
    float f = 6.0f;

    pound(times);
    pound(ch);
    pound(f);

    return 0;
}

void pound(int n)
{
    while(n-->0)
        printf("#");
    printf("\n");
}

file
函数不接受任何参数,函数头的圆括号应该写上关键字void。
由于该函数接受一个int类型的参数,所以圆括号中包含一个int类型变量n的声明。
声明变量就创造了被称为形式参数(formal argument 或formal parameter,简称形参)的变量。
该例子中形参为int类型的n。pount(10)函数会把10赋给n。
称函数调用传递的值为实际参数(actual argument或者actual parameter),实参。
把实际参数10传递给函数,该函数把10赋给形式参数(变量n)。
也就是,main()中的变量times的值被拷贝给pound()中的新变量n。

5.7 示例程序

//  running.c   --A useful program for runners
#include<stdio.h>
const int S_PER_M = 60;                 //1分钟的秒数
const int S_PER_H = 3600;               //1小时的描述秒数
const double M_PER_K = 0.62137;         //一公里的英里数
int main(void)
{
    double distk,distm;                 //跑过的距离
    double rate;                        //速度
    int min,sec;
    int time;
    double mtime;
    int mmint,msec;

    printf("This program converts your time for a metric race\n");
    printf("to a time for running a mile and to your average\n");
    printf("speed in miles per hour.\n");
    printf("Please ENTER,in kilometers,the distance run.\n");
    scanf("%lf",&distk);
    printf("Next enter the time in minutes and seconds.\n");
    printf("Begin by entering the minutes.\n");
    scanf("%d",&min);
    printf("Now enter the seconds.\n");
    scanf("%d",&sec);

    time = S_PER_M*min+sec;
    distm = M_PER_K *distk;
    rate = distm / time* S_PER_H;
    mtime = (double)time /distm;
    mmint = (int)mtime/distm;
    msec = (int)mtime%S_PER_M;

    printf("You ran %1.2f km (%1.2f miles) in %d min,%d sec.\n",distk,distm,min,sec);
    printf("That pace corresponds to running amile in %d min,",mmint);
    printf("%d sec.\n your average speed was %1.2f mph.\n",msec,rate);

    return 0;
}

file

file

file


擦肩而过的概率