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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_24990189/article/details/90018060

关键字:while、typedef

运算符:=、-、*、/、%、++、--、(类型名)

C语言的各种运算符,包括用于普通数学运算的运算符

运算符优先级以及语句、表达式的含义

while循环

复合语句、自动类型转换和强制类型转换

如何编写带有参数的函数

 

目录

5.1 循环简介

5.2 基本运算符(operator)

5.2.1 赋值运算符:=

5.2.2 加法运算符:+

5.2.3 减法运算符:-

5.2.4 符号运算符:-和+

5.2.5 乘法运算符:*

5.2.6 除法运算符:/

5.2.7 运算符优先级

5.2.8 优先级和求值顺序

5.3 其他运算符

5.3.1 sizeof运算符和size_t类型

5.3.2 求模运算符:%

5.3.3 递增运算符:++

5.3.4 递减运算符:--

5.3.5 优先级

5.3.6 不要自作聪明

5.4 表达式和语句

5.4.1 表达式

5.4.2 语句

5.4.3 复合语句(块)

5.5 类型转换

5.6 带参数的函数

5.7 示例程序

5.8 关键概念

5.9 小结


5.1 循环简介

/* shoes2.c -- calculates foot lengths for several sizes */
#include <stdio.h>
#define ADJUST 7.31              // one kind of symbolic constant
int main(void)
{
    const double SCALE = 0.333;  // another kind of symbolic constant
    double shoe, foot;
    
    printf("Shoe size (men's)    foot length\n");
    shoe = 3.0;
    while (shoe < 18.5)      /* starting the while loop */
    {                        /* start of block          */
        foot = SCALE * shoe + ADJUST;
        printf("%10.1f %15.2f inches\n", shoe, foot);
        shoe = shoe + 1.0;
    }                        /* end of block            */
    printf("If the shoe fits, wear it.\n");
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang shoes2.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
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.30 inches
      16.0           12.64 inches
      17.0           12.97 inches
      18.0           13.30 inches
If the shoe fits, wear it.

5.2 基本运算符(operator)

5.2.1 赋值运算符:=

术语:数据对象、左值、右值。

赋值表达式语句的目的是把值存储到内存位置上,用于存储值的数据存储区域统称为数据对象(data object),C标准只有这个地方是提到对象这个术语。使用变量名是标识对象的一种方法,除此之外,还有指定数组的元素、结构的成员、指针表达式(所指对象的地址)等等。

左值(lvalue)是用于标识或定位特定数据对象存储位置的标签,可修改的左值(modifiable lvalue),用于标识可修改的对象 = 对象定位值(object locator value)。

右值(rvalue)是能赋值给可修改左值的量,且本身不是左值。

int ex;
int why;
int zee; //可修改的左值(对象定位值)
const int TWO = 2;//不可修改的左值,但是可初始化
why = 32; //32是右值,不能引用某指定内存位置
zee = why; //可修改的左值
ex = TWO * (why + zee);//表达式是右值,不能表示特定内存位置,而且也不能给它赋值。
/* golf.c -- golf tournament scorecard */
#include <stdio.h>
int main(void)
{
    int jane, tarzan, cheeta;
    
    cheeta = tarzan = jane = 68;//C语言允许三重赋值
    printf("                  cheeta   tarzan    jane\n");
    printf("First round score %4d %8d %8d\n",cheeta,tarzan,jane);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang golf.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
                  cheeta   tarzan    jane
First round score   68       68       68

5.2.2 加法运算符:+

income = salary + bribes;
都是可修改的左值,因为每个变量都标识了一个可被赋值的数据对象。但是表达式是一个右值。

5.2.3 减法运算符:-

+ - 都是二元运算符(binary operator),需要两个运算对象才能完成操作。

5.2.4 符号运算符:-和+

5.2.5 乘法运算符:*

/* wheat.c -- exponential growth 指数增长*/
#include <stdio.h>
#define SQUARES 64             // squares on a checkerboard
int main(void)
{
    const double CROP = 2E16;  // world wheat production in wheat grains
    double current, total;
    int count = 1;
    
    printf("square     grains       total     ");
    printf("fraction of \n");
    printf("           added        grains    ");
    printf("world total\n");
    total = current = 1.0; /* start with one grain   */
    printf("%4d %13.2e %12.2e %12.2e\n", count, current,
           total, total/CROP);
    while (count < SQUARES)
    {
        count = count + 1;
        current = 2.0 * current;
        /* double grains on next square */
        total = total + current;     /* update total */
        printf("%4d %13.2e %12.2e %12.2e\n", count, current,
               total, total/CROP);
    }
    printf("That's all.\n");
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang wheat.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
square     grains       total     fraction of 
           added        grains    world total
   1      1.00e+00     1.00e+00     5.00e-17
   2      2.00e+00     3.00e+00     1.50e-16
   3      4.00e+00     7.00e+00     3.50e-16
   4      8.00e+00     1.50e+01     7.50e-16
   5      1.60e+01     3.10e+01     1.55e-15
   6      3.20e+01     6.30e+01     3.15e-15
   7      6.40e+01     1.27e+02     6.35e-15
   8      1.28e+02     2.55e+02     1.27e-14

5.2.6 除法运算符:/

/* divide.c -- divisions we have known */
#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("floating division: 7./4. is %1.2f \n", 7./4.);
    printf("mixed division:    7./4  is %1.2f \n", 7./4);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
integer division:  5/4   is 1 //整数截断
integer division:  6/3   is 2 
integer division:  7/4   is 1 
floating division: 7./4. is 1.75 
mixed division:    7./4  is 1.75 

5.2.7 运算符优先级

表达式树(expression tree)

5.2.8 优先级和求值顺序

注意正号(加号)和负号(减号)的两种不同用法

5.3 其他运算符

C语言大概有40个运算符

5.3.1 sizeof运算符和size_t类型

sizeof运算符以字节为单位返回运算对象的大小,C语言规定,sizeof返回size_t类型的值,这是一个无符号的整数类型,不是信类型。即C头文件系统使用typedef把size_t作为unsigned int或unsigned long的别名。这样,在使用size_t类型时,编译器会根据不同的系统类型替换标准类型。

C99进一步调整,%zd转换说明用于printf()显示size_t类型的值。

// sizeof.c -- uses sizeof operator
// uses C99 %z modifier -- try %u or %lu if you lack %zd
#include <stdio.h>
int main(void)
{
    int n = 0;
    size_t intsize;
    
    intsize = sizeof (int);
    printf("n = %d, n has %zd bytes; all ints have %zd bytes.\n",
           n, sizeof n, intsize );
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang sizeof.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
n = 0, n has 4 bytes; all ints have 4 bytes.

5.3.2 求模运算符:%

求模运算符(modulus operator)用于整数运算,即左侧整数除以右侧整数的余数(remainder)。

// min_sec.c -- converts seconds to minutes and seconds
#include <stdio.h>
#define SEC_PER_MIN 60            // seconds in a minute
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");
    scanf("%d", &sec);            // read number of seconds
    while (sec > 0)
    {
        min = sec / SEC_PER_MIN;  // truncated number of minutes截断分钟数
        left = sec % SEC_PER_MIN; // number of seconds left over剩下的秒数
        printf("%d seconds is %d minutes, %d seconds.\n", sec,
               min, left);
        printf("Enter next value (<=0 to quit):\n");
        scanf("%d", &sec);
    }
    printf("Done!\n");
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang min_sec.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
Convert seconds to minutes and seconds!
Enter the number of seconds (<=0 to quit):
154 
154 seconds is 2 minutes, 34 seconds.
Enter next value (<=0 to quit):
567
567 seconds is 9 minutes, 27 seconds.
Enter next value (<=0 to quit):
0
Done!

5.3.3 递增运算符:++

递增运算符(increment operator),两种方式,前缀模式(++出现在变量前面)、后缀模式(++出现在变量后面)区别在于递增行为发生的时间不同。

    while (shoe < 18.5)      /* starting the while loop */
    {                        /* start of block          */
        foot = SCALE * shoe + ADJUST;
        printf("%10.1f %15.2f inches\n", shoe, foot);
        shoe = shoe + 1.0;
    }                        /* end of block            */

    while (++shoe < 18.5)      /* starting the while loop */
    {                        /* start of block          */
        foot = SCALE * shoe + ADJUST;
        printf("%10.1f %15.2f inches\n", shoe, foot);
    }                        /* end of block            */

把控制循环的过程集中在一个地方,但降低了代码的可读性。

其次,递增运算符生成的机器语言代码效率更高。

/* post_pre.c -- postfix vs prefix */
#include <stdio.h>
int main(void)
{
    int a = 1, b = 1;
    int a_post, pre_b;
    
    a_post = a++;  //使用a的值之后,递增a
    pre_b = ++b;   //使用b的值之前,递增b
    printf("a  a_post   b   pre_b \n");
    printf("%1d %5d %5d %5d\n", a, a_post, b, pre_b);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
a  a_post   b   pre_b 
2     1     2     2

5.3.4 递减运算符:--

#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 down and pass it around,\n");
        printf("%d bottles of spring water!\n\n", count - 1);
    }
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang bottles.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
100 bottles of spring water on the wall, 100 bottles of spring water!
Take one down and pass it around,
99 bottles of spring water!

99 bottles of spring water on the wall, 99 bottles of spring water!
Take one down and pass it around,
98 bottles of spring water!

1 bottles of spring water on the wall, 1 bottles of spring water!
Take one down and pass it around,
0 bottles of spring water!

5.3.5 优先级

递增和递减运算符只能影响一个变量(只能影响一个可修改的左值)

5.3.6 不要自作聪明

在c语言中,编译器可以自行选择现对函数中的哪个参数求值,这样做提高了编译器的效率,但是如果在函数的参数中使用了递增运算符会出现很多问题,

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

如果一个变量多次出现在在一个表达式中,同上

  while (num < 21)
    {
        printf("%4d %6d\n", num, num * num);
        num = num + 1;
    }
    

wlsh@wlsh-MacbookPro] ch05$ clang squares.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
   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
    while (num < 21)
    {
        printf("%4d %6d\n", num, num * num++);
    }
    
[wlsh@wlsh-MacbookPro] ch05$ clang squares.c 
squares.c:9:43: warning: unsequenced modification and access to 'num' [-Wunsequenced]
        printf("%4d %6d\n", num, num * num++);
                            ~~~           ^
1 warning generated.

5.4 表达式和语句

5.4.1 表达式

表达式(expression)由运算符和运算对象组成,由子表达式(subexpression)组成。但是每个表达式都有一个值。

5.4.2 语句

语句(statement)是C程序的基本构成块,一条语句相当于一条完整的计算机指令。

声明创建了名称和类型,并为其分配内存位置。声明不是一个表达式语句。

/* addemup.c -- five kinds of statements */
#include <stdio.h>
int main(void)                /* finds sum of first 20 integers */
{
    int count, sum;           /* declaration statement声明          */
    
    count = 0;                /* assignment statement           */
    sum = 0;                  /* ditto表达式语句                          */
    while (count++ < 20)      /* while迭代语句                          */
        sum = sum + count;    /*     statement                  */
    printf("sum = %d\n", sum);/* function statement表达式语句             */
    
    return 0;                 /* return statement跳转语句               */
}

副作用(side effect)是对数据对象或文件的修改。

序列点(sequence point)是程序执行的点,在该点上,所有的副作用都在进入下一步之前发生。语句的分号标记一个序列点,意思是,在一个语句中,赋值运算符、递增减运算符对运算对象做的改变必须在程序执行下一条语句之前完成。

    int a = 0;
    while (a++ < 10)//序列点,保证程序转至执行printf()之前发生副作用。同时,后缀形式保证了a在完成与10的比较后才进行递增。
    {
        printf("%d\n",a);
    }
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
1
2
3
4
5
6
7
8
9
10

  int a = 0;
    while (++a < 10)
    {
        printf("%d\n",a);
    }
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
1
2
3
4
5
6
7
8
9

5.4.3 复合语句(块)

5.5 类型转换

1.升级(promotion),无论是unsigned还是signed的char和short都会自动转换成int,如有必要会转换成unsigned int。

2.涉及两种类型的运算时,两个值会被分别转换成两种类型的更高级别。

类型级别long double、doubloe 、f'loat、unsignedlong long、long long、unsigned long、long、unsigned int、int

3.当作为函数参数传递时,char和short被转换成int,float转换成double。

4.在赋值表达式语句中,计算的最终结果会被转换成被赋值变量的类型。

/* convert.c -- automatic type conversions */
#include <stdio.h>
int main(void)
{
    char ch;
    int i;
    float fl;
    
    fl = i = ch = 'C';                                  /* line 9  */
    printf("ch = %c, i = %d, fl = %2.2f\n", ch, i, fl); /* line 10 */
    ch = ch + 1;                                        /* line 11 */
    i = fl + 2 * ch;                                    /* line 12 */
    fl = 2.0 * ch + i;                                  /* line 13 */
    printf("ch = %c, i = %d, fl = %2.2f\n", ch, i, fl); /* line 14 */
    ch = 1107;                                          /* line 15 */
    printf("Now ch = %c\n", ch);                        /* line 16 */
    ch = 80.89;                                         /* line 17 */
    printf("Now ch = %c\n", ch);                        /* line 18 */
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ clang convert.c 
convert.c:17:10: warning: implicit conversion from 'double' to 'char' changes value from 80.89 to 80 [-Wliteral-conversion]
    ch = 80.89;                                         /* line 17 */
       ~ ^~~~~
convert.c:15:10: warning: implicit conversion from 'int' to 'char' changes value from 1107 to 83 [-Wconstant-conversion]
    ch = 1107;                                          /* line 15 */
       ~ ^~~~
2 warnings generated.

ch = C, i = 67, f1 = 67.00
ch = D, i = 203, f1 = 339.00
Now ch = S
Now ch = P

字符‘c’被作为1字节的ASCII值存储在ch中,整数变量 i 接受由‘C’转换的整数,即按4字节存储67。最后f1接受由67转换的浮点数67.00

字符变量‘C’转换成整数67,然后加1,结果4字节整数68,被截断成1字节存存储在ch中,被解释成‘D’的ASCII码。

然后,为了与f1相加,136转换成浮点数,计算结果(203.00f)转换成int类型,并存储在i中。

再然后,ch的值(68)转换成浮点数,然后2 * ch,为了做加法,i的值(203)转换成浮点类型,计算结果也存储在f1中。

类型降级的示例,把ch设置为一个超出其范围的值,忽略额外的位后,最终ch的值是字符S的ASCII码,确切的说是 1107 % 265 = 83

类型降级的示例,把ch设置位一个浮点数,截断后是字符P的ACSII码。

mice = 1.6 + 1.7
mice = (int)1.6 + (int)1.7

第1行,相加得3.3,为了匹配int类型,3.3被截断为整数3

第2行,相加之前都被转换成整数1,在赋值给mice

5.6 带参数的函数

/* pound.c -- defines a function with an argument   */
#include <stdio.h>
void pound(int n);   // ANSI function prototype declaration
int main(void)
{
    int times = 5;
    char ch = '!';   // ASCII code is 33
    float f = 6.0f;
    
    pound(times);    // int argument
    pound(ch);       // same as pound((int)ch);
//char与int不匹配,开头的原型(prototype)即函数的声明发挥了作用,描述函数的返回值和参数,
//函数声明告诉编译器pound()需要一个int类型的参数。
    pound(f);        // same as pound((int)f);
    
    return 0;
}

void pound(int n)    // ANSI-style function header
{                    // says takes one int argument
    while (n-- > 0)
        printf("#");
    printf("\n");
}
[wlsh@wlsh-MacbookPro] ch05$ clang pound.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
#####
#################################
######

声明创建形式参数(formal argument 或 fromal parameter),函数调用传递的值为实际参数(actual argumeter 或 actual parameter)。

注意:ANSI C之前是函数声明,pound(ch)也没问题,因为即使缺少函数原型,C也会把char和short类型自动升级为int类型。但是pound(f)会失败,因为缺少函数原型,float会被自动升级为double,输出的内容不正确。如下 直接没有了输出

void pound();//函数声明

[wlsh@wlsh-MacbookPro] ch05$ clang pound.c 
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
#####
#################################

5.7 示例程序

// running.c -- A useful program for runners
#include <stdio.h>
const int S_PER_M = 60;         // seconds in a minute
const int S_PER_H = 3600;       // seconds in an hour
const double M_PER_K = 0.62137; // miles in a kilometer
int main(void)
{
    double distk, distm;  // distance run in km and in miles
    double rate;          // average speed in mph
    int min, sec;         // minutes and seconds of running time
    int time;             // running time in seconds only
    double mtime;         // time in seconds for one mile
    int mmin, msec;       // minutes and seconds for one mile
    
    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);  // %lf for type double
    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);
    // converts time to pure seconds
    time = S_PER_M * min + sec;
    // converts kilometers to miles
    distm = M_PER_K * distk;
    // miles per sec x sec per hour = mph
    rate = distm / time * S_PER_H;
    // time/distance = time per mile
    mtime = (double) time / distm;
    mmin = (int) mtime / S_PER_M; // find whole minutes
    msec = (int) mtime % S_PER_M; // find remaining seconds
    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 a mile in %d min, ",
           mmin);
    printf("%d sec.\nYour average speed was %1.2f mph.\n",msec,
           rate);
    
    return 0;
}
[wlsh@wlsh-MacbookPro] ch05$ ./a.out 
This program converts your time for a metric race
to a time for running a mile and to your average
speed in miles per hour.
Please enter, in kilometers, the distance run.
10.0
Next enter the time in minutes and seconds.
Begin by entering the minutes.
36
Now enter the seconds.

23
You ran 10.00 km (6.21 miles) in 36 min, 23 sec.
That pace corresponds to running a mile in 5 min, 51 sec.
Your average speed was 10.25 mph.

5.8 关键概念

5.9 小结

猜你喜欢

转载自blog.csdn.net/qq_24990189/article/details/90018060
今日推荐