C运算与表达式
# C运算符
# 赋值运算符
赋值运算符即=
号,用于将值存储到某个内存位置。赋值运算符的左边又称为左值,左值需要引用一个存储位置,引用存储位置的最常见方法就是变量名。赋值运算符的右边又称为右值,指需要存储的值。
用于存储值的数据存储区域统称为数据对象。而变量名是标识对象的一种方法。
例如:
// 2赋值给i变量
int i = 2;
// 链式赋值,结果是三者都等于5
int a, b, c;
a = b = c = 5;
// i + 1的结果赋值给i变量
int i = i + 1;
2
3
4
5
6
7
# 二元运算符
为二元运算符,即运算符需要两个运算对象才能完成操作。
// + 加法运算符
i = 1 + 1;
// - 减法运算符
i = 1 - 1;
// * 乘法运算符
i = 2 * 2;
// "/" 除法运算符
i = 2 / 2;
// % 求模运算符(取余)
i = 3 / 2;
// ++ 递增运算符,变量自增1,但区分前缀形式和后缀形式
// 后缀形式:会返回变量的当前值,然后再加1。
i = 1;
a = i++; // 该行执行完后,a为1、i为2
// 前缀形式:会先加1,然后再返回变量值。
i = 10;
a = ++i; // 该行执行完后,a为11、i为11
// -- 递减运算符,同递增,只不过是自减1。
i--;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
另外还有一元运算符(+、-),写在值前面,用来表示正负数,例如:-(2 - 1) = -1
# 表达式
表达式由运算符和运算对象组成。最简单的表达式是一个单独的运算对象,以此为基础可以建立复杂的表达式,最后每个表达式都有一个值。表达式例如:
4
-6
4+21
a*(b + c/d)/20
q = 5*2
x = ++q % 3
q > 3
2
3
4
5
6
7
运算对象可以是常量、变量或二者的组合。一些表达式由子表达式组成。
# 强制类型转换运算符
在需要进行精确的类型转换时,我们可以使用强制类型转换,来避免自动类型转换,尤其是类型降级。
使用强制类型转换只需要在某个量的前面放置用圆括号括起来的类型名即可,该类型名即是希望转换成的目标类型。圆括号和它括起来的类型名构成了强制类型转换运算符,其格式是:(目标数据类型)量
例如:
// 此表达式会将3转化float类型,所以表达式结果为9.0
(float)9
// 此处会先进行运算1.6 + 1.7 = 3.3,然后再将结果转化为int类型,所以最终结果为3
a = (int)(1.6 + 1.7);
// 此处会将1.6和1.7先转化int类型再进行运算,所以最终结果为1 + 1 = 2
a = (int)1.6 + (int)1.7;
2
3
4
5
6
# 关系运算符
关系运算符用于判断两个表达式之间的关系,返回值为1或0,条件成立返回1代表真,条件不成立返回0代表假。
所有的非零值都视为真,只有0被视为假。从C99开始提供专门用于保存真假的_Bool类型,只用来存储1(真)和0(假)。
<
小于
<=
小于或等于
==
等于
>=
大于或等于
>
大于
!=
不等于
# 逻辑运算符
&&
与
||
或
!
非
# 三元运算符
三元运算符是if else的一种便捷写法。
格式:条件表达式 ? 成立返回的表达式值 : 不成立返回的表达式值
例如:
// 此处执行完后a = 1
int a = 3 > 2 ? 1 : 0;
// 同等于如下
int a;
if(3 > 2){
a = 1;
} else {
a = 0;
}
2
3
4
5
6
7
8
9
# 其他赋值运算符
+=、-=、*=、/=、%=
这些表达式会将左测的值与运算符右侧的值进行对应二元符号的运算。
例如:
int i = 1;
// 此处同等于i = i * 2;
i *= 2;
// 同样的同等于i = i + i;
i += i;
2
3
4
5
# C函数
# 定义
函数是一组代码的集合,能够减少代码冗余,并方便我们对代码进行复用,较为规范的C语言函数定义需要在源代码开头声明函数原型,然后再去定义函数。
格式:
// 无返回值或无参数则指定void即可
返回值类型 函数名(形参类型 形参名1, 形参类型 形参名2...) {
代码块...
// 如果无返回值则写return;即可
return 返回值;
}
2
3
4
5
6
例如:
#include <stdio.h> // 导入标准输入输出库
void hello(void); // 声明函数原型
// 定义函数
void hello(void) {
printf("Hello, world!");
return;
}
int main(void) {
hello();
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
如果没有声明函数原型,则main函数需要放到它所调用的函数的下面,才能正常调用。
# 参数
在函数定义过程中声明的参数被称为形式参数,在函数调用过程中传入的参数被称为实际参数。
形式参数
形参在函数名后面的括号中写好形参定义即可。
例如:
void hello(int age, int score){
printf("you age is: %d, score is: %d", age, score);
}
2
3
实际参数
实际参数即调用函数时传入的参数,传入的参数数量需要和形参数量匹配,如果传入的实参和形参的数据类型不匹配,则会将实参转化为形参指定的类型。
例如:
int a = 18;
hello(a, 90);
2
# C循环
# 循环辅助
break;
关键字用于跳出当前循环。
continue;
关键字用于跳过本轮循环,直接进入下一轮循环。循环体代码执行到continue时,本次循环体剩余的代码都将被跳过。
# while循环
while循环用于根据条件判断循环执行某段代码,这段代码需要使用花括号括起来,花括号以及被花括号括起来的部分被称为块。 程序执行到while时会先进行判断,如果条件成立则会执行代码块,执行完再进行一次判断,如果仍然成立则继续循环,直到条件不成立或者在代码块中碰到break关键字为止。
格式:
while(条件表达式){
代码块...
}
2
3
例如:
int i = 1;
while(i < 10){
printf("i is: %d", i);
i++;
}
2
3
4
5
# for循环
C语言的for循环就是能将初始化表达式、条件表达式和更新表达式组合在一处的循环写法,在某些时候比while循环更简洁。另外for循环初始化表达式中声明的变量,仅作用于该循环体内,仅在该循环体内有效。
格式:
// 初始化表达式只会在开始循环前执行一次。可有多个,用逗号隔开。
// 循环条件表达式在开始和每次循环结束都会进行一次判断,成立则继续循环。
// 更新表达式会在每次循环代码块执行完的最后执行一次,一般用来进行自增或自减。可有多个,用逗号隔开。
for(初始化表,循环条件,更新){
代码块...
}
2
3
4
5
6
例如:
#include <stdio.h>
int main(void) {
for(int i = 0; i < 10; i++){
printf("%d\n", i);
}
for (int i = 0, n = 10; i < n; i++, n--) {
printf("%d %d\n", i, n);
}
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
# do while循环
while和for循环都是入口条件循环,也就是在循环前会先判断条件是否要进入循环。而do while则是出口条件循环,先执行一遍循环体的代码,再判断条件是否要继续循环。
格式:
do{
代码块...
}while(条件表达式);
2
3
例如:
int i = 1;
do{
printf("i is: %d", i);
i++;
}while(i < 10);
2
3
4
5
# C流程控制
# if语句
if用于根据条件判断来执行哪些代码,可以进行单分支、双分支、多分支流程控制。要执行的代码可以是一条简单语句、或则是用花括号扩起的复合语句。
格式:
// 单分支,如果条件成立则执行
if(条件表达式){
代码块...
}
// 双分支,如果条件成立则执行代码块1,否则执行代码块2
if(条件表达式){
代码块1...
} else {
代码块2...
}
// 多分支,多分支同样可以使用else,也可以不使用
if(条件表达式1){
代码块1...
}else if(条件表达式2){
代码块2...
}else if(条件表达式3){
代码块3...
}else{
代码块4...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
如果语句没有被花括号括起来,则else会与离它最近的if相匹配,所以为了提高代码可读写,建议都使用花括号。
# switch语句
switch用于根据给定的表达式的值(一般直接使用变量),匹配其值对应的代码块进行执行。
格式:
// 基本写法
switch(表达式){
// 如果表达式值为值1,则执行该代码块
case 值1:
代码块...
// 执行完后需要手动break,否则会继续向下判断,浪费性能
break;
// 也可以指定多个case来判断多个值
case 值2:
代码块...
break;
default:
// default会匹配所有值,它是可选的,一般用于在前面都不匹配时则执行该代码块
// 需要注意的是如果前面匹配的代码块最后没有使用break,则匹配到default时,还会执行一遍default的代码块
代码块...
}
// 多重标签写法
switch(表达式){
// 可指定多个标签进行匹配,此处表示匹配到值1或值2都执行该代码块
case 值1:
case 值2:
代码块...
break;
default:
代码块...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
例如:
int choice;
printf("1.hello 2.what?");
scanf("%d", &choice);
switch(choice){
case 1:
printf("you choice hello");
break;
case 2:
case 3:
case 4:
printf("you choice what?");
break;
default:
printf("you choice is not 1 range 4!");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15