C程序运行机制流程
- ① 编写代码
- ② 预处理,得到预处理之后的源文件(通常以 .i 为扩展名)
- ③ 编译,得到汇编代码(通常以 .s 或 .asm 为扩展名)
- ④ 汇编,得到目标文件(通常以 .o 或 .obj 为扩展名)
- ⑤ 链接,将我们编写的代码与系统的库链接到一起,得到可程序程序(windows上以 .exe 为扩展名)
- ⑥ 运行
源文件->预处理之后的源文件->汇编文件-> 目标文件 -> 可执行文件
原码、反码、补码
1. 正数的原码、反码、补码一致,最高位符号位是0
2. 0 的原码、反码、补码都是 0
3. 负数 最高位表示符号位,1表示负数
原码:符号位是1,其他位是二进制表示形式
反码:在原码基础上,符号位不变,其他位取反
补码:反码基础上+1
补码计算器:https://www.lddgo.net/convert/number-binary-code
- 每一组都有个特殊的存在,为了节约空间会将每组最小的负数的补码用其正数表示。例如
-8
的四位补码为1000
;-128
的八位补码为10000000
#include <stdio.h>
int main()
{
int num = -10;
printf("以d输出结果为:%d\n",num);
printf("以u输出结果为:%u\n\n",num);
/* 使用 %d 输出会得到负数
使用 %u 输出会得到一个较大的正数,把负数的补码作为无符号形式展示出来了 */
return 0;
}
第6章 数据类型
比特: 英文 bit,表示一个二进制位,用 b 表示。
字节: 英文 Byte,通常 8 个 bi t为一个字节,用 B 表示。
6.1 整数类型
① 整型划分
类型 | 类型简写 | 说明 | 存储大小 |
---|---|---|---|
unsigned short int | unsigned short | 无符号短整型 | 2字节 |
signed short int | short | 有符号短整型 | 2字节 |
unsigned int | unsigned | 无符号整型 | 4字节(32位及以上)/2字节(16位及以下) |
signed int | int | 有符号整型 | 4字节(32位及以上)/2字节(16位及以下) |
unsigned long int | unsigned long | 无符号长整型 | 4字节(32位)或8(64位)字节 |
signed long int | long | 有符号长整型 | 4字节(32位)或8(64位)字节 |
unsigned long long int | unsigned long long | 无符号长长整型 | 8字节 |
signed long long int | long long | 有符号长长整型 | 8字节 |
注意:
整数分为 short、int、long、long long 四种,每种分为有符号和无符号。
一般优先使用 int 类型,如果超出范围,再使用 long 或者 long long。
long long 类型是 C99 标准之后增加的语法。
② 字面量后缀(不需要记)
数据类型 | 字面量后缀 | 数据类型 | 字面量后缀 |
---|---|---|---|
int | 无 | unsigned int | U |
long | L | unsigned long | LU、UL |
long long | LL | unsigned long long | ULL、LLU |
注意:
字面量后缀不区分大小写,
LL
与ll
等价。字面量后缀之间可以组合,比如表示无符号的
U
和表示long类型的L
组合,且顺序无所谓,LU
与UL
等价。
③ 格式占位符
数据类型 | 格式占位符 | 数据类型 | 格式占位符 |
---|---|---|---|
int | %d | unsigned int | %u |
short | %hd | unsigned short | %hu |
long | %ld | unsigned long | %lu |
long long | %lld | unsigned long long | %llu |
④ 精确宽度整数类型
定义在标准库头文件 <stdint.h>
中:
int8_t
int16_t
int32_t
int64_t
uint8_t
uint16_t
uint32_t
uint64_t
#include <stdio.h>
int main()
{
unsigned int cab;
printf("请输入硬盘容量GB?\n");
scanf("%u",&cab);
unsigned long long res= (long long) cab << 30;
printf("容量大小为:%llu\n",res);
return 0;
}
6.2浮点类型
① 浮点类型划分
数据类型 | 说明 | 存储长度 | 有效小数位数 |
---|---|---|---|
float | 单精度浮点 | 4字节 | 6~9 |
double | 双精度浮点 | 8字节 | 15~18 |
long double | 长双精度浮点 | 10字节或16字节 | 18或更多 |
总结:
- 优先使用 double 类型。
6.8
、8.0
、5.78E5
、.56
都是浮点数的字面量写法。
② 字面量后缀(不需要记)
类型 | 字面量后缀 |
---|---|
float | F |
double | 不需要 |
long double | L |
注意: 字面量后缀不区分大小写
③ 格式占位符
- 默认显示六位小数
- 像**%.2f**表示保留两位小数
数据类型 | 十进制小数形式对应的占位符 | 科学计数法形式对应的占位符 |
---|---|---|
float | %f | %e |
double | %lf | %le |
long double | %Lf | %Le |
注意:
输出 double 类型数据,使用 %f 和 %lf 都可以,但是使用 scanf 获取输入赋值给 double 类型变量,只能使用 %lf。
- 若想显示为科学计数法的形式则需把
f
换成e
%e、%le、%Le则会显示科学计数法的形式。
④ 浮点类型存储原理
1. 浮点数分为符号位、指数位、尾数位三部分存储
2. 指数位决定可表示数字范围,尾数位决定数字精度
⑤浮点类型存储规则
根据IEEE754标准,浮点数在计算机内部分成符号S、指数E、尾数M三部分,分别以二进制的形式进行存储,其中S取0或者1(0表示正数,1表示负数),M要求大于等于1且小于10。
- 整数类型和浮点数类型在内存存储原理上有什么不同
整数: 补码
浮点:符号位、指数、尾数
- 定义一个有符号整数变量,赋值一个负数,使用 %d 和 %u 分别输出会得到什么结果
/**********************************************************************
* 定义一个有符号整数变量,赋值一个负数,使用 %d 和 %u 分别输出会得到什么结果
**********************************************************************/
#include <stdio.h>
int main()
{
// 定义一个有符号整数变量,赋值一个负数
// 对于变量num,内存中存补码,int是4字节(32bit),-2对应的32位补码:11111111111111111111111111111110
int num = -2;
printf("%d \n", num);
printf("%u \n", num);
printf("\n");
// 定义一个无符号整数变量,赋值一个比较大正数(超过有符号正数的范围)
unsigned int num1 = 4294967290;
printf("%d \n", num1);
printf("%u \n", num1);
return 0;
}
输出结果:
-2
4294967294
-6
4294967290
6.3 字符类型
① 字符类型的本质
1. char 类型本质是整数类型,存储长度1个字节,里面存储的是字母、符号所对应的ASCII码
2. char 类型分为 signed char 和 unsigned char
② ASCII 码
A -> 65
a -> 97
6.4 布尔类型
① 布尔类型的定义方式
第一种方式
C89标准没有定义布尔类型,判断真假时以0为假,非0为真 ,但这种做法不直观,我们一般需要借助C语言的宏定义。
第二种方式
C99标准提供了_Bool 型,_Bool仍是整数类型,但与一般整型不同的是,_Bool变量只能赋值为0或1,非0的值都会被存储为1。
第三种方式
C99标准还提供了一个头文件 <stdbool.h> 定义了bool代表_Bool,true代表1,false代表0。
6.5 获取数据存储大小
1. sizeof (数据类型别名)
2. sizeof 常量、变量、表达式
- 注:
sizeof
也属于一种运算符
使用sizeof 可以获取数据类型或变量、字面量的存储大小,单位是字节。sizeof返回一个size_t类型的无符号整数值,格式占位符是 %zu。
6.6 数据类型转换
① 自动类型转换
1. 运算过程中的自动类型转换
(1) 整数和整数
① 窄类型转宽类型
② 有符号转无符号(比大小的时候)
③ char和short运算时会转为int
sizeof也算运算,但是sizeof对变量运算不会有影响.
如:
char num1 = 100;
printf("%zu \n", sizeof 'a');
printf("%zu \n", sizeof num1);
(2)浮点和浮点
精度小的转精度大
(3)整数和浮点
整数转浮点,不论存储长度
2. 赋值过程中的自动类型转换
等号右边的数据转为等号左边指定的类型,注意要避免宽类型转窄类型
转换方向 :
② 强制类型转换
(数据类型关键字)变量、常量、表达式
第 7 章 运算符
7.1 算术运算符
%
取余(取模) :
① 结果的符号(正负)与第一个操作数一致
② 两个操作数必须都是整数类型
注意:
- 带有副作用的运算符要求操作数必须是变量的形式。
- C 语言中,同一个表达式中不要出现对同一个操作数的多次副作用操作。
7.2 逻辑运算符
运算符 | 描述 | 操作数个数 | 所组成表达式的值 | 有无副作用 |
---|---|---|---|---|
&& | 逻辑与(AND、并且) | 2 | 全真得真,有假得假 | 无 |
` | ` | 逻辑或(OR、或者) | 2 | |
! | 逻辑非 | 1 | 真得假,假得真 | 无 |
总结:
- 逻辑与短路:如果第一个操作数不成立,第二个操作数不会执行。
- 逻辑或短路:如果第一个操作数成立,第二个操作数不会执行。
- 同类型运算结果也是同类型
7.3 位运算符
运算符 | 描述 | 操作数个数 | 所组成表达式的值 | 有无副作用 |
---|---|---|---|---|
& | 按位与 | 2 | 无 | |
` | ` | 按位或 | 2 | |
^ | 按位异或 | 2 | 无 | |
~ | 按位取反 | 1 | 无 | |
<< | 按位左移 | 2 | 无 | |
>> | 按位右移 | 2 | 无 |
总结:
位运算的时候,操作数需要使用二进制补码进行运算
对于有符号数,如果最高位为1(负数),则右移时会在高位补1;如果最高位为0(正数),则右移时会在高位补0。
按位左移和右移的快捷计算方式:
十进制数: 67 左移两位 67 × 10^2 = 6700 189 右移两位 189 × 10^-2 = 1.89 二进制 17 左移两位 17 × 2^2 = 68 -12 左移两位 -12 × 2^2 = -48 17 右移三位 17 × 2^-3 = 17 / 8 ≈ 2 -12 右移三位 -12 × 2^-3 = -12 / 8 = -1.5 ≈ -2
7.4 逗号运算符
#include <stdio.h>
int main()
{
for (int x = 0,y = 0; x < 10, y < 6; x++ ,y++)
{
printf("x=%d y=%d\n",x,y);
}
}
输出:
x=0 y=0
x=1 y=1
x=2 y=2
x=3 y=3
x=4 y=4
x=5 y=5
逗号运算符以逗号右边的值或条件作为标准
第 8 章 流程控制
- if-else,if-else if:用于条件判断
①多向分支 switch case
- 用于判等
switch (表达式)
{
case 表达式可能的值1:
语句1;
语句2;
...
break;
case 表达式可能的值2:
语句1;
语句2;
...
break;
case 表达式可能的值3:
语句1;
语句2;
...
break;
default:
语句1;
语句2;
...
}
总结:
(1)switch 后面表达式的值必须是一个整型(char、short, int, long等)或枚举类型。
(2)case 后面的值必须是字面量常量,而不能是变量或标识符常量。
(3)default 是可选的,当没有匹配的 case 时,执行default。
(4)break 语句可以使程序跳出 switch 语句块,如果没有 break,会执行下一个 case 语句块,直到遇到break或者执行到switch结尾,这个现象称为穿透。
循环控制语句
②do while 循环
do
{
语句1;
语句2;
...
} while (条件表达式);
while 和 do while 区别:
whlie 每次循环都是先判断再执行
do while 第一次执行没有判断,以后的每次执行仍然先先判断再执行,和while一样
③for循环
- 适用于计数循环
#include <stdio.h>
int main()
{
int i;
for (i = 0; i < 5; i++)
{
printf("%d ",i);
i++;
}// 循环结束,i 自增1(由for循环的迭代部分处理)
printf("\n %d",i);
}
输出:
0 2 4
6
- for循环的迭代表达式:在每次循环迭代的末尾执行,通常用来更新循环计数器的值。
for (循环变量初始化; 条件表达式; 循环变量变化)
{
语句1;
语句2;
...
}
总结:
循环变量初始化:在循环之前执行一次。
条件表达式:每次循环都要先判断再执行,同 whlie。
循环变量变化:每次循环的时候在循环体语言的后面执行。
④ goto
1. 使用 goto 可以跳转到指定位置
goto 标签名;
2. 标签名是自定义的,需要符合标识符规范
3. 尽量避免使用!
第九章 断点
程序执行到断点时,断点是处于当前语句之前的,即断点所在语句并未执行。
printf(“%d “,i);
i++;
}// 循环结束,i 自增1(由for循环的迭代部分处理)
printf(”\n %d”,i);
}
输出:
0 2 4
6
- for循环的迭代表达式:在每次循环迭代的末尾执行,通常用来更新循环计数器的值。
```c
for (循环变量初始化; 条件表达式; 循环变量变化)
{
语句1;
语句2;
...
}
总结:
循环变量初始化:在循环之前执行一次。
条件表达式:每次循环都要先判断再执行,同 whlie。
循环变量变化:每次循环的时候在循环体语言的后面执行。
④ goto
1. 使用 goto 可以跳转到指定位置
goto 标签名;
2. 标签名是自定义的,需要符合标识符规范
3. 尽量避免使用!