复习:
进制转换:
十进制转二进制:对2求余,直到商为0,过程中的余数的逆序就是二进制
二进制转十进制:2^(n-1)求和
二进制转八进制:3个二进制位对应1个八进制位
二进制转十六进制:4个二进制位对应1个十六进制位,超过10用ABCDEF表示
代码中以0开头的数据都是八进制,以0x/0X都是十六进制
printf %o 以八进制格式显示数据
%x 以十六进制格式显示数据
原码反码补码:
无符号的原码、反码、补码都是它的原码
整数的原码、反码、补码都是它的原码
负数的原码符号位不变,其他位按位求反得到反码,反码+1,得到补码
无符号的补码就是原码
有符号的,看最高位是0,则补码就是原码
有符号的,看最高位是1,补码-1得到原码,符号位不变,按位取反得到原码
运算符的优先级:单目 算术 位 关系 逻辑 三目 赋值
位1运算符:& | ~ ^ << >>
在位运算符中,~运算级别最高
^ 异或 相异为1,相同为0
>> 左边补符号位
int num =20;
num & 1+2;
num 还是等于20 因为没有赋值
自定义函数:
函数声明:告诉编译器函数的格式,方便编译器检查调用时的参数和返回值
返回值 函数名(类型1 变量1,类型2 变量2,…);
隐式声明: 如果在调用函数时没有声明和定义,编译器会猜测函数的格式
根据调用函数时提供的实参猜测参数类型,返回默认猜测int
函数定义:
如果在函数调用前定义函数,则可以省略函数声明
返回值 函数名(类型1 变量1,类型2 变量2,...)
{
函数体;
return [val];
}
注意:如果函数不需要提供参数,形参要写void,不要空参,因为会导致误会
如果函数没有返回值,返回值也要写void,否则默认返回值为int类型
函数传参:
1、函数的形参变量属于它所在的函数,出了该函数就不能再使用了
2、实参与形参之间是以赋值的形式传递数据的(值传递)
3、return 其实是把返回值的数据放置到一个公共区域(函数和函数调用者都能访问),调用者会从该区域获取返回值,如果不写return语句,则里面是一个随机的垃圾数据,也会被调用者获取
4、当数组作为函数的参数时,长度会丢失,需要额外增加一个变量把数组的长度也传递过去
5、数组的传递是"址传递",函数与函数的调用者可以共享数组
练习1:实现一个函数,找出数组中的最大值
练习2:实现一个函数,对数组进行排序
练习3:实现一个函数,查找出数组中是否存在某个值,如果存在则返回该值的下标,否则返回-1
int find_arr(int arr[],int len,int num)
设计函数的准则:
1、一个函数最好只解决一个问题,这样可以降低错误率,提高代码可读性
2、最好不要依赖其他的函数(降低耦合度)
3、数据由调用者提供,把处理结果返回给调用者(通用性)
4、要考虑调用者提供的非法数据,可以通过返回值告诉调用者,或者可以吧可能出现的情况写在注释上(健壮性)
进程映像:
程序:储存在磁盘上的可执行文件(二进制文件、脚本文件)
进程:正在系统中运行的程序
进程映像:指的是进程的内存分布情况
text 代码段:存储的是二进制指令、常量数据,权限是只读,强制修改会产生段错误
data 数据段:存储被初始化过的全局变量、被初始化过的静态局部变量
bss 静态数据段:存储未初始化过的全局变量、未初始化过的静态局部变量,程序运行时会自动清理为0
stack 栈: 局部变量、块变量,会随着程序的运行而不断的申请、释放,由系统统一管理但是小
heap 堆: 由程序员手动管理,特点 大
局部变量和全局变量:
全局变量:定义在函数外部的变量
存储位置:data(初始化过)或者bss(未初始化)
生命周期:从main运行前直到程序结束才释放
使用范围:程序的任意位置都可以使用
局部变量:定义在函数内的变量
存储位置:stack 栈内存
生命周期:从函数调用开始到函数执行结束
使用范围:只能在本函数内使用
块变量:定义语句块内的变量 if while for
存储位置:stack 栈内存
生命周期:从函数调用开始到函数执行结束
使用范围:只能在所在的语句块内使用
局部变量是屏蔽同名的全局变量,块变量会屏蔽同名的局部变量和全局变量
全局变量变量名建议首字母大写
类型限定符:
auto 用于定义自动分配、释放内存的变量(局部变量),不加代表了加
注意:全局变量不能用它修饰
在C11
extern
声明外部变量,意思是说明此变量已经在别处定义,请放心使用
但是只能临时通过编译,链接时如果找不到依然还是会报错
不能赋值
static
改变存储位置:
改变局部变量的存储位置:由stack栈内存改为data或者bss(由局部变量是否初始化决定)
被它修饰过的局部变量也被称为静态局部变量
延长生命周期:
延长局部变量的生命周期
限制作用范围:
限制全局变量、函数只能在本文件中使用
防止全局变量、函数名冲突,也可以防止被别人调用
const
“保护”变量不被显示的修改
但是如果对初始化过的全局变量、初始化过的静态局部变量,都会变成常量,一定不能修改了
volatile
如果变量的值没有被显示的修改,再次使用该变量时不会从内存中重新读取,而是继续使用上一次读取结果(取值优化)
变量被volatile修饰后,每次使用该变量时,都会从内存重新读取
一般硬件编程或者多线程编程时都会使用
register
申请把变量的存储介质由内存改为寄存器,但是寄存器有限,不一定能百分百成功
注意:寄存器变量不能取地址
typedef
time_t size_t uint8_t
类型重定义,在定义变量之前加上typedef 变量名就变成了这种类型
注意:不是替换关系