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

本文主要是介绍最最最详细的C语言教程笔记零起步(6)进阶必备 同笔者一起学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C语言教程笔记

  • 十二. 运算符与表达式
    • 1. 表达式
      • 1.1 什么是表达式?
      • 1.2 表达式的结果
      • 1.3 表达式语句
    • 2. 加法运算符 +
    • 3. 减法运算符 -
    • 4. 符号运算符 +、-
    • 5. 乘法运算符 *
    • 6. 除法运算符 /
      • 6.1 整型无法整除问题
    • 7. 求余运算符 %
    • 8. 赋值运算符 =
      • 8.1 赋值与初始化的区别
      • 8.2 求一个赋值表达式的结果
      • 8.3 不能给常量赋值
    • 9. 自增、自减运算符
      • 9.1 前缀模式
      • 9.2 后缀模式
    • 10. 自增、自减表达式何时操作运算对象
      • 10.1 Visual Studio的表达式求值过程
      • 10.2 GCC的表达式求值过程
      • 10.3 表达式操作运算对象最晚时机
    • 11. 一元运算符,二元运算符
    • 12. 运算符优先级
  • 十三. 类型转换
    • 1. 判断数据类型的小技巧
    • 2. 同类型之间进行运算
      • 2.1 有符号整型同类型
      • 2.2 无符号整型同类型
      • 2.3 浮点同类型
      • 2.4 同类型运算的结果
    • 3.不类型之间进行运算
      • 3.1 有符号整型不同类型
      • 3.2 无符号整型不同类型
      • 3.3 混合整型类型
      • 3.4 浮点不同类型
      • 3.5 浮点整型混合
    • 4. 自动类型转换
    • 5. 整型运算的注意点
    • 6. 强制类型转换
    • 7. 赋值造成的类型转换
  • 十四. 关系运算符与逻辑运算符
    • 1. 关系运算符
      • 1.1 大于 > 和小于 <
      • 1.2 大于等于 >= 和 小于等于 <=
    • 2. 等于 == 和 不等于 !=
    • 3. 逻辑运算符
      • 3.1 逻辑或 || 和 逻辑与 &&
      • 3.2 逻辑非 !
    • 4.运算符优先级

十二. 运算符与表达式

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;

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

图片来源:你好编程

这篇关于最最最详细的C语言教程笔记零起步(6)进阶必备 同笔者一起学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/392124

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss