此部分运算符优先级记一记,记不了后面用到可以再来看,自增自减理解概念就好。比较重要的代码是基本算数运算中的的逆序后四位。(学会得到一个多位数的每一位)
一.基本算数运算
①(代码)勾股定理
任务描述:
勾股定理,是几何学中一颗光彩夺目的明珠,被称为“几何学的基石”。中国是发现和研究勾股定理最古老的国家之一。勾股定理是指直角三角形两直角边的平方和等于斜边的平方。如果用a、b和c分别表示直角三角形的两直角边和斜边,那么a²+b²=c²。若三个正整数a,b,c满足a²+b²=c²,则称a,b,c是勾股数。可以证明,对任意一个正整数n,设a=2n+1,b=2n(n+1),c=b+1,则a,b,c就是一组勾股数。
输入格式:
一个正整数n。
输出格式:
请按输出样例格式输出按题目中算法算出的一组勾股数。
输入样例:
1
输出样例:
(3,4,5)
输入样例:
3
输出样例:
(7,24,25)
#include<stdio.h>
int main()
{
int n, a, b, c;
scanf("%d", &n);
a = 2 * n + 1;
b = 2 * n * (n + 1);
c = b + 1;
printf("(%d,%d,%d)", a, b, c);
return 0;
}
代码分析
程序首先定义4个整型变量,然后输入变量n的值。接下来通过三个赋值语句分别计算a,b,c的值,最后按格式要求输出。程序中用到加法、乘法和括号,下面我们就一起来看看C语言中的运算符吧。
相关知识 运算符、表达式、优先级和结合性
1.运算符运算符是指表达操作数之间运算规则的符号。C语言的运算符包括算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、条件运算符、逗号运算符、指针运算符、求字节数运算符、强制类型转换运算符、分量运算符、下标运算符等多种类型。只需要一个操作对象的运算符(如!、++、--等)称为单目运算符;需要两个操作对象的运算符(如加号+、减号-)称为双目运算符;需要三个操作对象的运算符(如 ? : )称为三目运算符。2.表达式表达式是指用运算符将运算对象连接起来式子。运算对象包括常量、变量、函数等等。例如,表达式:a+b、a*b+c、3.1415926*r*r、(a+b)*c-10/d、sin(x)/cos(y)、a>=b、m+3<n-2、x>y&&y>z、a*b+6/c-1.2+'a'都是合法的表达式。特别的,15、3.1415926、x、(n)等也是合法的表达式。
C语言的运算符及优先级别和结合性见表2-3。
![](https://i-blog.csdnimg.cn/blog_migrate/9b9ab251694124c68da58b2854e93cfb.png)
3.优先级和结合性
每种运算符都有不同的优先级别,当在一个表达式中有多种运算混合时,运算次序要严格按优先级别进行,所有的运算符中,括号的优先级最高。
在求解表达式值的时候,根据运算符的优先级和结合性,具体规定如下:
(1)在求解某个表达式时,如果某个操作对象的左右都出现运算符,则首先要按运算符优先级别高低的次序执行运算。
例如在表达式a+b*c中,操作对象b的左侧为加号运算符,右侧为乘号运算符,而乘号运算符的优先级高于加号,所以b优先和其右侧的乘号结合先运算b*c,表达式相当于a+(b*c)。
(2)在表达式求值时,如果某个操作对象的左右都出现运算符且优先级别相同时,则要按运算符的结合性来决定运算次序。
例如在表达式a+b-c中,操作对象b的左侧为加号运算符,右侧为减号运算符,而减号运算符与加号运算符优先级别相同。那么这个表达式的运算次序是什么呢?这时我们要看运算符加号和减号的结合性,由于它们的结合性是“自左至右”,所以运算对象b优先和其左侧的减号结合先运算a+b,表达式相当于(a+b)-c。
4.不同类型数据混合运算
C语言还规定,只有类型相同的两个操作数才能一起运算。如果运算符两侧的操作数类型不同但相容(比如char和double),系统会按规则自动转换它们的类型,使双方的类型一致。系统进行自动类型转换的规则如图2-2所示。
![](https://i-blog.csdnimg.cn/blog_migrate/aaefa24dba40c9c4f4e5dc3fb04ce0fd.png)
图2-2 精度转换规则
图2-2中纵向的转换是无条件的,也就是说只要是字符型或短整型都无条件的先转换成基本整型再参加运算,只要是单精度实型都无条件的转换成双精度实型再参加运算。图中横向的转换是在运算符两边操作对象类型不一致时进行的,精度低的类型自动转换成精度高的类型。(注:Dev-Cpp和VC++中的单精度实型不再自动转换成双精度类型)。
例如表达式100+'A'-5.0*8是合法的表达式。它的运算过程如图2-3所示。
![](https://i-blog.csdnimg.cn/blog_migrate/cc54a309784b2719322ee8f72b24224f.png)
图2-3 表达式100+'A'-5.0*8的运算过程示意图系统自左至右扫描表达式至'A'时,
首先无条件地将'A'转换成基本整型数据65,表达式变成了100+65-5.0*8。
继续扫描发现65左右的运算符分别为+和-,而它们的优先级相同并且结合性是自左至右,
所以65和其左侧的+号结合,即先计算100+65,其结果为165。表达式变成165-5.0*8,
在扫描表达式至5.0时发现其左右两端的运算符-和*优先级别不同,
那么0.5自然和优先级别高的*结合,先计算5.0*8,系统自动将精度低的整型常量8转换成双精度实型8.0,运算结果为40.0。表达式最终变成了165-40.0,这时系统首先将165转换成165.0,
然后运算得到结果为125.0。5.强制类型转换在C语言中除了系统自动进行的类型转换以外,
我们也可以利用强制类型转换运算符将一个表达式转换成所需的类型。
其一般格式为:(类型标识符)表达式例如:
(int)(5.2+3.3) 将表达式5.2+3.3的值转换成int类型,转换后的值为8
(double)(5+3) 将表达式5+3的值转换成double类型,转换后的值为8.0
(float)(x+y) 将表达式x+y的值的类型转换成float类型
(float)x+y 将表达式x的值转换成float类型后再与y相加
请注意(float)(x+y)与(float)x+y的区别。
相关知识 算术运算
基本算术运算算术运算符是用来进行数学运算的,一共有+、-、*、/、%、++、--7个。用算术运算符连接起来的式子就是算术表达式,算术表达式的值是一个数值。C语言中基本的算术运算符有:
+ (加法运算符、或正值运算符。如5+6,a+c,+3,+b)
- (减法运算符、或负值运算符。如5-6,a-c,-3,-b)
* (乘法运算符。如5*6,值为30)
/ (除法运算符。如25/3,值为8)
% (求余运算符或称为取模运算符。如15%6,值为3)
C语言规定两个整型数相除的结果为仍然是整型数。例如5/2的结果为整数2,不保留小数部分。若被除数或除数有一个为实型,则结果为double类型。例如5.0/2的结果为实型数2.5。取模运算符 % 的意义是求解两个操作数相除后的余数。例如:7%3的结果为1、15%6的结果为3。余数的符号与被除数一致,如-15%6和-15%-6的结果都是-3,15%-6和15%6的结果都是3。C语言规定取模运算符的两侧必须均为整型数据,因为只有整型数据才能取余数。如果一方为实型数据,则编译程序时出错。当不同的运算出现在同一个表达式中时,各种运算是有先后次序的,依据是各个运算符的优先级及结合性。在表达式中遇到不同类型数据间的混合运算时系统按上文介绍的规则进行转换。任何时候,我们都可以使用括号来改变运算次序,而且恰当的使用括号会增加表达式的可读性。
②(代码)苹果装盘
任务描述:
有N个苹果要全部装盘,每个盘子装两个,编程输入苹果数量N,输出这些苹果能装多少盘。
输入格式:
一个整数N。
输出格式:
一个整数,盘子数量。
输入样例:
15
输出样例:
8
解法1
#include<stdio.h>
int main()
{
int n, p; //int型变量,苹果数量n,盘子数量p
scanf("%d", &n); //输入苹果数量
p = n / 2 + n % 2; //请思考该表达式的意义,此处还有另一种解法,你会吗?
printf("%d", p);
return 0;
}
代码分析
表达式n/2的意义可以理解为n个苹果能装的整盘的数量,整数除法的结果为整数。表达式n%2的意义可以理解为半盘的数量,其结果不是0就是1。两个表达式的和正好是装盘n个苹果需要的盘子数量。
解法2
#include<stdio.h>
int main()
{
int n, p; //int型变量,苹果数量n,盘子数量p
scanf("%d", &n); //输入苹果数量
p = (n + 1) / 2; //请思考这个表达式的意义
printf("%d", p);
return 0;
}
代码分析
表达式(n+1)/2的意义可以理解为:若n为奇数,则额外补1个苹果凑成偶数个,除以2正好是需要的盘子数量;若n为偶数,则(n+1)/2和n/2的结果是相同的,因为整数除法的结果还是整数。
解法3
#include<stdio.h>
int main()
{
int n, p; //int型变量,苹果数量n,盘子数量p
scanf("%d", &n); //输入苹果数量
p = (n + n % 2) / 2; //请思考这个表达式的意义
printf("%d", p);
return 0;
}
代码分析
表达式(n+n%2)/2的意义可以理解为总是把苹果凑成偶数个再除以2,若n为奇数,则n+n%2的值就是n+1;若n为偶数,则n+n%2的值就是n。苹果装盘程序是一个比较简单的问题,但是只使用算术运算完成还是需要技巧的。从以上三种解法可以看出,程序设计的灵活性和算法的多样性,希望你多做题、多思考、多实践,写出更好地程序。
③(代码)逆序后四位
任务描述:
程序每次读入一个至少4位数的正整数,然后输出其后4位按位逆序的数字。注意:当输入的数字含有结尾的0时,输出不应带有前导的0。比如输入57000,输出应该是7。
输入格式:
每个测试是一个正整数。
输出格式:
输出逆序的数。
输入样例1:
34500
输出样例1:
54
#include <stdio.h>
int main()
{
int a, b, c, d, num;
scanf("%d", &num);
if (num > 9999)
{
num = num % 10000; //如果超过四位数,对10000取余,获取后四位
}
a = num / 1000; //得到千位数
b = (num - a * 1000) / 100; //得到百位数(可以向得到十位数一样得到)
c = (num % 100) / 10; //对100求余得到十位和个位,在/10得到十位数
d = num % 10; //得到个位数
printf("%d", d * 1000 + c * 100 + b * 10 + a);
return 0;
}
这题比较经典,熟练得出一个数的每一位数,以后会用到。
二.自增自减
①(代码)天增岁月人增寿
任务描述:
天增岁月人增寿,春满乾坤福满门。小白弟弟今年n岁,请问过了新年后他多少岁呢。
输入格式:
一个整数n。
输出格式:
一个整数。
输入样例:
5
输出样例:
6
解法1
#include<stdio.h>
int main()
{
int n1, n2;
scanf("%d", &n1);
n2 = n1 + 1;
printf("%d", n2);
return 0;
}
代码分析
程序首先读入一个整数n1,然后将n1+1赋值给变量n2,最后输出n2。
解法2
#include<stdio.h>
int main()
{
int n1, n2;
scanf("%d", &n1);
n2 = ++n1;
printf("%d", n2);
return 0;
}
代码分析
1.语句n2=++n1;的功能是将++n1的值赋给变量n2,++n1的含义是先将n1的值自加1,然后再参与运算,所以最后n2得到的值实际就是n1的原值加1。也就是说,此语句实际等价于:n1=n1+1,n2=n1;2.请思考,如果将语句n2=++n1;改成n2=n1++;,程序的结果是什么,为什么。
相关知识 特殊的算术运算符(++、--)
C语言还为我们提供了两个功能特殊的算术运算符:++ (自增1运算符)-- (自减1运算符)关于这两个算术运算符,特别说明如下:++和--两个运算符都是单目运算符,其结合性是自右至左。这两个运算符的操作数只能是一个变量,不可以是其它任何形式的表达式。它们既可以做为前缀运算符放在变量的左侧,也可以做为后缀运算符放在变量的右侧。设n为一整型变量,则有下面的规则:作为后缀运算符:n++ (先使用n的值参与运算,当使用完成后再让n的值自加1)n-- (先使用n的值参与运算,当使用完成后再让n的值自减1)作为前缀运算符:++n (先让n的值自加1,然后再使用n的值参与运算)--n (先让n的值自减1,然后再使用n的值参与运算)例如,假设变量i的值为3,那么:执行j=i++;后j的值为3,i的值为4;执行j=i--;后j的值为3,i的值为2;执行j=++i;后j的值为4,i的值为4;执行j=--i;后j的值为2,i的值为2;也可以这样来理解:j=i++; 相当于: j=i; i=i+1;或相当于 j=i; i++;j=++i; 相当于: i=i+1;j=i; 或相当于 i++; j=i;可以知道,当i++或++i单独出现在独立的表达式中,其作用都是使i加1;当i--或--i单独出现在独立的表达式中,i--和--i的作用都是使i的值减1,二者在功能上没有区别。
示例代码分析 请分析以下代码的执行结果
#include<stdio.h>
int main()
{
int a, b, c;
a = 7;b = 2; c = ++a + b;
printf("1.c=%d,a=%d,b=%d\n", c, a, b);
a = 7;b = 2; c = a++ + b;
printf("2.c=%d,a=%d,b=%d\n", c, a, b);
a = 7;b = 2; c = a++ + ++b;
printf("3.c=%d,a=%d,b=%d\n", c, a, b);
a = 7;b = 2; c = ++a + ++b;
printf("4.c=%d,a=%d,b=%d\n", c, a, b);
a = 7;b = 2; c = ++a + ++b;
printf("5.c=%d,a=%d,b=%d\n", c, ++a, b++);
a = 7;b = 2; c = ++a + b++;
printf("6.c=%d,a=%d,b=%d\n", c, ++a, b++);
return 0;
}
//执行程序输出:
//1.c = 10, a = 8, b = 2
//2.c = 9, a = 8, b = 2
//3.c = 10, a = 8, b = 3
//4.c = 11, a = 8, b = 3
//5.c = 11, a = 9, b = 3
//6.c = 10, a = 9, b = 3
程序分析:程序中++、--运算符优先级高于其它算术运算符。程序中运算符之间加入了空格,使程序的理解和表达式的解析变得清晰和明确。
示例代码分析 请分析以下代码的执行结果
#include<stdio.h>
int main() {
int x, y, z;
x = 6;y = 5; z = 4;
printf("\n01.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = -x--;
printf("\n02.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = x++ + y;
printf("\n03.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = ++x + --y;
printf("\n04.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = ++x - y++;
printf("\n05.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = --x - ++y;
printf("\n06.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = x++ - ++y;
printf("\n07.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = x-- + --y;
printf("\n08.x=%d,y=%d,z=%d", x, y, z);
x = 6;y = 5; z = x-- + y++;
printf("\n09.x=%d,y=%d,z=%d", x, y, z);
return 0;
}
//执行程序,输出:
//01.x = 6, y = 5, z = 4
//02.x = 5, y = 5, z = -6
//03.x = 7, y = 5, z = 11
//04.x = 7, y = 4, z = 11
//05.x = 7, y = 6, z = 2
//06.x = 5, y = 6, z = -1
//07.x = 7, y = 6, z = 0
//08.x = 5, y = 4, z = 10
//09.x = 5, y = 6, z = 11
代码分析:1.由于++运算符、--运算符、-(负号)运算符、!(非)运算符的优先级相同,结合性都是自右至左,所以说表达式-n--会被理解成-(n--),表达式!n++会被理解成!(n++)。所以语句z=-x--;被理解成z=-(x--),此后输出:02.x=5,y=5,z=-62.C语言规定在理解有多个连续运算符的表达式时,尽可能自左至右地将更多的字符组成一个运算符,所以表达式m+++n会被理解成(m++)+n。所以语句z=x+++y;被理解成z=(x++)+y;此后输出:03.x=7,y=5,z=113.尽可能自左至右地将更多的字符组成一个运算符,当自左至右扫描表达式,如果读入下一个字符而不能构成运算符时,则将当前符号和下一个符号断开理解成两个运算。例如表达式m-++n会被理解成m- ++n,也就是m-(++n)。所以语句z=++x+--y;被理解成z=++x+(--y);此后输出:04.x=7,y=4,z=11
②(代码)奇怪的加法
任务描述
以下是一段简单的程序代码
#include<stdio.h>
int main()
{
int a,b,s;
scanf("%d%d",&a,&b);
s=______________; //请填空
printf("a=%d,b=%d,s=%d",a,b,s);
return 0;
}
结合输入输出样例可知,程序首先的功能是首先输入整型变量a和b的值,在最后输出时a和b的值都变成原值加1,而s的值是a和b原值的和再加1。
不幸的是,程序中重要的部分丢失了,你知道在横线处应该填写什么才能实现以上功能吗?你知道有多少种解法吗?
请将此代码补充完整后提交(不要修改横线外的代码),至少要使用三种解法哟,我知道你很聪明的。
输入格式:
两个空格分隔的整数。
输出格式:
代码中已规定好输出格式,请不需要改动,具体见输出样例。
输入样例:
2 8
输出样例:
a=3,b=9,s=11
你这个任务有思路吗?通过语句s=_______;要实现将a的值加1、b的值加1、表达式的值赋值给变量s,相当于在一个语句中做三件事。要想使变量s的值为a+b的和再加1,可以在空白处填写:a+b+1,要想在表达式中实现使a和b的值加1,可以在变量后加上++运算符,因而得到解法1的代码。
解法1
#include<stdio.h>
int main()
{
int a,b,s;
scanf("%d%d",&a,&b);
s = a++ + b++ + 1 ;
printf("a=%d,b=%d,s=%d",a,b,s);
return 0;
}
代码分析
根据++运算符的规则,语句s = a++ + b++ +1 ;与下面的代码是等价的:s = a+b+1; a++; b++;也就是说,变量a和b先参与运算,计算s=a+b+1,然后再自加1。程序首先读入一个整数n1,然后将n1+1赋值给变量n2,最后输出n2。以上是利用后缀++完成的代码,请小白弟弟在Dev-C++中运行测试,并在平台提交。如果恰当使用前缀++,是不是也能完成呢?请小白弟弟顺着这个思路完成解法2。
解法2
#include<stdio.h>
int main()
{
int a,b,s;
scanf("%d%d",&a,&b);
s = ++a + b++ ;
printf("a=%d,b=%d,s=%d",a,b,s);
return 0;
}
代码分析
根据++运算符的规则,表达式 s = ++a + b++ ; 相当于按顺序执行的++a;s=a+b;b++;三个语句。
解法3
请思考另外一种解法。
三.赋值运算
①(代码)生意兴隆通四海
任务描述:
俗话说:民以食为天。小白弟弟的爷爷经营一家粮食批发商店,已知昨天的库存是大米a公斤、小米b公斤,今天的进销记录是大米卖出c公斤、小米进货d公斤。爷爷想知道今日的库存应该是多少,小白为爷爷编写了一个程序,解决了这个问题,但程序中的一个部分不小心被删除了,你能恢复吗?
#include<stdio.h>
int main(){
double a,b,c,d,s;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
s=___________________;//请补充丢失的代码
printf("大米:%.2lf,小米:%.2lf,总库存:%.2lf",a,b,s);
return 0;
}
输入格式:
4个实数,分别对应题目中的a,b,c,d。
输出格式:
程序中已经给出输出样式。
输入样例:
100.50 200.80 50.00 300.00
输出样例:
大米:50.50,小米:500.80,总库存:551.30
解法1 利用赋值运算
#include<stdio.h>
int main()
{
double a,b,c,d,s;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
s= (a=a-c) + (b=b+d) ;
printf("大米:%.2lf,小米:%.2lf,总库存:%.2lf",a,b,s);
return 0;
}
相关知识 赋值运算
1.赋值运算符
在前面的程序中我们接触了很多关于赋值的操作,在C语言中赋值也是一种运算,运算符为单个的等号:=。赋值运算的一般格式是:变量名称=表达式它的功能是将赋值运算符右侧表达式的值赋给其左侧的变量。赋值运算符的左侧只能是一个变量。
2.赋值表达式
赋值是一种运算,由赋值运算符连接组成的式子称为赋值表达式。赋值表达式是有值的,它的值就是最终赋给变量的值。赋值表达式的值还可以参加运算。
a=3 a的值是3,整个赋值表达式的值为3
b=5+(a=3) a的值为3,b的值为8,整个赋值表达式的值为8
a=b=c=8 相当于a=(b=(c=8)),a,b,c的值为8,整个表达式的值为8
a=(b=10)/(c=2) b的值是10,c的值是2,a的值5,整个表达式的值是5
b=(a=5)+(c=++a) 求解后,a与c的值是6,b的值是11,整个表达式的值是11
不同类型间赋值当赋值运算符两侧的数据类型不一致但相容时(如均为数值),系统会通过类型自动转换规则将表达式值的类型转换成左侧变量的类型后完成赋值。如果是低精度向高精度赋值,其精度将自动扩展;如果是高精度向低精度赋值,那么可能会发生溢出或损失精度(通常是小数)。例如:
int a=5.8; //a最后收到的值是5
double d=5; //d最后收到的值是5.0
复合赋值运算符复合赋值运算符有:+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=等等。这里我们暂时只讨论前5种,后5种关于位操作的复合赋值运算符本书不作讨论。复合赋值运算是某种赋值运算的简写,即如果把某变量与另一表达式的某种运算结果还赋值给这个变量本身,例如a=a+3,那么这一赋值表达式就可以用复合赋值运算符简写为a+=3。请看以下的几种复合情形:
x*=8 等价于x=x*8
x*=y+8 等价于x=x*(y+8),注意不是等价于x=x*y+8
x%=3 等价于x=x%3
代码分析
根据题意可知,题目要求我们在语句s=__;中实现三个操作,即a=a-c、b=b+d和s=a+b。由于赋值表达式是有值的,可以参与运算,其值就是赋的那个值。所以我们可以将以上三个表达式合并写成一个:s= (a=a-c) + (b=b+d) 。这样就实现了在一个表达式中改变三个变量的值。上述表达式中的赋值完全可以改写成复合赋值,从而我们得到解法2的代码。
解法2 利用复合赋值运算
#include<stdio.h>
int main()
{
double a,b,c,d,s;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
s= (a-=c) + (b+=d) ;
printf("大米:%.2lf,小米:%.2lf,总库存:%.2lf",a,b,s);
return 0;
}
②(代码)动态考核
任务描述
小白弟弟本次期末考核语文卷面分为a,数学卷面分为b,品德积分为c,劳动积分为d(d为偶数)。
学校实行动态考核制度,经过严格审核,小白弟弟因为作文写的特别好,获得语文加m分的奖励,因为数学答题超时而罚掉n分,因为拾金不昧品德分加倍,因为忘记值日劳动分减半。
小白弟弟最后的成绩都是多少呢?
输入格式:
在一行中有6个整数,分别对应题目中的a,b,c,d,m,n。其中d是偶数。
输出格式:
一行中以空格分隔输出小白的各科最后得分。
输入样例:
80 90 100 150 10 5
输出样例:
90 85 200 75
#include<stdio.h>
int main()
{
int a, b, c, d, m, n; //注意OJ题目中输入%d旁边要带空格,其他情况一般不带
scanf("%d %d %d %d %d %d %d", &a, &b, &c, &d, &m, &n);
a = a + m;
b = b - n;
c = c * 2;
d = d / 2;
printf("%d %d %d %d", a, b, c, d);
return 0;
}