C语言基础运算符

1、C 语言加减乘除运算

加减乘除是常见的数学运算,C 语言当然支持,不过,C 语言中的运算符号与数学中的略有不同,请见下表。

加法减法乘法除法取余
数学+-×÷
c语言+-*/%

下面的代码演示了如何在 C 语言中进行加减乘除运算:

#include <stdio.h>
int main()
{
int a = 12;
int b = 100;.
float c = 8.5;
int m = a + b;
float n = b * c;
double p = a / c;
int q = b % a;
printf("m=%d, n=%f, p=%lf, q=%d\n", m, n, p, q);
return 0;
}

输出结果:

m=112, n=850.000000, p=1.411765, q=4

也可以让数字直接参与运算:

#include <stdio.h>
int main()
{
int a = 12;
int b = 100;
float c = 8.9;
int m = a - b; // 变量参与运算
int n = a + 239; // 有变量也有数字
double p = 12.7 * 34.3; // 数字直接参与运算
printf("m=%d, n=%d, p=%lf\n", m, n, p);
printf("m*2=%d, 6/3=%d, m*n=%ld\n", m * 2, 6 / 3, m*n);
return 0;
}

输出结果:

m=-88, n=251, p=435.610000
m*2=-176, 6/3=2, m*n=-22088

对除法的说明

C 语言中的除法运算有点奇怪,不同类型的除数和被除数会导致不同类型的运算结果:

  • 当除数和被除数都是整数时,运算结果也是整数;如果不能整除,那么就直接丢掉小数部分,只保留整数部分,这跟将小数赋值给整数类型是一个道理。
  • 一旦除数和被除数中有一个是小数,那么运算结果也是小数,并且是 double 类型的小数。

请看下面的代码:

#include <stdio.h>
int main()
{
int a = 100;
int b = 12;
float c = 12.0;
double p = a / b;
double q = a / c;
printf("p=%lf, q=%lf\n", p, q);
return 0;
}

运行结果:

p=8.000000, q=8.333333

a 和 b 都是整数,a / b 的结果也是整数,所以赋值给 p 变量的也是一个整数,这个整数就是 8。
另外需要注意的一点是除数不能为 0,因为任何一个数字除以 0 都没有意义。

对取余运算的说明

取余,也就是求余数,使用的运算符是 %。C 语言中的取余运算只能针对整数,也就是说,% 的两边都必须是整数,
不能出现小数,否则编译器会报错。
另外,余数可以是正数也可以是负数,由 % 左边的整数决定:

  • 如果 % 左边是正数,那么余数也是正数;
  • 如果 % 左边是负数,那么余数也是负数。

请看下面的例子:

#include <stdio.h>
int main()
{
printf(
"100%%12=%d \n100%%-12=%d \n-100%%12=%d \n-100%%-12=%d \n",
100 % 12, 100 % -12, -100 % 12, -100 % -12);
return 0;
}

运行结果:

100%12=4
100%-12=4
-100%12=-4
-100%-12=-4

在 printf 中,% 是格式控制符的开头,是一个特殊的字符,不能直接输出;要想输出 %,必须在它的前面再加一个 %,
这个时候 % 就变成了普通的字符,而不是用来表示格式控制符了。

加减乘除运算的简写

有时候我们希望对一个变量进行某种运算,然后再把运算结果赋值给变量本身,请看下面的例子:

#include <stdio.h>
int main()
{
int a = 12;
int b = 10;
printf("a=%d\n", a);
a = a + 8;
printf("a=%d\n", a);
a = a * b;
printf("a=%d\n", a);
return 0;
}

输出结果:

a=12
a=20
a=200

在 C 语言中,对变量本身进行运算可以有简写形式。假设用 # 来表示某种运算符,那么

a = a # b

可以简写为:

a #= b

#表示 +、-、*、/、% 中的任何一种运算符。

上例中 a = a + 8 可以简写为 a += 8,a = a * b 可以简写为 a *= b。

2.C 语言自增(++)和自减(- -)运算符

一个整数类型的变量自身加 1 可以这样写:

a = a + 1;

或者

a += 1;

不过,C 语言还支持另外一种更加简洁的写法,就是:

a++;

或者

++a;

这种写法叫做自加或自增,意思很明确,就是每次自身加 1。相应的,也有 a----a,它们叫做自减,表示自身减 1。
++和- -分别称为自增运算符和自减运算符,它们在循环结构中使用很频繁。

自增和自减的示例:

#include <stdio.h>
int main()
{
int a = 10, b = 20;
printf("a=%d, b=%d\n", a, b);
++a;
--b;
printf("a=%d, b=%d\n", a, b);
a++;
b--;
printf("a=%d, b=%d\n", a, b);
return 0;
}

运行结果:

a=10, b=20
a=11, b=19
a=12, b=18

自增自减完成后,会用新值替换旧值,将新值保存在当前变量中。
自增自减的结果必须得有变量来接收,所以自增自减只能针对变量,不能针对数字,例如 10++就是错误的。

需要重点说明的是,++ 在变量前面和后面是有区别的:

  • ++ 在前面叫做前自增(例如 ++a)。前自增先进行自增运算,再进行其他操作。
  • ++ 在后面叫做后自增(例如 a++)。后自增先进行其他操作,再进行自增运算。

下面的例子能更好地说明前自增(前自减)和后自增(后自减)的区别:

#include <stdio.h>
int main()
{
int a = 10, b = 20, c = 30, d = 40;
int a1 = ++a, b1 = b++, c1 = --c, d1 = d--;
printf("a=%d, a1=%d\n", a, a1);
printf("b=%d, b1=%d\n", b, b1);
printf("c=%d, c1=%d\n", c, c1);
printf("d=%d, d1=%d\n", d, d1);
return 0;
}

输出结果:

`a=11, a1=11
`b=21, b1=20
`c=29, c1=29
`d=39, d1=40

a、b、c、d 的输出结果相信没有疑问,下面重点分析 a1、b1、c1、d1:

  1. 对于 a1=++a,先执行 ++a,结果为 11,再将 11 赋值给 a1,所以 a1 的最终值为 11。而 a 经过自增,最终的值也为 11。
  2. 对于 b1=b++,b 的值并不会立马加 1,而是先把 b 原来的值交给 b1,然后再加 1。b 原来的值为 20,所以b1 的值也就为 20。而 b 经过自增,最终值为 21。
  3. 对于 c1=–c,先执行 --c,结果为 29,再将 29 赋值给 c1,所以 c1 的最终值为 29。而 c 经过自减,最终的值也为 29。
  4. 对于 d1=d–,d 的值并不会立马减 1,而是先把 d 原来的值交给 d1,然后再减 1。d 原来的值为 40,所以d1 的值也就为 40。而 d 经过自减,最终值为 39。
  5. 可以看出:a1=++a;会先进行自增操作,再进行赋值操作;而 b1=b++;会先进行赋值操作,再进行自增操作。c1=–c;和 d1=d–;也是如此。

为了强化记忆,我们再来看一个自增自减的综合示例:

#include <stdio.h>
int main()
{
int a = 12, b = 1;
int c = a - (b--); // ①
int d = (++a) - (--b); // ②
printf("c=%d, d=%d\n", c, d);
return 0
}

输出结果:

c=11, d=14

我们来分析一下:

  1. 执行语句①时,因为是后自减,会先进行 a-b 运算,结果是 11,然后 b 再自减,就变成了 0;最后再将 a-b 的结果(也就是 11)交给 c,所以 c 的值是 11。
  2. 执行语句②之前,b 的值已经变成 0。对于 d=(++a)-(–b),a 会先自增,变成 13,然后 b 再自减,变成 -1,最后再计算 13-(-1),结果是 14,交给 d,所以 d 最终是 14。

3.C 语言运算符的优先级和结合性

请看下面的代码:

#include <stdio.h>
int main() {
int a = 16, b = 4, c = 2;
int d = a + b * c;
int e = a / b * c;
printf("d=%d, e=%d\n", d, e);
return 0;
}

运行结果:

d=24, e=8

对于表达式 a + b * c,如果按照数学规则推导,应该先计算乘法,再计算加法;b * c 的结果为 8,a + 8 的结果为 24,所以 d 最终的值也是 24。从运行结果可以看出,我们的推论得到了证实,C 语言也是先计算乘法再计算加法,和数学中的规则一样。
先计算乘法后计算加法,说明乘法运算符的优先级比加法运算符的优先级高。所谓优先级,就是当多个运算符出现在同一个表达式中时,先执行哪个运算符。

一下子记住所有运算符的优先级并不容易,还好 C 语言中大部分运算符的优先级和数学中是一样的,在以后的编程过程中也会逐渐熟悉起来。如果实在搞不清,可以加括号,就像下面这样:

int d = a + (b * c);

括号的优先级是最高的,括号中的表达式会优先执行,这样各个运算符的执行顺序就一目了然了。

对于表达式 a / b * c,除法和乘法的优先级是相同的,这个时候到底该先执行哪一个呢?
按照数学规则应该从左到右,先计算除法,在计算乘法;a / b 的结果是 4,4 * c 的结果是 8,所以 e 最终的值也是 8。这个推论也从运行结果中得到了证实,C 语言的规则和数学的规则是一样的。当乘法和除法的优先级相同时,编译器很明显知道先执行除法,再执行乘法,这是根据运算符的结合性来判定的。所谓结合性,就是当一个表达式中出现多个优先级相同的运算符时,先执行哪个运算符:先执行左边的叫左结合性,先执行右边的叫右结合性。
/和*的优先级相同,又都具有左结合性,所以先执行左边的除法,再执行右边的乘法。

像 +、-、*、/ 这样的运算符,它的两边都有要计算的数据,每份这样的数据都称作一个操作数,一个运算符需要 n 个操作数就称为 n 目运算符。例如:

  • +、-、、/、= 是双目运算符;
  • ++、-- 是单目运算符;
  • ? : 是三目运算符

4.C 语言数据类型转换(自动转换+强制转换)

自动类型转换

自动类型转换就是编译器默默地、隐式地、偷偷地进行的数据类型转换,这种转换不需要程序员干预,会自动发生。

  1. 将一种类型的数据赋值给另外一种类型的变量时就会发生自动类型转换,例如:

    float f = 100;
    

    100 是 int 类型的数据,需要先转换为 float 类型才能赋值给变量 f。再如:

    int n = f;
    

    f 是 float 类型的数据,需要先转换为 int 类型才能赋值给变量 n。
    在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型转换为左边变量的类型,这可能会导致数据失真,或者精度降低;所以说,自动类型转换并不一定是安全的。对于不安全的类型转换,编译器一般会给出警告。

  1. 在不同类型的混合运算中,编译器也会自动地转换数据类型,将参与运算的所有数据先转换为同一种类型,然后再进行计算。转换的规则如下:
    转换按数据长度增加的方向进行,以保证数值不失真,或者精度不降低。例如,int 和 long 参与运算时,先把int 类型的数据转成 long 类型后再进行运算。
    所有的浮点运算都是以双精度进行的,即使运算中只有 float 类型,也要先转换为 double 类型,才能进行运算。
    char 和 short 参与运算时,必须先转换成 int 类型。
    自动类型转换示例:
#include<stdio.h>
int main() {
float PI = 3.14159;
int s1, r = 5;
double s2;
s1 = r * r * PI;
s2 = r * r * PI;
printf("s1=%d, s2=%f\n", s1, s2);
return 0;
}

运行结果:

s1=78, s2=78.539749

在计算表达式 rrPI 时,r 和 PI 都被转换成 double 类型,表达式的结果也是 double 类型。但由于 s1 为整型,
所以赋值运算的结果仍为整型,舍去了小数部分,导致数据失真。

强制类型转换

自动类型转换是编译器根据代码的上下文环境自行判断的结果,有时候并不是那么“智能”,不能满足所有的需求。如果需要,程序员也可以自己在代码中明确地提出要进行类型转换,这称为强制类型转换。
自动类型转换是编译器默默地、隐式地进行的一种类型转换,不需要在代码中体现出来;强制类型转换是程序员明确提出的、需要通过特定格式的代码来指明的一种类型转换。换句话说,自动类型转换不需要程序员干预,强制类型转换必须有程序员干预。

强制类型转换的格式为:

(type_name) expression

type_name 为新类型名称,expression 为表达式。例如:

(float)a; //将变量 a 转换为 float 类型
(int)(x + y); //把表达式 x+y 的结果转换为 int 整型
(float)100; //将数值 100(默认为int类型)转换为 float 类型

下面是一个需要强制类型转换的经典例子:

#include <stdio.h>
int main() {
int sum = 103; //总数
int count = 7; //数目
double average; //平均数
average = (double)sum / count;
printf("Average is %lf!\n", average);
return 0;
}

运行结果:

Average is 14.714286!

sum 和 count 都是 int 类型,如果不进行干预,那么 sum / count 的运算结果也是 int 类型,小数部分将被丢弃;虽然是 average 是 double 类型,可以接收小数部分,但是心有余力不足,小数部分提前就被“阉割”了,它只能接收到整数部分,这就导致除法运算的结果严重失真。
既然 average 是 double 类型,为何不充分利用,尽量提高运算结果的精度呢?为了达到这个目标,我们只要将sum 或者 count 其中之一转换为 double 类型即可。上面的代码中,我们将 sum 强制转换为 double 类型,这样sum / count 的结果也将变成 double 类型,就可以保留小数部分了,average 接收到的值也会更加精确。

在这段代码中,有两点需要注意:

  1. 对于除法运算,如果除数和被除数都是整数,那么运算结果也是整数,小数部分将被直接丢弃;如果除数和被除数其中有一个是小数,那么运算结果也是小数。
  2. ( )的优先级高于/,对于表达式(double) sum / count,会先执行(double) sum,将 sum 转换为 double 类型,然后再进行除法运算,这样运算结果也是 double 类型,能够保留小数部分。注意不要写作(double) (sum /count),这样写运算结果将是 3.000000,仍然不能保留小数部分。

类型转换只是临时性的

无论是自动类型转换还是强制类型转换,都只是为了本次运算而进行的临时性转换,转换的结果也会保存到临时的内存空间,不会改变数据本来的类型或者值。请看下面的例子:

#include <stdio.h>
int main() 
{
double total = 400.8; //总价
int count = 5; //数目
double unit; //单价
int total_int = (int)total;
unit = total / count;
printf("total=%lf, total_int=%d, unit=%lf\n", total, total_int, unit);
return 0;
}

运行结果:

total=400.800000, total_int=400, unit=80.160000

注意看第 6 行代码,total 变量被转换成了 int 类型才赋值给 total_int 变量,而这种转换并未影响 total 变量本身的类型和值。如果 total 的值变了,那么 total 的输出结果将变为 400.000000;如果 total 的类型变了,那么 unit的输出结果将变为 80.000000。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南荒×

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值