C语言程序设计之数据计算
3.1 运算符概述
计算机最核心的任务就是完成数据的计算,C语言提供了丰富(多达34种)的运算符来实现不同数据的各种运算,之前在求数据类型的大小时已经使用过的sizeof()就是一种运算符,最常用的运算符有算术,关系,逻辑以及比较和位运算符,在介绍具体的运算符之前先要明确关于运算符的一些概念。
- 操作数:就是参与运算的数据,例如2,(3+2)都是一个操作数
- 运算符:指定数据执行的运算类型,例如算术,逻辑,关系,比较,位运算等等
- 表达式:由操作数和运算符组成,通常都是完成某种业务数据计算而设计的,例如计算圆的面积等等。
- 优先级:在各种运算符参与运算时,有不同的执行顺序,由它们的优先级决定,可以使用()来改变执行的顺序。
- 结合性:执行运算的方向,例如从左到右或者从右到左。
关于运算符概念的应用案例如下所示
#include "common.h"
/*
关于运算符的概念
*/
void main(){
//运算符:参与数据的运算方式,这里的+就是运算符
//3+5就是表达式
//3,5就是操作数
int result = 3 + 5;
//优先级:计算的先后顺序,这里就是先乘除,后加减 ,可以通过()提高优先级
//结合性:计算的方向:这里就是从左往右开始计算
int precedence = (45 + 5) / 5 * 10;
//运算符不能相邻
// 1 + *3;
//但是在执行加减法运算时,编译器把+3当成了正数
1 + +3;
1 + -3;
system("pause");
}
3.2 算数运算符
算数运算符就是数学意义上的加减乘除,还有取模运算(即求余数),取模主要用于数据的截取。
算数运算符是按照先乘除,后加减的优先级,从左到右的结合性执行计算,应用案例如下所示
#include "common.h"
/*
算数运算符
+ - * / % 的常规应用 以整数为例
*/
void arithmetic_int() {
printf("1 + 3 = %d\n", (1 + 3));
printf("8 - 2 = %d\n", (8 - 2));
//运算结果的类型是参与运算中的最大数据类型 整数和整数运算的结果是整数
printf("5 / 2 = %d\n", (5/2 ));
//整数和小数运算的结果类型是小数
printf("5 / 2.0 = %f\n", (5/2.0 ));
//3.5*2的结果是浮点数,这里通过强制类型转换为整数
printf("3.5 * 2 = %d \n",(int) (3.5 *2));
//求模运算符 就是求余数
printf("5 %% 2 = %d\n", (5%2));
//需要注意的是,只有整数才能求模,如下代码会发生编译错误
//printf(5%1.2);
//求模结果的符号类型与被除数相同
printf("5 %% -2 = %d\n", (5 % -2));
printf("-5 %% -2 = %d\n", (-5 % 2));
}
void main(){
arithmetic_int();
system("pause");
}
在执行算数运算时,会发生自动类型转换,结算结果的数据类型是其中最大的数据类型,例如整数和浮点数参与算数运算,结果一定是浮点类型,如果想要获得整数,则需要进行强制类型转换,应用案例如下所
#include "common.h"
void arithmetic_float() {
// 13/4=3 自动转换为float 就是3.0
float fl = 13 / 4;
//输出结果为3.000000
printf("%f\n",fl);
//先运算出浮点类型 13/4.0=3.25
fl = 13 / 4.0;
printf("%f", fl);
printf("5.0 /2 = %d",(int)(5.0 / 2));
}
void main(){
arithmetic_float();
system("pause");
}
取模只能是整数参与运算,运算结果的符号和被除数一致,也就意味着如果被除数是正数,那么取模的结果就是正数,反之亦然,应用案例如下所示
#include "common.h"
/*
取模运算要求左右两边必须是整数类型
*/
void modulus() {
//被除数/除数的余数 就是取模
printf("3%%5=%d\n",(3%5));//3
printf("5%%3=%d\n",(5%3));//2
printf("3%%-5=%d\n",(3%-5));// 3
printf("5%%-3=%d\n",(5%-3));//2
printf("-3%%5=%d\n",(-3%5));// -3
printf("-5%%3=%d\n",(-5%3));// -2
}
void main(){
modulus();
system("pause");
}
取模的应用案例
将一个两位数实现倒转
#include "common.h"
/*
取模的应用场景
数据切割
将一个二位数实现颠倒 例如输入95 反转结果是59
*/
void reversal() {
printf("请输入一个整数\n");
int num = 0;
scanf("%d",&num);
//个位
int unit = num % 10;
//十位
int decade = num / 10;
int reversalResult = unit * 10 + decade;
printf("%d反转之后的结果是%d\n",num,reversalResult);
}
void main(){
reversal();
system("pause");
}
将一个三位数倒转
#include "common.h"
/*
将一个三位数实现颠倒 例如输入123 反转结果是321
*/
void reversal_hundred() {
printf("请输入一个整数\n");
int num = 0;
scanf("%d", &num);
//个位 123/10=12..3
int unit = num %10;
printf("unit= %d\n",unit);
//十位 123%10=12...3
int decade = num /10%10;
int hundreds = num / 100;
int reversalResult = unit * 100 + decade*10+ hundreds;
printf("%d反转之后的结果是%d\n", num, reversalResult);
}
void main(){
reversal_hundred();
system("pause");
}
3.3 赋值运算符
在学习变量赋值时用到的=
实际上就是赋值运算符,它的作用就是用来将右边的值赋值给左边的变量,当表达式中有多个变量同时赋值时按照从右往左的结合性进行赋值,优先级在所有运算符中仅高于逗号运算符,应用案例如下所示
#include "common.h"
/*
赋值运算符
优先级:
结合性: 如果有多个赋值运算,则是从右向左赋值
*/
void assignment_sample() {
int num = 3;
num = 10;
printf("num = %d\n", num = 20); //num=20 赋值表达式整体的值就是num被赋值的变量
int left;
int right;
//结合性:从右向左计算
left = right = 88;
printf("left = %d \t right = %d \n",left,right);
}
void main(){
assignment_sample();
system("pause");
}
在赋值时,赋值运算符左边的值叫做左值,就是有内存实体的变量,右值就是能放在赋值号右边,并且能够赋值给其他变量的值,左值可以当作右值赋值给其他变量.
在赋值时会进行自动类型转换,应用案例如下所示
#include "common.h"
/*
赋值是在CPU内部的寄存器完成的
*/
void assignment_feature() {
int num = 10;
//有内存实体的变量才能赋值
//右值:能放在赋值号右边,能赋值给其他变量的值
//20 = num;
//左值:被赋值的值,必须有内存实体,左值一定能当作右值
int target_num = num;
//赋值号会进行自动类型转换
int val = 10.999;
printf("val = %d\n",val);
}
void main(){
assignment_feature();
system("pause");
}
在日常开发中,赋值运算还可以和算数运算结合在一块使用,用于简化表达式,但是需要注意的是它们在一起使用时不能使用空格隔开,否则会发生编译错误,应用案例如下所示
#include "common.h"
/*
赋值运算符结合算数运算符的使用
注意不能有空格 例如 + =,会造成编译错误
*/
void assignment_arithmetic() {
int num = 80;
printf("num =%d\n", num);
num += 8; //等价于 num =num +8;
printf("num+8 =%d\n", num);
num -= 20;
printf("num-20 =%d\n", num);
}
void main(){
assignment_arithmetic();
system("pause");
}
赋值和算数运算符的复杂案例
首先定义一个打印方法,用于输出三个整数参数的值
/*
输出三个整数参数的结果并换三行
*/
void print_result(int a,int b,int c) {
printf(" a = %d \n b = %d \n c = %d \n", a, b, c);
}
赋值运算结合算数运算的案例如下所示
#include "common.h"
/*
赋值运算符结合算数运算符的复杂案例
理解赋值运算符的优先级,低于算术运算符,可以通过()提高优先级
遇到复杂的表达式时,先拆减,后计算
*/
void assignment() {
int a, b, c;
a = b = c=5;
print_result(a,b,c); // 5 5 5
//改变了优先级 先计算b=5
a = (b=5);
print_result(a, b, c); // 5 5 5
//先执行赋值,后执行加法 再把相加的结果赋值给a
a = 5 + (c = 6);//11 5 6
print_result(a, b, c);
//先执行 c=6,再执行b=4,再执行6+4 并把相加的结果赋值给a
a = (b = 4) + (c = 6); // 10 4 6
print_result(a, b, c);
//先执行c=2,再执行b=10 最周执行10/2并赋值给a
a = (b = 10) / (c = 2);// 5 10 2
print_result(a, b, c);
int num = 12;
//首先明确 赋值运算符低于算数运算符
//拆解表达式 num =num+(num=num-(num*num))
//计算步骤 num= -132+ (12-144)
num += num -= num * num;
printf(" num =%d \n ",num);
int tmp = 2;
tmp %= 4 - 1;
printf("tmp = %d",tmp); //目前tmp=2
//拆解表达式
// 0 0 0 6 6
//tmp=tmp+(tmp=(tmp*(tmp=tmp-(tmp=tmp*3))))
//tmp=
tmp += tmp *= tmp -= tmp *= 3;
printf("tmp += tmp *= tmp -= tmp *= 3 = %d",tmp);
}
void main(){
assignment();
system("pause");
}
3.4 自增运算符
自增运算符的作用就是用于变量的加1,主要用于控制循环的自增,由++
两个加号组成,可以放到变量的前面或者是后面,如果是单独一行语句,前置或者是后置结果是一样的,应用案例如下所示
#include "common.h"
/*
自增运算符
当自增运算符作为单独的语句,无论前置++或者后置++结果都是一样的
*/
void auto_inc_before_after() {
int num = 10;
num++;
printf("num = %d\n", num);
int val = 10;
++val;
printf("val = %d\n", val);
}
void main(){
auto_inc_before_after();
system("pause");
}
当自增运算符不是一条单独的语句时,前置和后置会影响表达式的计算结果,应用案例如下所示
#include "common.h"
/*
表达式中的自增运算符
*/
void auto_inc_expression() {
int num = 10;
int result = num++;
printf("result = %d \t num = %d\n", result, num);
int tmp = 10;
int target = ++tmp;
printf("target = %d \t tmp = %d\n", target, tmp);
}
void main(){
auto_inc_expression();
system("pause");
}
而如果自增运算符和算数运算符同时参与运算时,自增运算符的优先级高于算数运算符,应用案例如下所示
#include "common.h"
/*
自增运算符的优先级高于算数
*/
void auto_inc_priority() {
int num = 10;
int data = 5;
printf(" num = %d\n", ++num*5); //num先自增1 再参与乘法运算 结果是55
}
void main(){
auto_inc_priority();
system("pause");
}
3.5 逗号运算符
在日常开发中,可以将多个表达式合并到一块,表达式之间使用逗号分隔,它们就构成了逗号表达式,其优先级是所有运算符中最低的,结合性是会按照从左到右的顺序执行计算,整个表达式的值就是最后那个逗号之后的表达式的值,应用案例如下所示。
#include "common.h"
/*
逗号表达式的运算结果是最后一个逗号的值
优先级是所有运算符中最低的
*/
void comma_sample() {
int num = (5, 8);
printf("num = %d\n",num);
}
/*
逗号运算符的每条语句都会被执行
结合性:从左向右
*/
void comma_feature() {
//使用逗号将多个表达式连接起来,整个表达式的值就是最后那个逗号之后的表达式的值
system("calc"), system("notepad"), system("ipconfig");
}
/*
逗号表达式的复杂案例
*/
void comma() {
//使用逗号将多个表达式连接起来,整个表达式的值就是最后那个逗号之后的表达式的值
printf("3+4,6的运算结果是%d\n",(3+4,6));
int a = 0;
printf(" a = (a=3,6*3) 的运算结果是%d\n",(a = (a = 3, 6 * 3)));
printf(" a = a=3,6*3 的运算结果是%d\n",(a = a = 3, 6 * 3));
printf(" a = 3 ,a+=2,a+3 的运算结果是%d\n",(a = 3, a += 2, a + 3)); //8
printf(" a = 3*5,a*4 的运算结果是%d\n",(a = 3 * 5,a * 4)); //60
printf(" (a = 3*5,a*4,a+5)的运算结果是%d\n",((a = 3 * 5,a * 4,a+5))); //20
}
void main() {
// comma_sample();
// comma_feature();
comma();
getchar();
}
3.6 条件运算符
条件运算符也被称为三目运算符,其表现形式为表达式1?表达式2:表达式3
,其中如果表达式1的条件成立,那么表达式的计算结果就是表达式2,否则计算结果就是表达式3,应用案例如下所示
#include "common.h"
/*
条件运算符的应用案例
*/
void conditon_gramma() {
//表达式为非0,执行打开记事本,否则打开计算器
3 > 1 ? system("notepad"):system("calc");
}
void main() {
conditon_gramma();
system("pause");
}
使用关系运算符实现求两个整数的最大值应用案例
#include "common.h"
/*
使用条件运算符实现取两个数的最大值
*/
void condition_compare() {
int first = 100;
int second = 200;
int max = first > second ? first : second;
printf("最大值是%d\n",max);
}
void main(){
condition_compare();
system("pause");
}
条件运算符的优先级仅仅优先于赋值运算符,当有多个条件表达式执行运算时,会按照从右到左的结合性进行计算,应用案例如下所示
#include "common.h"
/*
优先级:优先于赋值运算符
结合性:从右向左
*/
void condition_feature() {
int a = 5, b = 6, c = 7, d = 8;
//拆解表达式
// c>d?c:d ->8
// a>b?a:8 -> 8
//最后结果就是8
int result = a > b ? a : c > d ? c : d;
printf("result =%d \n",result);
}
void main(){
condition_feature();
system("pause");
}
使用关系运算符实现求四个整数中的最大值
#include "common.h"
}
/*
求四个整数的最大值
*/
void get_max_value() {
int a = 5, b = 6, c = 7, d = 8;
int max = (a > b ? a : b) > (c > d ? c : d)? (a > b ? a : b): (c > d ? c : d);
printf("四个整数之间的最大值是%d\n",max);
}
void main(){
get_max_value();
system("pause");
}
3.8 关系运算符
没有对比就没有伤害,生活中处处都存在着比较,回归到程序中亦是如此,因为程序来源于生活,是对生活的一种仿真实现。
C语言的关系运算符以及说明如下表格所示
运算符 | 功能 |
---|---|
> | 大于 |
< | 小于 |
== | 等于 |
!= | 不等于 |
>= | 大于等于 |
<= | 小于等于 |
关系运算符的运算结果取决于参与运算的关系表达式,如果表达式成立,结果为1,否则为0,应用案例如下所示
#include "common.h"
/*
关系表达式的运算结果:成立为1,不成立为0
*/
void releation_result() {
printf(" 88 <99 %d ",(88<99));
printf(" 88 >99 %d ",(88>99));
}
void main(){
releation_result();
system("pause");
}
关系运算符的结合性是从左向右依次开始计算,应用案例如下所示
#include "common.h"
/*
关系运算符的结合性也是从左到右开始运算的
*/
void releation_associativity() {
printf("5>4>3 %d", (5 > 4 > 3));
}
void main(){
releation_associativity();
system("pause");
}
在使用关系运算符进行相等性判断时,如果数据类型是浮点数,还要注意浮点数的精度问题,应用案例如下所示
#include "common.h"
/*
关系运算符的相等性判断
*/
void releation_equals_float() {
float left = 10.00000000001;
float right = 10.00000000000001;
//因为超过了float精确范围,所以是相等,即结果为1
printf(" left == right ? %d\n",(left==right));
}
void main(){
releation_equals_float();
system("pause");
}
C语言中使用字符串可以通过指针和字符数组两种方式,字符串也可以实现相等行判断,应用案例如下所示。
#include "common.h"
/*
字符串相等性判断
*/
void releation_equals_str() {
//C语言使用字符串可以通过指针和数据两种方式
char *p1 = "BAT";
//相同常量的字符串,存储的是同一个地址
char *p2 = "BAT";
printf("p1的地址是%p\np2的地址是%p\n",p1,p2);
//因此这里是相等的。
printf("*p1 == *p2 ? %d\n ",(*p1 == *p2));
char str1[100] = "我要去阿里";
//这里会重新开辟内存,拷贝常量
char str2[100] = "我要去阿里";
printf("str1的地址是%p\n str2的地址是%p\n", str1, str2);
//此时不等,因为这里比较的是两个字符串的引用地址
printf("str1 == str2 ? %d\n",str1==str2);
}
void main(){
releation_equals_str();
system("pause");
}
关系运算符案例1:实现是否通过面试
#include "common.h"
//定义一个名为面试分数的常量
#define INTERVIEW_SCORE 90
void interview() {
int score = 0;
printf("请输入你面试的评分\n");
scanf("%d", &score);
//根据输入的分数判断是否符合面试
score >= INTERVIEW_SCORE ? printf("恭喜你通过面试\n") : printf("回家等电话\n");
}
void main() {
interview();
system("pause");
}
关系运算符案例2:实现是否满足结婚条件
#include "common.h"
#include <string.h>
#define MAN_AGE 22
#define WOMEN_AGE 20
/*
使用三目运算符结合关系运算符和逻辑运算符实现判断是否符合结婚条件
*/
void marray() {
char boy[2] = "男";
char girl[2] = "女";
printf("请输入你的性别\n");
char gender[3] = {0};
scanf("%s",&gender);
printf("请输入你的年龄\n");
int age = 0;
scanf("%d",&age);
printf("你的性别是%s\t你的年龄是%d",gender,age);
//strcmp表示两个字符串的比较,如果返回0则为相等,需要引入<string.h>头文件
// //判断要么满足年龄大于等于22周岁并且性别为男性,或则年龄大于等于20周岁并且性别为女性的才能结婚。
(strcmp(gender,boy)==0&&age >= 22 || strcmp(gender,girl)&&age >= 20 )? printf("你已经到了法定的结婚年龄\n") : printf("你还没有到结婚的年龄,好好学习吧\n");
}
void main() {
marray();
system("pause");
}
关系运算符案例3:使用程序实现根据不同的性别销售不同的商品
#include "common.h"
#include <string.h>
#define MEN "男"
#define WOMEN "女"
/*
根据不同的性别制订不同的销售策略(卖不同的东西)
*/
void sale() {
printf("请输入你的性别\n");
char gender[3] = {0};
scanf("%s",&gender);
strcmp(gender, MEN) == 0 ? printf("销售刮胡刀\n") : printf("销售化妆品\n");
}
void main(){
sale();
system("pause");
}
3.9 逻辑运算符
逻辑运算是根据数据的逻辑关系,生成一个0或者1的值,常用的逻辑运算符有逻辑与(&&),逻辑或(||)和逻辑非(!)
- 逻辑与(&&):表达式左右两边都是1,逻辑与的结果为1,否则为0
- 逻辑或(||):表达式左右两边只要有1边为1,逻辑或为1,否则为0
- 逻辑非(!):表达式结果1,逻辑非为0,否则为1
应用案例如下所示
#include "common.h"
/*
逻辑运算符
*/
void logic_operator() {
//逻辑与:&&两边结果为1,逻辑与为1
printf(" 1 && 1 %d\n",(1&&1));
//&&两边有一个为0,结果为0
printf(" 1 && 0 %d\n",(1&&0));
//逻辑或: ||两边有一边为1 结果为1
printf(" 1 || 1 %d\n",(1||1));
//||两边同时为0,结果为0
printf("0 || 0 %d\n",(0||0));
//逻辑非 !0 就是1 反之就是0
printf("!1 %d\n",(!1));
printf("!0 %d\n",(!0));
}
void main() {
logic_operator();
system("pause");
}
逻辑与和逻辑或还存在短路特性:一旦明确整个表达式的值,就不再计算表达式余下的部分,应用案例如下所示
#include "common.h"
/*
逻辑运算符的短路特性:一旦明确整个表达式的值,就不再计算表达式余下的部分
*/
void logic_short_circuit() {
int left = 5;
int right = 8;
//
0 && ++left;
1 || ++right;
printf("left =%d \n",left);
printf("right =%d \n", right);
}
void main(){
logic_short_circuit();
system("pause");
}
运算符的优先级:
逻辑非(!)>算数运算符>逻辑与(&&)>逻辑或(||)>赋值运算符(=)