C Primer Plus 第五章运算符、表达式和语句学习笔记

小结

 C 通过运算符提供多种操作。每个运算符的特性包括运算对象的数量优先级结合律。当两个运算符共享一个运算对象时,优先级和结合律决定了先进行哪项运算(先进行优先级高的运算。
如果运算符的优先级相等,由结合律(从左往右或从右往左)决定求值顺序。)。表达式由运算符和运算对象组成(每个 C表达式都有一个值,包括赋值表达式和比较表达式)。如果不了解运算符的优先级和结合律,写出的表达式可能不合法或者表达式的值与预期不符。

本章讨论的赋值运算符算术运算符。一般而言,运算符需要一个或多个运算对象才能完成运算生成一个值。只需要一个运算对象的运算符(如负号和 sizeof)称为一元运算符,需要两个运算对象
的运算符(如加法运算符和乘法运算符)称为二元运算符

在C语言中,=并不意味着“相等”,而是一个赋值运算符。

用花括号括起来的一条或多条语句构成了复合语句(或称为块)while语句是一种迭代语句,只要测试条件为真,就重复执行循环体中的语句。

虽然C允许编写混合数值类型的表达式,但是算术运算要求运算对象都是相同的类型。因此,C会进行自动类型转换(当char和short类型出现在表达式里或作为函数的参数(函数原型除外)时,都会被升级为int类型;float类型在函数参数中时,会被升级为double类型。)。尽管如此,不要养成依赖自动类型转换的习惯,应该显式选择合适的类型或使用强制类型转换。这样,就不用担心出现不必要的自动类型转换。有时需要进行精确的类型转换,或者在程序中表明类型转换的意图。这种情况下要用到强制类型转换(cast),即在某个量的前面放置用圆括号括起来的类型名,该类型名即是希望转换成的目标类型。圆括号和它括起来的类型名构成了强制类型转换运算符(cast operator)

下面两行代码,其中mice是int类型的变量。第2行包含两次int强制类型转换。

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

第1 行使用自动类型转换。首先,1.6和1.7相加得3.3。然后,为了匹配int 类型的变量,3.3被类型转换截断为整数3。第2行,1.6和1.7在相加之前都被转换成整数(1),所以把1+1的和赋给变量mice。本质上,两种类型转换都好不到哪里去,要考虑程序的具体情况再做取舍。

定义带一个参数的函数时,便在函数定义中声明了一个变量,或称为形式参数。然后,在函数调用中传入的值会被赋给这个变量。这样,在函数中就可以使用该值了。

复习题

1.假设所有变量的类型都是int,下列各项变量的值是多少:
a.x = (2 + 3) * 6;
b.x = (12 + 6)/2*3;
c.y = x = (2 + 3)/4;
d.y = 3 + 2*(x = 7/2);

a. 30

b.27

c. x=1,y=1

d. x=3,y=9

2.假设所有变量的类型都是int,下列各项变量的值是多少:
a.x = (int)3.8 + 3.3;
b.x = (2 + 3) * 10.5;
c.x = 3 / 5 * 22.0;
d.x = 22.0 * 3 / 5;

a.6

b.52

c.0

d.13

3.对下列各表达式求值:
a.30.0 / 4.0 * 5.0;
b.30.0 / (4.0 * 5.0);
c.30 / 4 * 5;
d.30 * 5 / 4;
e.30 / 4.0 * 5;
f.30 / 4 * 5.0;

a.37.5(7.5*5.0的结果)

b.1.5(30.0/20.0的结果)

c.35(7*5的结果)

d.37(150/4的结果)

e.37.5(7.5*5的结果)

f. 35.0(7*5.0的结果)

4.请找出下面的程序中的错误。

int main(void)
{
    int i = 1,
    float n;
    printf("Watch out! Here come a bunch of fractions!\n");
    while (i < 30)
    n = 1/i;
    printf(" %f", n);
    printf("That's all, folks!\n");
    return;
}
/*
第0行:应增加一行#include <stdio.h>。
第3行:末尾用分号,而不是逗号。
第6行:while语句创建了一个无限循环。因为i的值始终为 1,所以它总是小于 30。推测一下,
应该是想写while(i++ < 30)。
第 6~8行:这样的缩进布局不能使第7行和第8行组成一个代码块。由于没有用花括号括起来,while循环只包括第7行,所以要添加花括号。
第7行:因为1和i都是整数,所以当i为1时,除法的结果是1:当i为更大的数时,除法结果为0。用n=1.0/1,i在除法运算之前会被转换为浮点数,这样就能得到非零值。
第8行:在格式化字符串中没有换行符(n),这导致数字被打印成一行。
第10行:应该是return 0;
下面是正确的程序:
*/
#include <stdio.h>
int main(void)
{
    int i = 1;
    float n;
    printf("Watch out! Here come a bunch of fractions!\n");
    while(i++ < 30)
    {
        n = 1.0/i;
        printf(" %f\n",n);
    } 
    printf("That's all, folks!\n");
    return 0;
}

5.这是程序清单 5.9 的另一个版本。从表面上看,该程序只使用了一条scanf()语句,比程序清单5.9简单。请找出不如原版之处。

#include<stdio.h>
#define SEC_PER_MIN 60
int main(void)
{
	int sec, min, left;
	printf("This program converts seconds to minutes and ");
	printf("seconds.\n");
	printf("Just enter the number of seconds.\n");
	printf("Enter 0 to end the program.\n");
	while (sec > 0)
	{
		scanf("%d", &sec);
		min = sec/SEC_PER_MIN;
		left=sec%SEC_PER_MIN;
		printf("%d seconds is %d minutes, %d seconds.\n", sec,
               min, left);
		printf("Next input?\n");
	}
	printf("Bye!\n");
	return 0;
}

这个版本最大的问题是测试条件(sec是否大于0?)和scanf()语句获取 sec 变量的值之间的关系。具体地说,第一次测试时,程序尚未获得sec的值,用来与0作比较的是正好在sec 变量内存位置上的一个垃圾值。一个比较笨拙的方法是初始化sec(如,初始化为1)。这样就可通过第一次测试。不过,还有另一个问题。当最后输入0结束程序时,在循环结束之前不会检查sec,所以0也被打印了出来。因此,更好的方法是在while测试之前使用scanf()语句。

while循环第一轮迭代使用的是 scanf()在循环外面获取的值。因此,在 while 循环的末尾还要使用一次 scanf()语句。这是处理类似问题的常用方法。

// 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;
}

6.下面的程序将打印出什么内容?

#include <stdio.h>
#define FORMAT "%s! C is cool!\n"
int main(void)
{
	int num = 10;
	printf(FORMAT,FORMAT);
	printf("%d\n", ++num);
	printf("%d\n", num++);
	printf("%d\n", num--);
	printf("%d\n", num);
	return 0;
}
%s! C is cool!
! C is cool!
11
11
12
11

解释一下。第1个printf()语句与下面的语句相同:

printf("号s!C is cool!\n","号s!C is cool!\n");

第 2个printf()语句首先把 num 递增为 11,然后打印该值。第3个printf()语句打印 num的值(值为 11)。第4个printf()语句打印n当前的值(仍为 12),然后将其递减为 11。最后一个printf()语句打印 num 的当前值(值为 11)。

7.下面的程序将打印出什么内容?

#include <stdio.h>
int main(void)
{
    char c1, c2;
    int diff;
    float num;
    c1 = 'S';
    c2 = 'O';
    diff = c1 - c2;
    num = diff;
    printf("%c%c%c:%d %3.2f\n", c1, c2, c1, diff, num);
    return 0;
}

SOS:4 4.00

表达式c1-c2的值和'S’-'0'的值相同(其对应的ASCII值是83 - 79)。

8.下面的程序将打印出什么内容?

#include <stdio.h>
#define TEN 10
int main(void)
{
    int n = 0;
    while(n++ < TEN)
    printf("%5d", n);
    printf("\n");
    return 0;
}

    1    2    3    4    5    6    7    8    9   10

把1~10 打印在一行,每个数字占5列宽度,然后开始新的一行

9.修改上一个程序,使其可以打印字母a~g。

#include <stdio.h>

int main(void)
{
    char ch = 'a';
    while(ch <= 'g')
    {
        printf("%5c",ch++);
    }
    printf("\n");
    return 0;
}

10.假设下面是完整程序中的一部分,它们分别打印什么?

a.
int x = 0;
while (++x < 3)
    printf("%4d", x);

b.
int x = 100;
while (x++ < 103)
    printf("%4d\n",x);
printf("%4d\n",x);

c.
char ch = 's';
while (ch < 'w')
{
    printf("%c", ch);
    ch++;
}
printf("%c\n",ch);

a.        1        2
(注意,先递增x的值再比较。光标仍留在同一行)。
b. 101
    102
    103

    104
(注意,这次x先比较后递增。在示例a和b中,x都是在先递增后打印。另外还要注意,第2 个 printf()语句不是 while 循环的一部分。因此,在 while 循环结束后,才会调用一次该printf()语句)。

c. stuvw
(该例中,在第1次调用printf()语句后才会递增ch)。

11.下面的程序会打印出什么?

#define MESG "COMPUTER BYTES DOG"
#include<stdio.h>
int main(void)
{
	int n = 0;
	while(n<5)
	printf("%s\n",MESG);
	n++;
	printf("That's all.\n");
	return 0;
}

这个程序有点问题。while循环没有用花括号把两个缩进的语句括起来,只有printf()是循环的一部分,所以该程序一直重复打印消息COMPUTERBYTESDOG,直到强行关闭程序为止。

12.分别编写一条语句,完成下列各任务(或者说,使其具有以下副作用):
a.将变量x的值增加10
b.将变量x的值增加1
c.将a与b之和的两倍赋给c
d.将a与b的两倍之和赋给c

x = x+10;

x++;or ++x;or x=x+1;

c=2*(a+b);

c=a+2*b;

13.分别编写一条语句,完成下列各任务:
a.将变量x的值减少1
b.将n除以k的余数赋给m
c.q除以b减去a,并将结果赋给p
d.a与b之和除以c与d的乘积,并将结果赋给x

x--;or --x;x=x-1;

m=n%k;

p=q/(b-a);

x=(a+b)/(c*d);

编程练习

1.编写一个程序,把用分钟表示的时间转换成用小时和分钟表示的时间。使用#define或const创建一个表示60的符号常量或const变量。通过while循环让用户重复输入值,直到用户输入小于或等于0的值才停止循环。

#include <stdio.h>
int main(void)
{
    const int minperhour = 60;
    int minutes, hours, mins;
    printf("Enter the number of minutes to convert: ");
    scanf("%d", &minutes);
    while (minutes > 0 )
    {
        hours = minutes / minperhour;
        mins = minutes % minperhour;
        printf("%d minutes = %d hours, %d minutes\n", minutes, hours, mins);
        printf("Enter next minutes value (0 to quit): ");
        scanf("%d", &minutes);
    }
    printf("Bye\n");
    return 0;
}

3.编写一个程序,提示用户输入天数,然后将其转换成周数和天数。例如,用户输入18,则转换成2周4天。以下面的格式显示结果:

18 days are 2 weeks, 4 days.
通过while循环让用户重复输入天数,当用户输入一个非正值时(如0或-20),循环结束。

#include <stdio.h>
int main(void)
{
	const int daysperweek = 7;
	int days, weeks, day_rem;
	printf("Enter the number of days: ");
	scanf("%d", &days);
	while (days > 0)
	{
		weeks = days / daysperweek;
		day_rem = days % daysperweek;
		printf("%d days are %d weeks and %d days.\n",
		days, weeks, day_rem);
		printf("Enter the number of days (0 or less to end): ");
		scanf("%d", &days);
	}
	printf("Done!\n");
	return 0;
}

5.修改程序addemup.c(程序清单5.13),你可以认为addemup.c是计算20天里赚多少钱的程序(假设第1天赚$1、第2天赚$2、第3天赚$3,以此类推)。修改程序,使其可以与用户交互,根据用户输入的数进行计算(即,用读入的一个变量来代替20)。

#include <stdio.h>
int main(void) /* finds sum of first n integers */
{
	int count, sum;
	int n;
	printf("Enter the upper limit: ");
	scanf("%d", &n);
	count = 0;
	sum = 0;
	while (count++ < n)
	sum = sum + count;
	printf("sum = %d\n", sum);
	return 0;
}

7.编写一个程序,提示用户输入一个double类型的数,并打印该数的立方值。自己设计一个函数计算并打印立方值。main()函数要把用户输入的值传递给该函数。

#include <stdio.h>
void showCube(double x);
int main(void) /* finds cube of entered number */
{
    double val;
    printf("Enter a floating-point value: ");
    scanf("%lf", &val);
    showCube(val);
    return 0;
}
void showCube(double x)
{
    printf("The cube of %e is %e.\n", x, x*x*x );
}

  • 20
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值