最最最详细的C语言教程笔记零起步(6)进阶必备 同笔者一起学习

十二. 运算符与表达式

1. 表达式

1.1 什么是表达式?

运算符往往需要与运算对象一起使用才有意义。例如:
5 + 10
其中,5与10是 运算对象 ,+为 运算符 。
在C语言中,一个或多个运算对象与零个或多个运算符组成表达式。下面几个都是表达式:

100
5 + 10
a / b
a * 10 / b + c

如上的例子可以看出,100也是一个正确的表达式,虽然它只有运算对象而没有运算符。

1.2 表达式的结果

printf("%d\n", 5 + 10);

运算符与运算对象进行运算操作必然产生一个结果,因此每个表达式都有一个结果。例如上面的表达 式 5 + 10 的结果为15。

值15被传入printf后,在控制台上打印出字符15。

1.3 表达式语句

表达式后面加上分号构成表达式语句

C语言中表达式不能单独存在,必须以表达式语句的形式存在。
例如:

100; 
5 + 10; 
a / b; 
a * 10 / b + c;

那么下面的表达式5+10呢?它为什么可以没有分号。

printf("%d\n", 5 + 10);

因为 5 + 10 是一个子表达式,函数名加上括号运算符,构成了一个函数调用表达式。 所以, 5 + 10 为函数调用表达式的子表达式,而函数调用表达式后面加了分号了。
当然函数调用表达式也有一个表达式结果,这个结果就是函数的返回值了。

2. 加法运算符 +

+ 为加法运算符,它左右边各需要一个运算对象,构成 加法运算符表达式 。

表达式结果:加法表达式的结果为左右表达式结果相加。

int a, b; 
a = 200; 
b = 100; 
a + b;  //  表达式结果为300

3. 减法运算符 -

- 为减法运算符,它左右边各需要一个运算对象,构成 减法运算符表达式 。

表达式结果:减法表达式的结果为左右表达式结果相减。

int a, b; 
a = 200; 
b = 100; 
a - b;  //  表达式结果为100

4. 符号运算符 +、-

+ 和 - 为符号运算符。

+ 用于标明一个表达式的正负
- 用于改变一个表达式的正负。

与加减运算符不同的是,它仅需要在运算符右边有一个运算对象。
表达式结果:

+ 号表达式的结果为右边运算对象的值。

- 号表达式的结果为右边运算对象值的相反数。

+100;   
//  表达式结果为100 -100;  
//  表达式结果为-100

用于改变表达式的正负:

int a = 100; -a; 
//  表达式结果为-100

请注意:+不能改变表达式的正负,请使用负负得正。

int a = -100; 
+a; //  表达式结果为-100
-a; //  表达式结果为100

5. 乘法运算符 *

*为乘法运算符,它左右边各需要一个运算对象,构成乘法运算符表达式 。

表达式结果:乘法表达式的结果为左右表达式结果相乘。 * 是乘法运算符,注意不要误用为字母x

int a, b; 
a = 200; 
b = 100; 
a * b;      //  表达式结果为20000

6. 除法运算符 /

/ 为除法运算符,它左右边各需要一个运算对象,构成 除法运算符表达式 。

表达式结果:除法表达式的结果为左运算对象除以右运算对象

int a, b; 
a = 200; 
b = 100; 
a / b;      //  表达式结果为2

6.1 整型无法整除问题

对于除法,请特别注意整型无法整除时,出现浮点类型数据的问题。

int a, b, c; 
a = 5; 
b = 2; 
c = a / b;

a 的值为 5 , b 的值为 2 。那么 5 除以 2 ,应该等于 2.5 。

但是,使用 int 来接收 2.5 好像不太对,那我们把 c 改为 float 或 double 。

int a, b; 
a = 5; 
b = 2; 
float c; 
c = a / b; 
printf("%f\n", c);

在这里插入图片描述
为什么结果依然不对呢?

在C语言里面,整型与整型运算的结果,依然是一个整型。结果的小数部分被丢弃,这一过程被称作截 断。a / b后,结果仍然是一个整型,数值已经被截断了,这时候,我们再赋给一个浮点型的c。也只能 是整数2转成浮点2.0了,没有起到效果。
那我们将a,b,c都改为float,这样就不会出现截断了。a,b将会进行浮点运算,结果也是一个浮点数 类型float。

#include <stdio.h>
 int main()
{
    int a, b;
    a = 5;
    b = 2;
    float c;
    c = a / b;
    printf("%f\n", c);
    return 0;
}

7. 求余运算符 %

% 为求余运算符,它左右边各需要一个运算对象,构成 求余运算符表达式 。 表达式结果:求余表达式的结果为左运算对象除以右运算对象的余数。 例如:10%3,10除以3,等于3余1。

int a, b; 
a = 10; 
b = 3; 
a % b;  //  表达式结果为1

8. 赋值运算符 =

a = 100;    //  赋值表达式语句

= 为赋值运算符,它左右各需要一个运算对象,构成 赋值运算符表达式 。
赋值表达式既然也是一个表达式,类似于上面提到的各种表达式,赋值表达式也有一个运算结果。赋值表达式的结果为等号右边的运算对象的值。例如,赋值表达式 a = 100; 的结果为100。除了获得表达式 结果以外,赋值表达式还会将等号右边运算对象的值,传递给左边的运算对象

8.1 赋值与初始化的区别

int a = 100;    //  =表示初始化,不是赋值运算符 
a = a + 150;    //  赋值运算符,将右边的表达式结果赋值给左边的变量a。

在上面的代码中,第一行代码声明了一个变量a。请注意,声明变量时并将它初始化为100所用的 = 号, 不是赋值运算符,而是变量初始化。虽然初始化和赋值很像,但是 = 号左边并不是一个单纯的变量,而是变量的声明。你可以借此来区别它们。

8.2 求一个赋值表达式的结果

让我们来求一下上面赋值表达式的结果吧:

表达式 a = a + 50 是一个复合表达式,先求得子表达式 a + 50 的结果,为150。再求表达式 a = 150 的 结果,即 150 。另外,赋值表达式除了计算出表达式的结果外,还会将 150 赋值给变量 a 。

8.3 不能给常量赋值

最后,给常量赋值是错误的,因为常量不能被更改。下面几种赋值是错误的:

"Hello" = "HelloWorld"; 
'a' = 'b'; 
100 = 200;

9. 自增、自减运算符

++ 为指自增运算符, - - 为自减运算符。它们仅需要运算符左边或右边有一个运算对象即可。
运算符置于左边被称作前缀模式。
例如: ++i --i 。 运算符置于右边被称作后缀模式。例如: i++ i- - 。

9.1 前缀模式

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

在这里插入图片描述前缀模式表达式结果:
++ 与右运算对象构成前缀自增表达式,表达式结果为运算对象值加1。 - - 与右运算对象构成前缀自减表达式,表达式结果为运算对象值减1。

与赋值表达式类似,自增、自减表达式除了计算出表达式结果,也会对运算对象本身产生操作。将运算对象进行自增或自减。

前缀模式对运算对象的操作
自增表达式:将运算对象加1。
自减表达式:将运算对象减1。

因此printf函数输出的值为11和9。其后,再打印a,b的值,可以发现它们分别被加1和减1了。

9.2 后缀模式

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

在这里插入图片描述
后缀模式表达式结果
++ 与左运算对象构成后缀自增表达式,表达式结果为运算对象值。 - - 与左运算对象构成后缀自减表达式,表达式结果为运算对象值

和前缀模式一样,后缀模式也会对运算对象本身产生操作。将运算对象进行自增或自减。

后缀模式对运算对象的操作
自增表达式:将运算对象加1。
自减表达式:将运算对象减1。

因此printf函数输出的值为10和10。其后,再打印a,b的值,可以发现它们分别被加1和减1了。

10. 自增、自减表达式何时操作运算对象

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

在这里插入图片描述同一段代码,居然在不同的编译器下出现了不同的结果。
vs执行编译的结果为4 3。
gcc编译执行的结果为4 6。
我们可以看出变量a被后缀自加了3次,在下一行打印a的时候,结果都是4。但是,两种编译器对于何时 操作运算对象本身却有不同理解。

10.1 Visual Studio的表达式求值过程

  1. 第一个a++:a的值为1,后缀自加表达式结果为1,此外不做其他操作。
  2. 第二个a++:a的值为1,后缀自加表达式结果为1,此外不做其他操作。
  3. 第三个a++:a的值为1,后缀自加表达式结果为1,此外不做其他操作。
  4. 执行上面三次后缀自加累积的对运算对象的操作a + 3 = 4。

最终:b的值为表达式结果相加1 + 1 + 1 = 3,a的值为4。

10.2 GCC的表达式求值过程

  1. 第一个a++:a的值为1,后缀自加表达式结果为1,求值完成后立即操作运算对象。a的值变为2。
  2. 第二个a++:a的值为2,后缀自加表达式结果为2,求值完成后立即操作运算对象。a的值变为3。
  3. 第三个a++:a的值为3,后缀自加表达式结果为3,求值完成后立即操作运算对象。a的值变为4。

最终:b的值为表达式结果相加1 + 2 + 3 = 6,a的值为4。

10.3 表达式操作运算对象最晚时机

某些表达式除了求表达式结果以外,还会对运算对象产生操作。例如:赋值和自增、自减运算符。而对 运算对象产生操作的时机却在不同编译器里,有不同的发生时机。

在这个例子里,GCC每完成一个子表达式的求值,即对运算对象发生操作。而在VS里面,所有对运算 对象的操作,累积到所有子表达式求值完成后进行。

对运算对象的操作没有固定的发生时机,只有一个最晚时机。

表达式操作运算对象最晚时机为完整表达式求值结束后,进入下一步之前。完整表达式即它不是任何一 个表达式的子表达式。例如: b = a++ + a++ + a++; 为一个完整表达式,而 a++ 为它的一个子表达式。

因此,编译器只要保证在这个表达式结束并进入下一步操作之前,完对运算对象的操作即可。

前缀模式和后缀模式都会受到影响。例如: b = ++a + ++a + ++a; 在不同编译器下,也可能出现不同的 运算结果。

为了避免写出这种在不同编译器下可能造成不同结果的代码。请不要在一个表达式中,重复对一个变量 进行自增或自减

11. 一元运算符,二元运算符

一元运算符:只有一个运算对象的运算符。例如:自增运算符 ++ ,自减运算符 – 。
二元运算符:有两个运算对象的运算符。例如:赋值运算符 = ,加法运算符 + 。

12. 运算符优先级

C语言的四则运算符优先级和数学中的一致。先算括号里面的,先乘除后加减。

#include <stdio.h>
 int main() 
{     
     int a, b;     
     a = 10 * 2 + 4 * 3;     
     b = 10 * (2 + 4) * 3;     
     printf("%d %d", a, b);     
     return 0; 
}

在这里插入图片描述

优先级顺序从高到低如下表所示:

优先级运算符
1()
2! ++ - -
3* / %
4+ -
5< <= > >=
6== !=
7&&
8逻辑运算符或
9= += -= *= /= %=

下图是运算符优先级表格:
在这里插入图片描述
在这里插入图片描述
运算符优先级表格

点个赞吧♥

十三. 类型转换

类型转换,这次教你永不出错的办法
在编码过程中,我们肯定会遇到一些类型相互转化的问题。这一节当中,我们就来讨论类型的相互转化。

1. 判断数据类型的小技巧

在开始之前,先介绍一个小技巧,用于判断某一个数据对象的类型。

#include <stdio.h> 
 int main() 
{     
 //  一个整型指针变量p     
 int* p;     
 //  各式各样的类型     
 char c;     
 short s;     
 int n;     
 long l;     
 float f;     
 double d;     
 //  将整型赋值给指针类型     
 p = c;     
 p = s;     
 p = n;     
 p = l;     
 p = f;     
 p = d;    
  return 0; 
}

首先,我们定义一个整型指针变量 p 。注意,这里的 int 后面加了一个 * ,说明它是一个整型指针变 量。我们先不管什么是指针变量,大家只要知道,指针变量和整型、浮点这些数据类型是不能相互赋值的。

由于它们无法相互赋值,所以编译器会提示报错信息。
在这里插入图片描述从上到下,依次是赋值运算符无法将char、short、int、long、float、double转化为整型指针变 量 int * 。

错误提示与我们定义的变量类型一致,说明这个提示是准确的。好的,那下面我们就可以通过这个小技巧来研究一下,类型与类型之间进行运算,到底会发生什么样的变化呢?

2. 同类型之间进行运算

我们将一步一步探究运算会怎样改变数据对象的类型。首先,我们先了解同类型之间的数据对象进行运 算,将会产生怎样的结果。

2.1 有符号整型同类型

#include <stdio.h>
 int main() 
{     
    //  一个整型指针变量p     
    int* p;     //  各式各样的类型     
    char c;     
    short s;     
    int n;     
    long l;     
    p = c + c;  // char + char = int     
    p = s + s;  // short + short = int     
    p = n + n;  // int + int = int     
    p = l + l;  // long + long = long     
    return 0; 
}

在这里插入图片描述c + c,char同类型运算,结果是一个int类型。
s + s,short同类型运算,结果是一个int类型。
n + n,int同类型运算,结果是一个int类型。
l + l,long同类型运算,结果是一个long类型。

在C语言中,高级别的数据类型能表示的数据范围大于或等于低级的数据类型。

类型级别:
char < short < int < long

有符号整型类型同类型运算中:
比int低级的类型,都会转换成int,比int高级的类型不变

在这里插入图片描述

2.2 无符号整型同类型

#include <stdio.h>
 int main() 
{     
     //  一个整型指针变量p     
     int* p;     
     //  各式各样的类型     
     unsigned char uc;     
     unsigned short us;     
     unsigned int un;     
     unsigned long ul;     
     p = uc + uc;    // unsigned char + unsigned char = int     
     p = us + us;    // unsigned short + unsigned short = int     
     p = un + un;    // unsigned int + unsigned int = unsigned int     
     p = ul + ul;    // unsigned long + unsigned long = unsigned long     
     return 0; 
}

在这里插入图片描述
uc + uc,unsigned char同类型运算,结果是一个int类型。
us + us,unsigned short同类型运算,结果是一个int类型。
un + un,unsigned int同类型运算,结果是一个unsigned int类型。
ul + ul,unsigned long同类型运算,结果是一个unsigned long类型。

类型级别:
int < unsigned int < unsigned long

无符号整型类型同类型运算中:
比int低级的类型,都会转换成int,比int高级的类型不变。

2.3 浮点同类型

#include <stdio.h>
 int main() 
{    
     //  一个整型指针变量p     
     int* p;     
     //  各式各样的类型     
     float f;     
     double df;     
     p = f + f;      // float + float = float     
     p = df + df;    // double + double = double     
     return 0; 
}

在这里插入图片描述
f + f,float同类型运算,结果是一个float类型。
df + df,double同类型运算,结果是一个double类型。

类型级别:
float < double

浮点类型同类型运算中:
类型不变

2.4 同类型运算的结果

上面探究了同类型之间运算结果的类型。 对于整型,级别低于int的类型会转换成int。而比int高级的类型则不发生变化。 对于浮点,不发生变化。

3.不类型之间进行运算

3.1 有符号整型不同类型

#include <stdio.h>
 int main() 
 {     //  一个整型指针变量p     
     int* p;     
     //  各式各样的类型     
     char c;     
     short s;     
     int n;     
     long l;     
     p = c + s;  // char + short = int     
     p = c + n;  // char + int = int     
     p = c + l;  // char + long = long     
     p = n + l;  // int  + long = long     
     return 0; 
}

c + s,char类型与short类型运算,结果是一个int类型。
c + n,char类型与int类型运算,结果是一个int类型。
c + l,char类型与long类型运算,结果是一个long类型。
n + l,int类型与long类型运算,结果是一个long类型。

类型级别:
char < short < int < long

有符号整型不同类型运算中:
若运算符两边类型均低于int或等于int,那么结果为int。
若有高于int的,那么结果为高于int的等级最高的类型。

在这里插入图片描述

3.2 无符号整型不同类型

#include <stdio.h>
 int main() 
{     
     //  一个整型指针变量p     
     int* p;     
     //  各式各样的类型     
     unsigned char uc;     
     unsigned short us;     
     unsigned int un;     
     unsigned long ul;     
     p = uc + us;    // unsigned char + unsigned short = int     
     p = uc + un;    // unsigned char + unsigned int = unsigned int     
     p = uc + ul;    // unsigned char + unsigned long = unsigned long     
     p = un + ul;    // unsigned int  + unsigned long = unsigned long     
     return 0; 
}

uc + us,unsigned char类型与unsigned short类型运算,结果是一个int类型。
uc + un,unsigned char类型与unsigned int类型运算,结果是一个unsigned int类型。
uc + ul,unsigned char类型与unsigned long类型运算,结果是一个unsigned long类型。
un + ul,unsigned int类型与unsigned long类型运算,结果是一个unsigned long类型。

类型级别:
int < unsigned int < unsigned long

无符号整型不同类型运算中:(同上)
若运算符两边类型均低于int或等于int,那么结果为int。
若有高于int的,那么结果为高于int的等级最高的类型。

在这里插入图片描述

3.3 混合整型类型

#include <stdio.h>
 int main() 
{     
     //  一个整型指针变量p     
     int* p;     
     //  各式各样的类型     
     char c;     
     short s;     
     int n;     
     long l;     
     unsigned char uc;     
     unsigned short us;     
     unsigned int un;     
     unsigned long ul;     
     p = c + uc; // char + unsigned char = int     
     p = s + us; // short + unsigned short = int     
     p = c + n;  // char  + int = int     
     p = c + un; // char + unsigned int =  unsigned int     
     p = n + un; // int  + unsigned int = unsigned int     
     p = n + ul; // int  + unsigned long = unsigned long     
     return 0; 
}

c + uc,char类型与unsigned char类型运算,结果是一个int类型。
s + us,short类型与unsigned short类型运算,结果是一个int类型。
c + n,char类型与int类型运算,结果是一个int类型。
c + un,char类型与unsigned int类型运算,结果是一个unsigned int类型。
n + un,int类型与unsigned int类型运算,结果是一个unsigned int类型。
n + ul,int类型与unsigned long类型运算,结果是一个unsigned long类型。

类型级别:
int < unsigned int < long < unsigned long

混合整型类型运算中:(同上)
若运算符两边类型均低于int或等于int,那么结果为int。
若有高于int的,那么结果为高于int的等级最高的类型。

在这里插入图片描述
从结果看来,同一种类型的无符号等级要高于有符号等级。

3.4 浮点不同类型

#include <stdio.h>
int main()
{
// 一个整型指针变量p
int* p;
// 各式各样的类型
float f;
double df;
p = f + df;
return 0;
}

f + df,float类型与double类型运算,结果是一个double类型。

类型级别:
float < double

浮点不同类型运算中:
结果为运算符两边级别最高的类型。

3.5 浮点整型混合

#include <stdio.h>
  int main() 
 {     
       //  一个整型指针变量p     
       int* p;     
       //  各式各样的类型     
       char c;     
       short s;     
       int n;     
       long l;     
       unsigned char uc;     
       unsigned short us;     
       unsigned int un;     
       unsigned long ul;     
       float f;     
       double df;     
       p = c + f;  // char + float = float     
       p = s + f;  // short + float = float     
       p = n + f;  // int  + float = float     
       p = l + f;  // long + float =  float     
       p = uc + f; // unsigned char + float = float     
       p = us + f; // unsigned short + float = float    
       p = un + f; // unsigned int  + float = float     
       p = ul + f; // unsigned long + float =  float     
       p = c + df; // char + double = double     
       p = s + df; // short + double = double     
       p = n + df; // int  + double = double    
       p = l + df; // long + double =  double     
       p = uc + df;    // char + double = double     
       p = us + df;    // short + double = double     
       p = un + df;    // int  + double = double     
       p = ul + df;    // long + double =  double     
       return 0; 
}

类型级别: 整型类型 < float < double
浮点与整型类型混合运算中: 结果为运算符两边等级最高的类型。

4. 自动类型转换

上面的代码,让我们看到了类型经过运算后,结果的变化。那么造成这种变化的原因是什么呢?

这个原因,我们称之为自动类型转换。C语言会将运算符两边的类型,先经过自动类型转换后,再进行 运算。

那么为什么有时候转换为int,有时候又是long,有时候是float,又有时候是double了呢?

我们总结一下上面观察到的各种转换现象:

运算类型结论
有符号整型同类型比int低级的类型,都会转换成int,比int高级的类型不变
无符号整型同类型比int低级的类型,都会转换成int,比int高级的类型不变
浮点同类型类型不变
有符号整型不同类型若运算符两边类型均低于int或等于int,那么结果为int。若有高于int的,那么结果为高于int的等级最高的类型。
无符号整型不同类型若运算符两边类型均低于int或等于int,那么结果为int。若有高于int的,那么结果为高于int的等级最高的类型。
混合整型不同类型若运算符两边类型均低于int或等于int,那么结果为int。若有高于int的,那么结果为高于int的等级最高的类型。
浮点不同类型结果为高于int的级别最高的类型。
浮点整型混合结果为高于int的等级最高的类型。

综合所有情形,我们可以得到以下结论:
整型之间进行运算:若运算符两边类型均低于int或等于int,那么结果为int。若有高于int的,那么结果 为高于int的等级最高的类型。
整型与浮点进行运算:结果为运算符两边等级最高的类型。
类型级别从低到高依次为:
int < unsigned int < long < unsigned long < float < double。
char,short,unsigned char,unsigned short总是会被转换为int。

5. 整型运算的注意点

整型与整型运算,是不会出现浮点类型的。也就是说,运算结果将丢失小数部分。

#include <stdio.h>
 int main() 
 {     
    int n1, n2;     
    n1 = 5;     
    n2 = 2;    
    printf("%d\n", n1 / n2); 
}

除号运算符两边均为 int , int 与 int 运算,结果是 int 。那我们必须在运算符两边,设置一个浮点型 才行, float 和 double 都可以。根据上面的转换规则,运算符两边均会转换为浮点型进行运算,结果也 是一个浮点型。这样就能保留小数部分了。

#include <stdio.h> 
 int main() 
{     
     int n;     
     float f;     
     n = 5;     
     f = 2;     
     printf("%f\n", n / f); 
}

那我们再思考一下,对于字面常量来说,是不是也存在这种问题呢?

#include <stdio.h>
 int main() 
{     
     printf("%d\n", 5 / 2);      //  int与int运算,结果为int     
     printf("%f\n", 5 / 2.0);    //  int与double运算,结果为double     
     printf("%f\n", 5.0 / 2.0);  //  double与double运算,结果为double 
}

5 / 2,int与int运算,结果为int 5 / 2.0,
int与double运算,结果为double 5.0 / 2.0,
double与double运算,结果为double

确实如此,字面常量也有这个问题。至于字面常量是什么类型,我们可以用上面的小技巧判断一下。

常量的类型可以参考文章变量与常量。

6. 强制类型转换

如果我不想修改上面代码,依旧保持 n1 或 n2 为整型,但是计算结果想要得到浮点型怎么办?

好像以目前我们了解的知识,是无法解答的。因为整型与整型运算是无法得到浮点型的。因此,我们引 入一个新的知识点,强制类型转换。
使用公式:
(类型)需要转换的数据对象

#include <stdio.h>
 int main() 
{     
     int n1, n2;     
     n1 = 5;     
     n2 = 2;     
     printf("%f\n", (float)n1 / n2);     
     printf("%f\n", (double)n1 / n2);     
     return 0; 
}

在上面的代码中,我们把 n1 先强制转换为了 float型 , float 再除以 int 。那么结果就是 float 类型 了。 n2 先转换为 double ,再与 int 运算,结果为 double 。
请注意,强制类型转换,并不能影响n1和n2变量原本的类型。它们只是改变了运算时的临时数据对象的 类型。

7. 赋值造成的类型转换

#include <stdio.h>
 int main() 
 {
     int n;     
     char c = 123;     
     n = c;     
     printf("%d %d", c, n);     
     return 0; 
}

上面的代码中,n是int型,c是字符型。我们把char型变量c值给了int型变量n,结果正常。

#include <stdio.h>
 int main() 
 { 
     int n = 123456;     
     char c;     
     c = n;     
     printf("%d %d", c, n);     
     return 0; 
}

如果反过来,把整型赋值给字符型呢?结果是整型变量n存储的数值遭到了丢失。毕竟,字符型的最大 范围是-128到127。

小的整型类型可以赋值给大的,大的整型类型请勿赋值给小的。 除非你有这种特殊需求。

十四. 关系运算符与逻辑运算符

1. 关系运算符

1.1 大于 > 和小于 <

#include <stdio.h>
 int main() 
{ 
     printf("%d\n", 1 > 2);     
     printf("%d\n", 1 < 2);     
     return 0; 
}

表达式结果:
表达式关系成立,表达式结果为真。在C语言中,用1表示真。
表达式关系不成立,表达式结果为假。在C语言中,用0表示假。

例如:
1 < 2,表达式关系成立,表达式结果为真,即1。
1 > 2,表达式关系不成立,表达式结果为假,即0。

1.2 大于等于 >= 和 小于等于 <=

如果希望可以取值到N点,即N点为实心,那么可以使用大于等于或小于等于运算符。

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

因此以下两个表达式均为真。
1 >= 1 //为真 1 <= 1 //为真

下面是一些关系运算符示例:

大于等于:
10 >= 2,真
10 >= 10,真
2 >= 10,假

小于等于:
10 <= 2,假
10 <= 10,真
2 <= 10,真

2. 等于 == 和 不等于 !=

等于运算符以及不等于运算符,用于单纯地判断运算符两边的值是否相等。 由于 = 等号已经被作为赋值运算符,所以相等在C语言里面用 == 来表示,而不相等则使用 != 。

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

10 == 10,10等于10,表达式结果为真。
10 != 10,10不等于10,表达式结果为假。
10 == 12,10等于12,表达式结果为假。
10 != 12,10不等于12,表达式结果为真。

3. 逻辑运算符

我们来看看在C语言里面,怎样表达数轴上的这两个条件。

我们能否使用表达式 2 <= x <=10 来表示呢?
我们使用数值0来检查一下,0不在这个区间内,按理说表达式结果应当为假。
让我们用表达式求值的方法来求一下这个表达式的值。

2 <= 0 <= 10

先计算表达式 2<=0 ,表达式结果为假,即0。

0 <= 10

0 <= 10 ,表达式结果为真,即1。

结果与我们预料的不一致,区间不能这样来表示。 我们想要的是让x,同时满足大于等于2且小于等于10这两个条件,而不是想用它直接求表达式结果。

我们需要结合两个子表达式的结果:

第一个数轴区间:x <= 2 或 x >= 10。
由于数值只要符合任意一个条件就满足要求,所以这里我们用
第二个数轴区间:x >= 2 与 x <= 10。
由于数值要同时符合两个条件才能满足要求,所以这里我们用。 因此,这里必须引入新的运算符,来表达这种情况。

3.1 逻辑或 || 和 逻辑与 &&

逻辑或运算符写法为 ||, 两条竖线。
逻辑与运算符写法为 &&。

第一个数轴区间:(x <= 2) || (x >= 10)。
第二个数轴区间:(x >= 2) && (x <= 10)。

我们在上面加了 () ,确保两边完成之后,再进行 与运算 、 或运算 。然而,事实上,这里不加括号也是可以的。因为 || 和 && 的运算符优先级比关系运算符 >= 、 <= 低,所以按照优先级也会是先计算两边再 进行与或操作。
但是,为了着重一般会加上括号。

接下来,我们再用数值0带入第二个区间,验算一下结果是否为假吧。

(0 >= 2) && (0 <= 10)

0 >= 2 表达式的结果为假, 0 <= 10 表达式结果为真。
逻辑与运算&&,符要求两边均为真,整个表达式结果才为真。
因此表达式结果为假,符合我们的预期。

3.2 逻辑非 !

使用逻辑非运算符,我们可以对当前的结果,取它的反向。

例如,2 != 3,为真,但是如果加上逻辑非之后呢。

#include <stdio.h>
 int main() 
{ 
     printf("%d\n", 2 != 3);     
     printf("%d\n", !(2 != 3));  //  尽量使用多一些的括号清晰地表达意图     
     return 0; 
}

2 != 3,2不等于3,表达式结果为
!(2 != 3),将结果真取反向,表达式结果为

那我们再看看上面的区间,如果被逻辑非之后呢?

(x <= 2) || (x >= 10) 加上逻辑非,!( (x <= 2) || (x >= 10) )
为(x > 2) &&(x <10)

(x >= 2) && (x <= 10)加上逻辑非,!(x >= 2) && (x <= 10)
为(x < 2) || (x >10)

4.运算符优先级

int a; 
int i = 0; 
a = 9 / 3 + 1 * -2 && ++i || !6;

请添加图片描述点个赞吧♥

图片来源:你好编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

没有余地 EliasJie

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

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

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

打赏作者

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

抵扣说明:

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

余额充值