c基础
c在Linux下编译命令是通过gcc完成的
1.vi操作:
主要由三种模式构成:命令模式,输入模式,底行模式
记一下常用的命令即可。如 dd:删除光标所在的这一行,x:删除光标所在的这个字符
:set nu :显示该文件下命令的行数, :wq:保存并退出
2.关键字和标识符
c语言中的标识符可以分为:关键字,预定义标识符和用户标识符;如:case,default等属于关键字,scanf属于预定义标识符,acd之类的属于用户标识符。
在定义用户标识符时,可以和预定义标识符重名,但是会导致预定义标识符失去之前的含义。但是不能和关键字重名,关键字大概有32个
3.数据类型
主要分为:基本数据类型,其他类型,自定义类型
基本数据类型:
1.整型:
short --- 短整型 2字节
int-----整型(默认整型) 4字节
long int -----长整型 8字节
longlong int --- 超长整型 16字节
注意:int和long int 会根据计算机操作系统位数的不同,其大小也会发生改变
2.实型(浮点型)
float :单精度实数,只能保证小数点后6到7位是正确的 4字节
double:双精度实数,能保证小数点后15到16位是正确的 8字节
判断两个浮点数是否相等:
因为存在精度问题所以浮点型不能直接用==判断两个数是否相等,可以通过如:a - b - 3.3 > -0.000001 && a - b -3.3 < 0.000001,进行判断,ab都是float类型,a=5.5,b=1.2
3.字符类型:
char :字符 1字节
char类型通过ASCII码表进行转换,常见的有:'a'=97,'0'=48,'A'=65。浮点数可以进行整型运算
4.数的存储
因为计算机只能识别二进制的代码,所以要将其他类型的数据转换为二进制。计算机中存放的是数的补码
补充:二进制以0b开头,8进制以0开头,十六进制以0x开头
4.1进制转换
十进制转二进制:模二取余,低位在上,高位在下
例:10-----0.……01010
10%2--->5....0
5%2--- >2.....1
2%2---->1.....0
1%2---->0……1
二进制转十进制:按权展开
例:
0111---->1*2^0+1*2^1+1*2^2+0*2^3=7
特殊:二进制转16进制/8进制
因为2^4/2^3 ===16/8,所以二进制连续的4位/3位就表示,一位16进制/8进制的数。
注意如果不够4/3位,高位用0进行添加
4.2补码求解
正数;正数的补码等于其原码,原码就是该数的二进制表示
负数:符号位为1,从右往左找到第一个1,从1之后的数全都按位取反
5变量与常量,以及存储类型
1 变量
在程序中定义之后,在内存中的地址不会改变,但值会发生改变。变量也属于标识符(用户标识符)
1.1 变量的定义:数据类型 变量名;
2 常量
在程序过程中,值不会发生改变。可以通过关键字进行定义,如define,const;
3.存储类型
3.1 auto(默认):将变量存放到栈里面去
3.2 static:静态类型,将变量存放到静态变量区中
3.3 register(寄存器):将变量存放到CPU当中
3.4 extern:外部类型
6.格式化输入与输出,转义字符
1.输入
1.1输入函数
常用的输入函数:scanf,get,getchar
scanf:可以用于输入字符,数字,浮点数。scanf函数在遇到空格、制表符或回车时会停止读取数据。格式:scanf("%d",&a); &:表示取地址符号
注意: 如果遇到连续的数值字符,可以用空格或回车区分;如果是字符,不能使用空格或回车,因为空格或回车也算一种字符。解决方法:”%*c%c“,&c,表示读入两个字符,但是会舍去带有*的那个字符
getchar:用于读入连续的字符。(只能用于读入字符),遇到回车视为结束
gets:用于读入字符串,可以设置读取的长度。遇到'\n'结束,也可以将长度读完视为结束。
1.2格式化字符
常见的:-:表示左对齐,#:对于十六进制在前面添加0x;+:在正数前面添加'+',在负数前面添加'-'
2.输出
2.1 输出函数
常用函数:pirntf()。
补充:控制输入的长度和精度(浮点型)。例如:printf("%8.2f",f)8:数据的宽度,2:小数点的位数
2.2 转义字符
转义字符:C语言中一类特殊字符,例如"\n":表示换行,"\t":表示水平制表符
7运算符
1.
算数运算符:+,-,*,/,%(只适用于整数)
2.
关系运算符:<,>,<=,>=,==,!=.(==,!=优先级低于其他的)
3.
逻辑运算符:!,||(例如,表达式1||表达式2,如有表达式1为真(非0为真),那么表达式2不会进行计算),&&(!的优先级最高)
4.
位运算符(进行二进制运算):^(异或——相同为假,不同为真),&(位与——两个1为1),|(有一个1就为1),~(按位取反),<<(按位左移),>>(按位右移)
注意:<<。例:如果将-10左移两位,-2(1……111010-二进制表示),左移完得--->11(负数:左边移除两位,前面补两个1)1……0010,然后再末尾加1得--->11111111.....11得-3
5.
复合运算符:+=,-= ,*=,/=。例:变量 +=表达式—-->变量=变量+(表达式)
6.
自增自减运算符
a++:表示先用a的值进行运算,在执行a=a+1
++a:表示先进行a=a+1,在用a(此时a的值为a+1)的值进行运算
7.
三目运算符:格式:表达式1 ? 表达式2 :表达式3 .说明:如果表达式1为真,执行表达式2,为假执行表达式2
8.
逗号表达式:格式:(表达式1,表达式2,……表达式n);
如果是,a=(表达式1,表达式2,……表达式n),则将最后一个表达式的结果作为整个逗号表达式的结果进行输出(即赋值给a)
9.
sizeof:可以求数据类型所占空间大小,单位是字节。是一个整型变量。输出打印时要用到%ld
8.选择结构
1.if结构---单分支结构
if语句:if(表达式),如果表达式为真,执行if里面的内容,为假则不会进入if语句内
2.if……else---多分支结构
if...else语句,与if语句类型,为假时,进入到else中去,执行else里的内容
3.Switch----开关语句
Switch语句(与case关键字搭配使用), 格式:Switch(表达式),,case 常量。注意:表达式和常量表达式结果为整形(因为要判断相等)
9循环结构
1.while
while(表达式):判断while的表达式是否为真,为真进入while里执行,循环体内容,为假则跳过while
2.do……while
do....while(表达式):与while类似,需要判断表达式真假,但是do..while总会执行一次,即使表达式为假。
3.for
for(初值;判断语句;改变初值):与while类似,更像把while语句进行一个整合
10函数
1.函数定义
函数定义(注意:如果函数写在main函数之前,则不需要函数声明,否则需要再main之前写函数声明,即写 数据类型 函数名(参数列表))
1.1
无参无返回值:格式 void 函数名(要符合标识符命名规格) ()
1.2
无参有返回值:数据类型 函数名(),必须使用return语句返回一个值(如果与函数定义的数据类型不同,则会强制转为为与函数的数据类型想同的类型)
1.3
有参无返回值:void 函数名(形式参数) ——注意这里的形式参数也是变量,传递的只是实际参数的值,不会改变实际参数的值。没有实际参数地址的内容
1.4
有参有返回值:数据类型 函数名(形式参数)
2.函数调用
2.1
有参有返回值:数据类型 函数名(形式参数)
2.2
有参有返回值:通过与函数相同的数据类型去接,也可以直接使用相对应的格式化直接输出
2.3
有参无返回值:通过函数名直接调用,但要在函数名之后填入一个参数
2.4
有参有返回值:通过与函数相同的数据类型去接,也可以直接使用相对应的格式化直接输出,但要在函数名之后填入一个参数
11数组
1.一维数组
1.1数组定义
定义:数据类型 数组名[数组大小] 注意:数组大小可以不设置
注意:如果没有给定数组大小时,编译器会根据数组内容的大小计算出当前数组的大小
1.2数组使用
调用:通过函数名[索引],注意索引位置从0开始,
1.3 数组初始化
1.初始化时通过索引位置进行赋值;---------指定初始化
2.初始化时,如果不进行初始化,数组里的值则是随机值,采用部分初始化,没有被赋值的剩余部分的值默认为0--------部分初始化
3.将数组的每一个下标都赋值-----完全初始化
2.二维数组
1.定义
定义:数据类型 数组名[行坐标][列坐标]。
注意:行坐标可以没有,但是列坐标必须要有。行坐标表示二维数组中有多少个一维数组。列坐标表示在二维数组中一维数组所表示的值
2.调用
调用:数组名【行坐标】表示其中一个一维数组。 数组名【行坐标】【列坐标】表示一个准确的值
3.初始化
初始化:需要通过行坐标和列坐标进行准确赋值;也可以通过列坐标进行划分来赋值。
例如 a[][3]={1,2,3,4,5,6,6,8,7},表示每三个元素就代表一个一维数组
其它与一维数组初始化类似
12 全局变量与局部变量
1.全局变量
全局变量:定义在函数以外。有默认值,默认值为0
1.1作用范围
作用范围,从定义开始,到整个程序结束
1.2定义
定义:数据类型 变量名
2.局部变量
局部变量:定义在函数内。不具有默认值,值是一个随机值。
如果局部变量和全局变量重名,那么全局变量的值,会被局部变量给覆盖(即采用局部变量的值计算)
1.作用范围
作用范围:在定义该变量的函数范围内有效
2.定义
定义:数据类型 变量名
3.特殊--static关键字
static,加了该关键字,只会定义一次(即只能初始化一次),但值会保留,作用范围不变
Linux基础
通常Linux就指代的是Linux内核:能够让计算机运行起来(能够操作硬件)
Linux体系结构:
1.Linux内核
1.内核
内核是Linux系统中最底层,提供系统中核心功能并允许有序访问硬件资源件系统:用于组织和管理计算机存储设备上的大量文件
2.文件系统
Windows中使用ntfs(NTFS)文件格式
Linux中格式非常多,目前通用的是:EXT4文件系统格式
Linux文件系统把一切所有内容都看做文件,Linux一切皆文件
Linux文件系统就是一个 树形的目录结构:
将根(/)作为整个文件系统的起点,其他的所有目录都是从根开始
2.shell
人们与机器交互的方式
shell:命令解释器,通过shel提供内核的功能
1.文件目录命令
2.文件类型
3.文件命令
4.操作命令
5.用户管理
6.重定向符
7.终端提示符:ubuntu @ linuxmachine ~:
$ubuntu:用户名
@:分隔符
linuxmachine:计算机名字:分隔符
$:用户权限(普通用户)
#:超级用户
~:代表当前用户的家(用户)目录
8.通配符
3shell脚本
将shell命令按照一定的逻辑关系,顺序组织在一个文件中,组合成一系列完整的功能要求,执行文件,就可以把其中的shell命令按照对应的逻辑顺序执行
1.变量定义
变量=值(变量定义的值是一个字符串)
变量定义一般使用大写
2.变量引用
$ 变量---->表示引用变量
如:
cat $FILE
在字符串中可能会出现使用变量名情况:
“ ”:会解析引用的变量
' ':不会解析引用的变量
3.变量的输入
在shell脚本中,使用read表示 从键盘输入字符串 到变量中:
read 变量1 变量2……
4.位置变量
$1:获取执行shell脚本文件时,命令行(在终端上所输入的命令,并且可以执行,就称为命令行)传递的第一个参数
$2获取命令行传递的第二个参数:
$3:获取命令行传递的第三个参数:
版本不同,存在差异:如果存放的参数长度大于9个,会把超过的部分,都合并在$9中
$@/$*:获取保存命令行传递的所有参数
$?:获取上一条命令执行的状态值,上一条命令执行成功(为真)$?返回0,执行失败(为假)$?返回非0值
5.条件判断
关键字:test
5.1字符串:(s1,s2表示字符串)
1. $s1 = $s2;判断相等
2. $s1!=$s2;判断不相等
3. -z $s1:判断字符串长度是否等于0
4 .-n $s1 :判读字符串长度不为0
5.2整数判断:(a,b表数字字符串)
1. a -gt b:判断a是否大于b
2. a -ge b:判断a是否大于等于b
3. a -lt b:判断a是否小于b
4. a -le b:判断a是否小于等于b
5. a -eq b :判断a是否等于b
6. a -ne b:判断a是否不等于b
注意a,b之前需要加$,取变量a,b对应的值;
5.3文件测试:
1. -d filename :判断filename是否是一个目录
2. -e filename :判断filename文件是否存在
3. -f filename :判断filename文件是否是普通文件
4. -L filename:判断filename是否是符号链接文件
5 -s filename:判断filename文件存在且长度是否为0;
6. -r filename:判断filename文件是否可读
7. -w filename:判断filename文件是否可写
8. -x filename:判断filename文件是否可执行
5.4.逻辑判断
1. 条件1 -a 条件2:逻辑与,多个条件都为真,结果为真
2. 条件1 -o 条件2:逻辑或,只要有一个条件为真,结果为真
3. !条件:得到的条件取反
c高级
1.指针
指针:在内存空间申请空间(定义变量),存储地址,就叫做指针,也叫做指针变量
指针就是操作内存地址,使用内存地址
1.1定义指针变量
指针变量:本质上就是一个变量
指针变量定义的形式:
指向数据类型 * 指针变量名;
数据类型:存储哪种类型数据的地址,指向哪种数据类型
指针变量:定义一个变量,用于存储地址,如果要存储哪种类型的地址,数据类型就存储哪种数据类型
注意:不能随意赋一个地址给指针变量,可能存在给的地址没有被申请或者给的地址中的变量与指针变量的数据类型不一样,如果类型不匹配,会按照指针变量的类型取转化(有问题,尽量少用)。
1.2.使用指针
指针变量访问内容:操作对应地址的数据,通过地址的方式访问数据
间接取值符/间接访问符:*
指针变量间接访问变量
注意:如果指针变量为初始化,不能直接使用指针变量,因为指针变量没有指向一个地址时,指针变量的地址是一个随机值。
1.3.注意:区分:p,*p,&p
p:表示指针变量,指的是目标变量的地址
*p:表示存放目标变量地址的值,是一个值;
&p:指针变量占用的存储区域的地址,是一个地址(通常用二级指针来存储)
1.4.指针变量的初始化
在定义指针变量时,进行赋值,就叫做初始化
类型 * 指针变量=地址
1.5特殊指针
1.野指针:
指针记录的地址不明确(存储的地址不知道,或地址对应空间是否具有操作权限不明确),这种指针叫做野指针
野指针不允许直接进行取 *;
2.空指针:
指针记录的地址是NULL(地址:0x00),系统规定NULL地址不允许进行操作
只要操作就会报错
3.万能指针:
void * 指针变量(---只能当做中间变量使用),可以存储任意类型的地址,也可以把指针赋值给其他的任意类型指针变量
1.6.指针的运算
1.指针+整数:
指针 + 整数 * sizeof(指向类型)
2.指针-整数
指针 - 整数 * sizeof(指向类型)
3.指针++:
先使用指针,然后 指针 = 指针 + 1
4.++指针:
先 指针 = 指针 + 1 ,然后在使用指针
5.指针 - 指针:
获取两个指针之间间隔多少个对应类型的数据
(指针 - 指针)/sizeof(指向类型)
补充:要注意的是,指针相减的结果只有在指针指向同一数组或同一块内存空间时才有定义,并且指针相减的结果通常为长整型。
1.7指针与一维数组
数组是一一段连续的空间存储多个数据,在数组中相邻的元素,间隔大小为每个元素类型的大小, 即 数组名[ 元素 ] == & 数组名[元素 i -1] +类型大小
可以通过指针访问整个数组
只要知道数组的起始1地址(第零个元素的地址),就可以遍历整个数组
数组首地址:数组的起始地址,就是第零个元素的地址
int *p=&a【0】
*(p+n) ==a [n]
在数组中,数组名有个特殊作用,数组名就表示 数组的首地址
数组名,是一个地址常量--------代表一个准确的地址,不可以改变
特点:遍历数组的四种方式----指针方式:
1.p + i;主要运用了指针偏移,指针加一个数,实际上是指针地址+ 数*sizeof(目标数据类型)
2.a+i;大体上也是运用了指针偏移,因为数组名表示该数组的首地址,数组名 + i,也是将当前地址(a[0]的地址)移动 i*sizeof(数组数据类型)
3.p[ i ]:逻辑上等价于p+i;
4.p++:也是运用了指针偏移,每次运算,都会让p(指针变量)的地址偏移一个sizeof(数据类型)的大小。到最后p指向的地址会改变
1.8字符串与字符数组
字符串:由多个字符组成一个连续且有序的字符序列(有 字符数组表示(操作单个字符) 和 字符串表示(连续操作多个字符) 两种方式)
字符数组通过访问数组中的元素,就是访问字符串。
如果需要整体访问字符数组中存储的字符串,要求在字符串结束的下一个字符位置存储"\0"
“\0”字符就表示 字符串的结束
常量字符串表示: “abdsad”——常量字符串
补充:指针类型,都是统一的大小,各个类型之间没有区别
32位机器:4B
64位机器:8B
1.9 指针与二维数组
对于二维数组而言,数组名就是整个二维数组的首地址,第零个元素的地址,二维数组的元素都是一位数组,即二维数组数组名表示其中的元素,整个一维数组的地址
例:
int a[3][4];
a == &a[0];//a[0]是整个一维数组
a+1:代表加整个一维数组的大小
a[0]:表示二维数组的元素零,第零个一维数组,a[0]也是一维数组的数组名,在这个一维数组当中的首地址
核心:a[ 0 ]===&a[ 0 ][ 0 ] ==*(a)
*(a)+1:表示a[0][1]的地址
*(*(a)+1):表示a[0][1]的地址上存放的值
1.10数组指针
是一个指针,指针用于存储整个数组的地址,指针的指向类型为数组
定义格式
数组元素类型 (* 指针变量名)[大小]
1.11多级指针与指针数组
指针数组:是一个数组,只是每个元素为指针类型
指向类型 * 指针变量名[元素个数]
int * p[5];
定义 包含5个元素 每个元素为指针(int *)
二级指针与指针数组的关系:
二级指针可以用来存放指针数组的首地址,与一级指针存放一维数组的功能类似。
1.12.指针与函数
指针作为函数的参数:可以表示变量的地址,或者是数组名/数组首地址
把地址作为参数进行传递
返回值类型 函数名(指针参数1 , 指针参数2);接受传递的是地址
调用:
函数名(地址,地址/指针);
指针作为函数返回值:返回一个地址,把地址作为结果进行返回
2构造类型
由于基本数据类型不能满足需要,需要把多个数据类型进行组合,共同便是新的复合数据,形成新的类型。构造新的数据类型的方式就叫做构造类型
2.1.结构体
使用多种数据类型作为成员,进行组合,构成的新的类型,就叫做结构体
多个成员使用不同的空间
1.声明构造体
:结构体的类型表示
struct 结构体名字
{
类型1 成员1;
类型2 成员2;
类型3 成员3;
};在程序中添加一种新的类型,不占用内存空间,只能说明在程序中有一种新类型
1.2定义结构体变量:
数据类型(struct 结构体名字) 变量名;
1.3访问结构体变量:
结构体变量名.成员名;
1.4 结构体变量初始化
在定义结构体变量时,对其成员进行初始化
方法1:按照顺序进行初始化
struct 结构体 变量名={成员1值,成员2值,成员3值……}
1.5 结构体指针如何访问变量成员
结构体指针:
struct 结构体名 * 指针变量名 = 结构体地址;
访问方式:
指针 ->成员:表示访问结构体指针对应地址中的成员
(* 指针).成员 = == 指针 -> 成员
1.6结构体特殊的声明方式
struct 结构体名字
{
类型1 成员1;
类型2 成员2;
类型3 成员3;
} 结构体变量名 ;在申明时同时定义结构体变量名
3.共用体(联合体)
使用多种数据类型作为成员,进行组合,但是使用同一段空间进行存储(多个成员共用一个空间),构成的新的类型,就叫做结构体
注意:共用空间:指的是使用成员中 空间 最大的 空间
使用共用体的问题:同一时刻只能存储一个成员
3.1声明共用体类型:
union 共用体名
{
类型1 成员1;
类型2 成员2;
类型3 成员3;
};
4.枚举
枚举就是在定义一种新类型时,这个类型能够取值的范围是确定的,通过这个定义的新类型把能确定的取值范围一一列举出来,这种类型就叫做枚举
声明枚举类型:
enum 枚举名
{
成员1,成员2,成员3……
};
枚举类型中,每一个成员就代表能够取的一个值
声明类型时,如果成员没有赋值,成员就等于上一个成员的值+1
如果成员1没有赋值则为0
定义枚举类型:
enum 枚举名 变量名;
变量名 = 成员;
5.字符串函数
5.动态内存
栈:由系统进行管理,它的申请与释放都是由系统完成
栈中变量,只要离开了变量的生命周期,变量就会由系统销毁,释放
堆:由程序员自己进行管理,即释放和申请
堆空间:由程序员在程序中,自己进行管理的空间,需要使用时进行申请,由自己进行释放销毁。这个空间的申请与释放都是由程序中指定,通过地址指针进行访问,按照指针类型进行访问,就叫做动态内存
申请空间:malloc :在堆空间中申请指定大小的内存空间
void *malloc (size_t size)
参数:
size_t size:要申请的字节数
返回值:
void *:如果申请成功,返回申请的空间首地址
如果申请失败,则会返回NULL地址
6.关键字
const:
在定义变量时,使用const关键字修饰,当前变量不可修改(const修饰变量为只读变量),作用类似于常量,只能读,不能修改,不能赋值
通常情况下const变量要进行初始化。
const 数据类型 变量名
const 指向类型 const * 指针变量名;
指针变量不可改;
指向地址的内容也不修改