知识点#
2.1 常量, 变量, 整形, 实型, 字符型#
- @ 数据类型图
- ![[白板/P1 数据类型.canvas|P1 数据类型]]
2.1.1 如何创建基本的能运行的 C 程序#
2.1.2 C 语言的数据类型#
| 数据类型 | 32 位系统(字节) | 64 位系统 | 最小值 | 最大值 |
|---|---|---|---|---|
char | 1 | 1 | -128 | 127 |
short | 2 | 2 | -32767 | 32768 |
unsigned short | 2 | 2 | 0 | 65536 |
int | 4 | 4 | -2147483648 | 2147483647 |
unsigned int | 4 | 4 | 0 | 4294967295 |
float | 4 | 4 | ||
double | 8 | 8 | ||
long | 4 | 8 | -2147483648 | 2147483647 |
long long | 8 | 8 | -9223372036854775807 | 9223372036854775808 |
unsigned long long | 8 | 8 | 0 | 18446744073709551615 |
2.1.3 常量和变量#
[!tip] 常量和变量
常量: ==在程序运行过程中, 其值不能被改变的量==
- 整形常量
- 浮点型(实型)常量
- 字符常量: 用一对单引号包含起来的一个字符, 如`a`
变量: ==其值可以改变的量==
- ! 变量肯定会有一个变量名, 在内存中会占用一定的存储空间,变量名就是一个标识符,并且大小写敏感
@ 标识符: 由字母, 数字, 下划线三种字符组成, 并且第一个字符为字母或者下划线
- ! 第一个字符绝对不能是数字
@ 保留字: 系统保留起来, 有特殊用途
- ! 不能将保留字作为标识符来使用
变量的定义#
[!tip] 定义变量
- ! 定义变量的声明格式
类型名 变量名 = 变量初值; int a = 0;
2.1.4 整型数据#
[!tip] 整型数据
- 十进制数 - $
%d默认显示十进制数- 八进制数: 以
0开头的数字是八进制数- 十六进制数:==以
0x开头的数是十六进制数==
整型变量的分类#
- 基本型:
int - 短整型:
short int, 简写short - 长整型:
long int, 简写long - 无符号型:
unsigned intunsigned shortunsigned long
- ! 无符号整数,不能存放负数, 所以无符号型存放的数据范围比带符号整形变量存放的数字范围大一倍
- %
sizeof()运算符可以计算变量的数据类型的大小, 但是无法计算变量的具体大小
int a;
printf("%d字节",sizeof(a));
// 输出: 4字节
整型变量的定义#
int a = 0;
int a = b = c = 0;
常量的类型#
[!Note]
- % 在一个常数后面加一个字母
U或u, 表示该常数用无符号整型方式存储, 相当于unsigned int- % 在一个常数后面加一个字母
L或l, 表示该常数用长整型方式存储, 相当于long- % 在一个常数后面加一个字母
F或f, 表示该常数用浮点方式存储, 相当于float- ! 常量的类型并不会改变常量赋值的变量的数据类型
int a = 23.12F; //变量a依旧是int型
2.1.5 实型数据#
- @ 实型数据: 简称实数, 在 C 语言中称为==浮点数 (带小数部分的数)==
实型常量的两种表示形式#
- 十进制数表示形式:
0.12,3.14159 - 指数表示形式:
168E3等价于168×10³=16800.0- 字母
E可以大写也可以小写 168E+2等价于168×10²168E-8等价于168×10⁻⁸
- 字母
实型变量的分类#
- % 单精度:
float类型, 占 4 字节 - % 双精度:
double类型, 占 8 字节
实型变量的定义#
float d, e, f;
double i, k;
精度问题#
[!tip] 浮点数精度
float类型: 提供 7 位有效数字double类型: 提供 15-16 位有效数字- ! 浮点数在内存中以指数形式存储, 能够存储的数据范围很大
类型 取值范围 float3.4E-38~3.4E+38double1.7E-308~1.7E+308
- ! 将十进制数赋给实型变量时, 会先转换成二进制存储, 再转换回十进制显示, 这个过程可能导致精度丢失
float af = 0.51; // 实际显示可能是 0.509999990
2.1.6 字符型数据#
字符常量#
- @ 字符常量: 用单引号包含起来的一个字符, 如
'a','$' - ! 单引号中只能放一个字符, 放多个字符无法得到正确结果
转义字符#
[!tip] 转义字符 转义字符是以
\开头的字符序列, 将反斜杠后面的字符转变成另外一种含义
| 转义字符 | 含义 |
|---|---|
\n | 换行 |
\t | 制表符(Tab键) |
\\ | 反斜杠 |
\' | 单引号 |
\" | 双引号 |
\ddd | 1-3位八进制数所代表的字符 |
\xhh | 1-2位十六进制数所代表的字符 |
\0 | 空字符(字符串结束标记) |
printf("abc\ndef\'ghi\"jkl");
// 输出:
// abc
// def'ghi"jkl
字符变量#
- @ 字符变量: 用来存放字符常量, 只能存一个字符
- ! 字符变量在内存中只占 1 字节
char c1, c2, c3;
c1 = 'a';
c2 = 'b';
c3 = '\''; // 转义字符, 代表单引号
字符与 ASCII 码#
- @ ASCII 码: 范围处于
0~127之间的一个整数 - ! 字符数据在内存中以 ASCII 码形式存储, 与整型数据存储形式类似
- ! 字符型数据和整型数据可以互通使用
| 十进制(ASCII码) | 字符 | 十进制(ASCII码) | 字符 |
|---|---|---|---|
| 97 | a | 98 | b |
| 99 | c | 100 | d |
| 65 | A | 66 | B |
char c1, c2;
c1 = 97; // 相当于 c1 = 'a'
c2 = 98; // 相当于 c2 = 'b'
printf("c1=%c, c2=%c\n", c1, c2); // c1=a, c2=b
printf("c1=%d, c2=%d\n", c1, c2); // c1=97, c2=98
2.1.7 字符串常量#
- @ 字符串常量: 用双引号包含起来的一堆字符, 如
"Hello world!","zhangsan" - ! 不要混淆字符常量和字符串常量:
'a'是字符常量,"a"是字符串常量
字符与字符串的区别#
- ! 字符
'a'在内存中占 1 字节 - ! 字符串
"a"在内存中占 2 字节 (包含'a'和'\0') - @ 字符串末尾自动添加
'\0'作为字符串结束标记
char c;
c = 'a'; // 正确
c = "a"; // 错误! 不能把字符串赋值给字符变量
- !
'\0'如果出现在printf中进行输出, 不会输出任何内容, 而是标记字符串结束
printf("abc\0def"); // 输出: abc,系统自动截断
2.1.8 不同类型数据混合运算#
[!tip] 自动类型转换
- ! 不同类型数值变量进行混合运算时, 系统会尝试将它们的变量类型统一, 选取能表达最大数字的类型作为目标类型
- ! 转换规则: 从低类型往高类型转换
高 double
↑
float
↑
unsigned long
↑
long
↑
unsigned int
↑
int
↑
char, short
低
- %
char和short参与运算时, 必须先转成int - %
float参与运算时, 必须先转成double
2.2 算术运算符和表达式#
- @ 运算符图
- ![[白板/P2 运算符.canvas|P2 运算符]]
2.2.1 C 语言的运算符分类#
| 序号 | 名称 | 内容 |
|---|---|---|
| 1 | 算术运算符 | +, -, *, /, % |
| 2 | 关系运算符 | >, <, ==, >=, <=, != |
| 3 | 逻辑运算符 | !, &&, || |
| 4 | 位运算符 | <<, >>, ~, |, ^, & |
| 5 | 赋值运算符 | = 以及复合赋值运算符 |
| 6 | 条件运算符 | ?: |
| 7 | 逗号运算符 | , |
| 8 | 指针运算符 | *, & |
| 9 | 求字节数运算符 | sizeof() |
| 10 | 强制类型转换运算符 | (类型名) |
| 11 | 成员变量运算符 | ., -> |
| 12 | 下标运算符 | [] |
2.2.2 算术运算符和算术表达式#
[!tip] 基本算术运算符
+加法, 如3+5-减法, 如5-2,2-5*乘法, 如3*9/除法, 如5/3(整数相除会舍弃小数部分)%取余(模运算), 两侧都要求为整型数, 如7%4=3
printf("5 + 2 = %d\n", 5 + 2); // 5 + 2 = 7
printf("5 - 2 = %d\n", 5 - 2); // 5 - 2 = 3
printf("2 - 5 = %d\n", 2 - 5); // 2 - 5 = -3
printf("3 * 9 = %d\n", 3 * 9); // 3 * 9 = 27
printf("5 / 3 = %d\n", 5 / 3); // 5 / 3 = 1 (舍弃小数)
printf("7 %% 4 = %d\n", 7 % 4); // 7 % 4 = 3
2.2.3 运算符优先级#
- ! 优先级规则: 先乘除, 后加减, 优先级相同则从左到右
- ! 记不住优先级时, 用
()将需要优先计算的内容括起来
printf("2 + 3 * 5 = %d\n", 2+3*5); // 2+15=17
printf("2 + 8 - 5 = %d\n", 2+8-5); // 10-5=5
printf("(3+2) * 8 = %d\n", (3+2)*8); // 5*8=40
运算符优先级表#
| 优先级 | 运算符 | 含义 | 对象个数 | 结合方向 |
|---|---|---|---|---|
| 1 | () [] -> . | 圆括号/下标/成员 | 从左到右 | |
| 2 | ! ~ ++ -- - (类型) * & sizeof | 单目运算符 | 1个 | 从右到左 |
| 3 | * / % | 乘除取余 | 2个 | 从左到右 |
| 4 | + - | 加减 | 2个 | 从左到右 |
| 5 | << >> | 左移右移 | 2个 | 从左到右 |
| 6 | < <= > >= | 关系运算符 | 2个 | 从左到右 |
| 7 | == != | 等于不等于 | 2个 | 从左到右 |
| 8 | & | 按位与 | 2个 | 从左到右 |
| 9 | ^ | 按位异或 | 2个 | 从左到右 |
| 10 | | | 按位或 | 2个 | 从左到右 |
| 11 | && | 逻辑与 | 2个 | 从左到右 |
| 12 | || | 逻辑或 | 2个 | 从左到右 |
| 13 | ?: | 条件运算符 | 3个 | 从右到左 |
| 14 | = += -= *= /= %= | 赋值运算符 | 2个 | 从右到左 |
| 15 | , | 逗号运算符 | 从左到右 |
2.2.4 强制类型转换运算符#
- @ 强制类型转换: 将一个表达式转换成所需要的类型
- ! 一般形式:
(类型名)(表达式)
(double)a // 将a转换成double型
(int)(x+y) // 将x+y的值转换成int型
(float)(5%3) // 将5%3的结果转换成float型
- ! 强制类型转换得到一个所需类型的中间变量, 原来变量的类型没有发生变化
float x = 3.6;
int i;
i = (int)x; // i = 3, 但x依旧是float类型
printf("x=%f, i=%d\n", x, i); // x=3.600000, i=3
两种类型转换总结#
- % 自动类型转换: 混合运算时系统自动进行, 如
3+5.8 - % 强制类型转换: 当自动类型转换无法达到目的时使用, 如
(int)x%3
2.2.5 自增和自减运算符#
[!tip] 自增自减运算符
++自增运算符: 使变量值增加 1--自减运算符: 使变量值减少 1- ! 都是单目运算符, 只能用于变量, 不能用于常量或表达式
使用口诀#
++i先加 1 后使用--i先减 1 后使用i++先使用后加 1i--先使用后减 1
单独使用#
int i = 8;
i++; // i = 8 + 1 = 9
i--; // i = 9 - 1 = 8
++i; // i = 8 + 1 = 9
--i; // i = 9 - 1 = 8
printf("i = %d\n", i); // i = 8
在表达式中使用#
int i = 3;
printf("j = %d\n", ++i); // j = 4, 先加后用
i = 3;
printf("j = %d\n", i++); // j = 3, 先用后加
- ! 自增自减运算符常用于循环语句中循环变量自增或自减
2.3 赋值运算符和逗号运算符#
- @ 赋值运算符图
- ![[白板/P3 赋值运算符.canvas|P3 赋值运算符]]
2.3.1 赋值运算符和赋值表达式#
- @ 表达式:用运算符串起来的一个式子
赋值运算符#
- @ 赋值运算符:
=, 含义是将等号右边的值赋给等号左边的变量 - ! 等号左边必须是一个变量
int a;
a = 5;
a = 6.5; // 将实型数据给整型变量, 小数部分被舍弃, a = 6
a = 18+50; // 先计算右边表达式, 再赋值, a = 68
赋值原则#
- ! 赋值符号左侧和右侧的数据类型应该相同
- ! 类型不同时可用强制类型转换, 但要确保不会造成数据溢出
int a;
a = 1000000 * 1000000; // 溢出! 结果不可预料
复合赋值运算符#
- @ 在赋值运算符
=之前增加其他运算符, 构成复合赋值运算符
a += 3; // 等价于 a = a + 3
x *= y+8; // 等价于 x = x * (y+8)
x %= 3; // 等价于 x = x % 3
- ! 复合赋值运算符的优先级比
+低, 右侧是一个整体
赋值表达式的值#
- @ 赋值表达式本身是有值的, 值就是赋值运算符右侧的值
int a;
printf("a=5这个赋值表达式的值是%d\n", a=5); // 值是5
- ! 赋值运算符的结合顺序是从右到左
int a, b;
a = b = 5; // 5赋给b, b=5的值为5, 再赋给a
2.3.2 逗号运算符和逗号表达式#
- @ 逗号运算符:
,, 是优先级最低的运算符 - @ 逗号表达式: 用逗号将两个表达式连接起来
- ! 一般形式:
表达式1, 表达式2 - ! 求解过程: 先求解表达式1, 再求解表达式2, 整个表达式的值是表达式2的值
int a;
a = (4,5); // a = 5, 必须加()因为逗号优先级最低
a = (3+5, 6+8); // a = 14
a = 3*5, a*4; // 表达式值为60, 先计算a=15, 再计算a*4
扩展形式#
- ! 多个表达式用逗号连接:
表达式1, 表达式2, 表达式3, ..., 表达式N - ! 整个表达式的值是表达式N的值
int x, a;
x = (a=3, 6*3); // a = 3, x = 18
x = a = 3, 6*a; // a = 3, x = 3, 逗号表达式的结果18未被使用
int result = (x = a = 3, 6*a); // result = 18
- ! 并非任何出现逗号的地方都是逗号表达式, 如
printf("%d,%d,%d", 3, 4, 5);中的3,4,5是函数参数

