TODO: 前言

数据类型与运算符

# 数据类型

# 常量与变量

# 关键字

C 语言共有 32 个关键字

类型关键字
数据类型 12 个char,short,int,long,float,double,unsigned,signed,struct,union,enum,void
控制语句 12 个if,else,switch,case,default,for,do,while,break,continue,goto,return
存储类 5 个auto,extern,register,static,const
其他 3 个sizeof,typedef,volatile

# 标识符的命名规则

  • 由字母、数字、下划线组成
  • 不能以数字开头
  • 名称意义明确
  • 注意标识符的重复问题
  • 不能使用 C 语言关键字
  • 区分大小写

# 常量

在程序运行过程中值不能改变的量

  • const 数据类型 常量名 const float PI = 3.14

  • 宏定义 #define PI 3.14

注:const 修饰的常量不安全,可以通过指针修改 (C 语言中)

# 变量

变量在程序运行中值可以改变,在使用变量前需先定义

# 声明和定义的区别

声明变量不需要建立存储空间,例: extern int a

定义变量需要建立存储空间,例: int a

# 进制

# 进制在 C 语言中的表示

  • 十进制 int a = 10 //%d

  • 八进制 int a =010 //%o

  • 十六进制 int a = 0x10ac //%x 输出字母小写 %X 输出字母大写

# 内存中的存储方式

# 原码

原码(原始的二进制码)特点

  • 最高位做为符号位,0 表示正,为 1 表示负

  • 其它数值部分就是数值本身绝对值的二进制数

  • 负数的原码是在其绝对值的基础上,最高位变为 1

十进制数原码
+150000 1111
-151000 1111
+00000 0000
-01000 0000

原码表示法简单易懂,与带符号数本身转换方便,只要符号还原即可,但当两个正数相减或不同符号数相加时,必须比较两个数哪个绝对值大,才能决定谁减谁,才能确定结果是正还是负,所以原码不便于加减运算

# 反码

  • 正数:的反码和原码相同
  • 负数:符号位不变,其它部分取反
十进制数反码
+150000 1111
-151111 0000
+00000 0000
-01111 1111

反码运算也不方便,通常用来作为求补码的中间过渡

# 补码

计算机中,数值使用补码存储

  • 正数的原码、反码、补码相同

  • 负数的补码为它的反码加 1

  • 补码符号位不动,其他位求反,最后整个数加 1,得到原码

十进制数补码
+150000 1111
-151111 0001
+00000 0000
-00000 0000

使用补码存储的原因是

  • 统一了零的编码
  • 将符号位和其它位统一处理
  • 将减法运算转变为加法运算
  • 两个用补码表示的数相加时,如果最高位 (符号位) 有进位,则进位被舍弃

# 基本类型

# 整型 int

# 定义

数据类型占用空间
short2 字节
int4 字节
longWindows 为 4 字节,Linux 为 4 字节 (32 位),8 字节 (64 位)
long long8 字节

# 输入输出

打印格式含义
%hd输入输出 short 类型
%d输入输出 int 类型
%l输入输出 long 类型
%ll输入输出 long long 类型
%hu输入输出 unsigned short 类型
%u输入输出 unsigned int 类型
%lu输入输出 unsigned long 类型
%llu输入输出 unsigned long long 类型

# 取值范围

数据类型占用空间取值范围
short2 字节-32768 到 32767 (-215 ~ 215-1)
int4 字节-2147483648 到 2147483647 (-231 ~ 231-1)
long4 字节-2147483648 到 2147483647 (-231 ~ 231-1)
unsigned short2 字节0 到 65535 (0 ~ 216-1)
unsigned int4 字节0 到 4294967295 (0 ~ 232-1)
unsigned long4 字节0 到 4294967295 (0 ~ 232-1)

# 字符型 char

  • 字符型变量用于存储一个单一字符,在 C 语言中用 char 表示,存储字符的 ASCII 码,占用 1 字节,

  • 赋值时需使用单引号括起来 char ch = 'a'

# 定义

数据类型占用空间
char1 字节

# 输入输出

打印格式含义
%c输入输出 char 类型
c
char ch = 'a'
scanf("%c", &ch);
printf("ch = %c\n", ch); // 输出字符
printf("ch = %d\n", ch); // 输出字符的 ASCII 值
printf("CAP ch = %c\n", ch-32); // 小写转大写

# ASCII 码表

ASCII 值控制字符ASCII 值字符ASCII 值字符ASCII 值字符
0NUT32(space)64@96
1SOH33!65A97a
2STX34"66B98b
3ETX35#67C99c
4EOT36$68D100d
5ENQ37%69E101e
6ACK38&70F102f
7BEL39,71G103g
8BS40(72H104h
9HT41)73I105i
10LF42*74J106j
11VT43+75K107k
12FF44,76L108l
13CR45-77M109m
14SO46.78N110n
15SI47/79O111o
16DLE48080P112p
17DCI49181Q113q
18DC250282R114r
19DC351383S115s
20DC452484T116t
21NAK53585U117u
22SYN54686V118v
23TB55787W119w
24CAN56888X120x
25EM57989Y121y
26SUB58:90Z122z
27ESC59;91[123{
28FS60<92/124|
29GS61=93]125}
30RS62>94^126` |
31US63?95_127DEL

ASCII 码由非打印控制字符打印字符组成

  • 非打印控制字符:ASCII 表上的数字 0-31 分配给了控制字符,用于控制像打印机等一些外围设备
  • 打印字符:数字 32-126 分配给了能在键盘上找到的字符,当查看或打印文档时就会出现。数字 127 代表 Del 命令

# 转义字符

转义字符含义ASCII 码值(十进制)
\a警报007
\b退格 (BS) ,将当前位置移到前一列008
\f换页 (FF),将当前位置移到下页开头012
\n换行 (LF) ,将当前位置移到下一行开头010
\r回车 (CR) ,将当前位置移到本行开头013
\t水平制表 (HT) (跳到下一个 TAB 位置)009
\v垂直制表 (VT)011
\\代表一个反斜线字符 ""092
\'代表一个单引号(撇号)字符039
\"代表一个双引号字符034
?代表一个问号063
\0数字 0000
\ddd8 进制转义字符,d 范围 0~73 位 8 进制
\xhh16 进制转义字符,h 范围 09,af,A~F3 位 16 进制
c
printf("%d\n", '\123'); // '\123' 为 8 进制转义字符,0123 对应 10 进制数为 83
printf("%d\n", '\x23'); // '\x23' 为 16 进制转义字符,0x23 对应 10 进制数为 35

注:加粗标注的为不可打印字符

# 数值溢出

当超过一个数据类型能够存放最大的范围时,数值会溢出。有符号位最高位溢出的区别:符号位溢出会导致数的正负发生改变,但最高位的溢出会导致最高位丢失

数据类型占用空间取值范围
char1 字节-128 到 127 (-27 ~ 27-1)
unsigned char1 字节0 到 255 (0 ~ 28-1)
c
#include <stdio.h>
int main()
{
	char ch;
	// 符号位溢出会导致数的正负发生改变
	ch = 0x7f + 2; //127+2
	printf("%d\n", ch);
	//	0111 1111
	//+2 后 1000 0001,这是负数补码,其原码为 1111 1111,结果为 - 127
	// 最高位的溢出会导致最高位丢失
	unsigned char ch2;
	ch2 = 0xff+1; //255+1
	printf("%u\n", ch2);
	//	  1111 1111
	//+1 后 10000 0000, char 只有 8 位最高位的溢出,结果为 0000 0000,十进制为 0
	ch2 = 0xff + 2; //255+2
	printf("%u\n", ch2);
	//	  1111 1111
	//+1 后 10000 0001, char 只有 8 位最高位的溢出,结果为 0000 0001,十进制为 1
	return 0;
}

# 实型 float double

# 定义

浮点型变量是由有限的存储单元组成的,因此只能提供有限的有效数字。在有效位以外的数字将被舍去,这样可能会产生一些误差

数据类型占用空间有效数字范围
float4 字节7 位有效数字
double8 字节15~16 位有效数字

通常,不以 f 结尾的常量是 double 类型,以 f 结尾的常量 (如 3.14f) 是 float 类型。

# 输入输出

打印格式含义
%f输入输出 float 类型
%lf输入输出 double 类型

# 类型限定符 extern const volatile register

限定符含义
extern声明一个变量,extern 声明的变量没有建立存储空间
const定义一个常量,常量的值不能修改
volatile防止编译器优化代码
register定义寄存器变量,提高效率。register 是建议型的指令,而不是命令型的指令,如果 CPU 有空闲寄存器,那么 register 就生效,如果没有空闲寄存器,那么 register 无效

# 构造类型

TODO

# 指针类型

TODO

# 复合类型

TODO

# 运算符

# 算术运算符

运算符意义示例结果
+正号+33
-负号-3-3
+10 + 515
-10 - 55
*10 * 550
/10 / 52
%取模 (取余)10 % 31
++前自增a=2; b=++a;a=3; b=3;
++后自增a=2; b=a++;a=3; b=2;
--前自减a=2; b=--a;a=1; b=1;
--后自减a=2; b=a--;a=1; b=2;

# 赋值运算符

运算符意义示例结果
=赋值a=2; b=3;a=2; b=3;
+=加等于a=0; a+=2;a=2;
-=减等于a=5; a-=3;a=2;
*=乘等于a=2; a*=2;a=4;
/=除等于a=4; a/=2;a=2;
%=模等于a=3; a%=2;a=1;

# 比较运算符

运算符意义示例结果 (bool)
==相等于4 == 30
!=不等于4 != 31
<小于4 < 30
>大于4 > 31
<=小于等于4 <= 30
>=大于等于4 >= 11

# 逻辑运算符

运算符术语示例结果
!!a若 a 为假,则!a 为真; 如果 a 为真,则!a 为假。
&&a && b若 a 和 b 都为真,则结果为真,否则为假。
||a || b若 a 和 b 有一个为真,则结果为真,二者都为假时,结果为假。

# 三目运算符

? 前表达式为真择取值 a,为假则取值 b c = ( a > b ? a : b )

# 其他运算符 sizeof 强制类型转换

# sizeof

  • 用于求一个数据类型的占用空间的大小,单位为字节
  • 返回值类型为 size_t

# 类型转换

  • 分为自动类型转换(隐式转换,由编译系统自动完成)和强制类型转换

  • 类型转换的原则:占用内存字节数少 (值域小) 的类型,向占用内存字节数多 (值域大) 的类型转换,以保证精度不降低

  • 强制类型转换的格式为 (需转换的类型) 表达式 例: a = (int)b

# 运算符优先级

<table>
<tr>
<td> 优先级 </td>
<td> 运算符 </td>
<td> 名称或含义 </td>
<td> 使用形式 </td>
<td> 结合方向 </td>
<td> 说明 </td>
</tr>
<tr>
<td>1</td>
<td>[]</td>
<td> 数组下标 </td>
<td> 数组名 [常量表达式]</td>
<td> 左到右 </td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>()</td>
<td> 圆括号 </td>
<td>(表达式)/ 函数名 (形参表)</td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>.</td>
<td> 成员选择(对象)</td>
<td> 对象。成员名 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>-></td>
<td> 成员选择(指针)</td>
<td> 对象指针 -> 成员名 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>2</td>
<td>-</td>
<td> 负号运算符 </td>
<td>- 表达式 </td>
<td> 右到左 </td>
<td> 单目运算符 </td>
</tr>
<tr>
<td></td>
<td>~</td>
<td> 按位取反运算符 </td>
<td>~ 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>++</td>
<td> 自增运算符 </td>
<td> 变量名 / 变量名 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>--</td>
<td> 自减运算符 </td>
<td>-- 变量名 / 变量名 --</td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td> 取值运算符 </td>
<td> 指针变量 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>&</td>
<td> 取地址运算符 </td>
<td>& 变量名 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>!</td>
<td> 逻辑非运算符 </td>
<td>! 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>(类型)</td>
<td> 强制类型转换 </td>
<td>(数据类型) 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>sizeof</td>
<td> 长度运算符 </td>
<td>sizeof (表达式)</td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>3</td>
<td>/</td>
<td> 除 </td>
<td> 表达式 / 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td></td>
<td>
</td>
<td> 乘 </td>
<td> 表达式
表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>%</td>
<td> 余数(取模)</td>
<td> 整型表达式 % 整型表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td>4</td>
<td>+</td>
<td> 加 </td>
<td> 表达式 + 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td></td>
<td>-</td>
<td> 减 </td>
<td> 表达式 - 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td>5</td>
<td><<</td>
<td> 左移 </td>
<td> 变量 << 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td></td>
<td>>></td>
<td> 右移 </td>
<td> 变量 >> 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>6</td>
<td>></td>
<td> 大于 </td>
<td> 表达式 > 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td></td>
<td>>=</td>
<td> 大于等于 </td>
<td> 表达式 >= 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td><</td>
<td> 小于 </td>
<td> 表达式 < 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td><=</td>
<td> 小于等于 </td>
<td> 表达式 <= 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td>7</td>
<td></td>
<td> 等于 </td>
<td> 表达式
表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td></td>
<td>!=</td>
<td> 不等于 </td>
<td> 表达式!= 表达式 </td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>8</td>
<td>&</td>
<td> 按位与 </td>
<td> 表达式 & 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td>9</td>
<td>^</td>
<td> 按位异或 </td>
<td> 表达式 ^ 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td>10</td>
<td>|</td>
<td> 按位或 </td>
<td> 表达式 | 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td>11</td>
<td>&&</td>
<td> 逻辑与 </td>
<td> 表达式 && 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td>12</td>
<td>||</td>
<td> 逻辑或 </td>
<td> 表达式 || 表达式 </td>
<td> 左到右 </td>
<td> 双目运算符 </td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>13</td>
<td>?:</td>
<td> 条件运算符 </td>
<td> 表达式 1?</td>
</tr>
<tr>
<td> 表达式 2: 表达式 3</td>
<td> 右到左 </td>
<td> 三目运算符 </td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>14</td>
<td>=</td>
<td> 赋值运算符 </td>
<td> 变量 = 表达式 </td>
<td> 右到左 </td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>/=</td>
<td> 除后赋值 </td>
<td> 变量 /= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>=</td>
<td> 乘后赋值 </td>
<td> 变量
= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>%=</td>
<td> 取模后赋值 </td>
<td> 变量 %= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>+=</td>
<td> 加后赋值 </td>
<td> 变量 += 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>-=</td>
<td> 减后赋值 </td>
<td> 变量 -= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td><<=</td>
<td> 左移后赋值 </td>
<td> 变量 <<= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>>>=</td>
<td> 右移后赋值 </td>
<td> 变量 >>= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>&=</td>
<td> 按位与后赋值 </td>
<td> 变量 &= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>^=</td>
<td> 按位异或后赋值 </td>
<td> 变量 ^= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
<td>|=</td>
<td> 按位或后赋值 </td>
<td> 变量 |= 表达式 </td>
<td></td>
<td>--</td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td>15</td>
<td>,</td>
<td> 逗号运算符 </td>
<td> 表达式,表达式,…</td>
<td> 左到右 </td>
<td>--</td>
</tr>
<tr>
<td></td>
</tr>
</table>