Week 02
Day 06
进制转换
不同进制在程序的显示
-
在C代码中,以0开头的数据表示八进制数据,以0x/0X开头的数据表示十六进制数据
-
%x 让数据以十六进制显示
-
%o 让数据以八进制显示
-
%#x %#o 显示出数据对应的进制前缀
-
原码,反码,补码
-
原码:数据的二进制
-
反码:
-
正数的原码就是反码
-
负数的反码:它的原码符号位不变,其他位按位取反
-
-
补码:
注意:所有数据在计算机中,都是以补码形式存储
-
正数原码就是补码
-
负数补码:
-
转换成二进制,得到原码
-
原码符号位不变,其余按位求反,得到反码
-
反码+1,得到补码
-
-
补码如何转成数据:
-
先确定是有符号还是无符号
-
无符号/有符号且最高位为0,补码直接转成十进制
-
有符号的且最高位为1
-
补码-1,得到反码
-
符号位不变,其余为按位求反,得到原码
-
原码转十进制
1111 1111 补码
1111 1110 反码
1000 0001 原码
-1
-
-
位运算符
-
单目 > 算数 > 位 > 关系 > 逻辑 > 三目 > 赋值
-
在位运算符中 ~(按位求反) 优先级最高
-
^ 异或
-
左边补符号位>>
-
右移 >> 除2 左移 << 乘2
int num = 40; printf("%d\n",num >> 1 + 2); // num>>3 //先计算1+2后 右移3 即除(2*3)6 printf("%d\n",num); // 40
& | ~ ^ << >>
-
A & B 按位相与 只有两个数的二进制同时为1,结果才为1,否则为0 (一假即假)
1010 1110 A 0xAE
0111 1100 B 0x7C
————————————
0010 1100 C 0x2C
-
A | B 按位相或 两个数中的一个为1,结果就为1(一真即真)
1010 1110 A 0xAE
0111 1100 B 0x7C
————————————
1111 1110 C 0xFE
-
~A 按位取反(在位运算符中优先级最高)
1010 1110 A 0xAE
————————————
0101 0001 B 0x51
-
A ^ B 按位异或 相同为0,相异为1
1010 1110 A 0xAE
0111 1100 B 0x7C
————————————
1101 0010 C 0xC2
-
A << n 按位左移n位,左边超出的丢弃,右边补0 相当于乘2
1010 1110 A << 3
1010 1110
0111 0000
-
A >> n 按位右移n位,右边超出的丢弃,左边补符号位(遇1补1,遇0补0) 相当于除2
1010 1110 A >>3
1010 1110
1111010 1
注意:只要式子中出现了位运算符,必须转换成二进制进行补码再进行运算
函数:Function
函数分类
标准库函数
-
C语言标准委员会以函数形式提供的一些基础功能,都被封装在libc.so库中,并且分在了不同的文件中,需要使用时只要把对应的头文件导入即可(例如stdio.h....) 然后通过具体的 函数名(参数) 即可完成
取随机值函数
-
srand(time(NULL)) 一定要放在循环外(前面),内部和后面都不可以
int system(const char *command);
功能:执行系统命令command
例如:清屏system("clear");
自定义函数:
函数声明: 返回值类型 函数名(类型1 变量名1,类型2 变量名2,...); 1、如果函数不需要参数,要写void 2、如果函数没有返回值,也要写void 3、如果参数类型相同,不能省略后面的类型名 隐式声明: 在函数调用前没有出现函数声明或定义,那么编译器会猜测函数的返回值为int类型,如果猜对了会产生隐式声明的警告,如果没猜对会报错
函数定义: 返回值类型 函数名(类型1 变量名1,类型2 变量名2,...) { //函数体 return [val]; } 函数调用: 函数名(实参变量1,实参变量2,...);
Day 07
函数传参
-
函数中定义的变量属于该函数,出了该函数就不能在被别的函数直接使用
-
实参与形参(括号里的数据(int num))之间是以赋值的方式进行数据传递数据,并且是单向值传递
-
return语句其实是把返回值放入公共区域内存中(调用者和被调用者都可以访问),调用者会从该区域获取返回值;如果不写return语句,该区域会是一个随机的垃圾数据,调用者也能拿到返回值,但无意义
数组作为函数的参数
-
数组作为函数的参数传递时,数组的长度会丢失,需要额外添加一个变量把数组长度传进去 int len
固定搭配: void func(int arr[],int len); int arr[10]; func(arr,10)//调用时[]不加
-
数组作为参数传递时,时“址传递”,相当于调用者与函数共享数组
进程映像
-
程序:存储在磁盘上的可执行文件(二进制文件,脚本文件)
-
进程:正在系统中运行的程序
-
进程映像:进程在内存中分布的情况
名称 中文名 特点 text 代码段 (代码段+只读段 (常量) ) 存储的是二进制指令,常量(加'',""),权限是只读,如果强制修改会产生段错误 data 数据段 初始化的全局变量,初始化为0,不算,依旧放在bss,初始化过的静态局部变量 bss 静态数据段 未初始化的全局变量,在该段内存中的数据在程序开始前会自动清0,未初始化的静态局部变量 stack 栈(局部变量) 局部变量和块变量,会随着程序的运行不断申请,释放(自动申请,自动释放),使用方便,由操作系统管理,缺点内存小 默认初始值是随机的 heap 堆 该段内存由程序员手动管理,手动申请和释放,使用麻烦,优点内存足够大
局部变量和全局变量
全局变量
-
定义在函数外的变量
-
存储位置:data(初始化的全局变量) 或者 bss(未初始化的全局变量)
-
生命周期:程序开始到程序结束
-
使用范围:定义在函数外,程序的任意位置都可以使用
-
局部变量
-
定义在函数内的变量
-
存储位置:stack 栈内存
-
生命周期:从函数开始到函数结束,自动申请,自动释放
-
使用范围:只能在该函数范围内使用
-
块变量
-
也是一种局部变量
-
定义在if/for/while等语句块内的变量
-
存储位置:stack 栈内存
-
生命周期:从语句块开始到语句块结束
-
使用范围:只能在语句块范围内使用
-
注意:同名的局部变量会屏蔽同名的全局变量,同名的块变量会屏蔽,同名的局部变量,同名的全局变量
因此建议:全局变量首字母大写,局部变量全部小写
类型限定符
auto
-
用于定义自动申请,自动释放的变量(局部变量),不加就代表加了
-
注意:在C11语法标准中用于自动识别类型
auto int num;
int num;
-
注意:不能用它修饰全局变量,不能和static搭配
extern
-
用于声明外部变量,意思是告诉编译器此变量在程序的其他地方已经定义了,先让程序通过编译,如果在链接时找不到该变量依然会报错
-
不建议在extern时赋值,它只是声明
static
改变存储位置
-
改变局部变量的存储位置,由stack改为data(初始化)或者bss(未初始化)
延长生命周期
-
延长局部变量的生命周期,从程序开始直到程序结束才释放(改变了stack栈的存储位置为全局变量),同全局变量
限制作用范围
-
使用static修饰全局变量,会限制全局变量的使用范围,限制只能在本文件内使用(不能配合extern使用)
注意:使用static修饰全局变量,可以防止改变量被别的文件使用,以及防止命名冲突
const
-
“保护”变量的值不能被显示的修改
注意:如果通过内存进行修改,还是可以改的
注意:使用const修饰data段数据(因为数据发布靠太近了),那么该数据会存储到text段中,如果强制修改会发生段错误
volatile
-
C编译器会对普通变量的取值进行 “ 取值优化 ”,只要在使用变量的过程中该变量没有发生显式改变,那么编译器会直接使用上一次结果,而不会每次都去内存读取数据
-
加上volatile修饰,让编译器不要对该变量进行 “ 取值优化 ”
-
一般在驱动编程,硬件编程,多线程编程时使用
volatile int num = 10;
register
-
存储介质:
硬盘 < 内存 < 高级缓存 < 寄存器(register) < CPU
-
申请把变量的存储介质由内存改为寄存器,但是由于寄存器数量有限,不一定百分百成功
注意:寄存器变量不能取地址,不安全
typedef(改变类型名称)
-
类型重定义
-
在定义变量前,加上typedef,那么原本的变量名就变成了这种数据类型,可以像数据类型一样定义变量
typedef int num; num n1 = 10;
-
常用的:uint_t time_t size_t 都是标准库用typedef重新定义出的名字
注意:它不是替换
typedef int num; //类型重定义 #define num int //替换 num n1;
Day 08
函数递归
-
函数自己调用自己的行为,叫函数递归
-
递归是分治思想的具体实现,就是把一个复杂而庞大的问题,分解成若干个相似小问题,解决小问题,从而大问题得到解决
-
如果函数递归缺少出口设置,任意出现类似死循环的效果,且很快内存耗光程序异常结束
-
如果能用循环循环解决的问题,不要用递归,递归会比循环更耗时耗内存
三个要素
-
出口 *
-
解决一个小问题
-
调用自己
Day 09
什么是指针
-
指针是一种特殊的数据类型(eg:int char),使用它可以定义指针变量,指针变量存储的是整型数据,该数据代表了内存的编号(地址),可以通过这个编号访问到对应的内存(背)