Linux C高级
Linux基础
Linux:内核:能够让计算机硬件进行工作,
能够进行最核心的功能组合,计算机运行起来
Linux内核:Linus和linux社区的人员一起研发出的的内核
Linux内核基础上,加上各个厂商匹配内核开发出网络管理、
桌面系统、快捷功能、形成完成的操作系统
操作系统:
Ubuntu、Debuan、Redhat、centos stream 、Arch linux
Linux内核 文件系统
1.linux内核
内核是Linux系统系中最底层,
提供系统中核心功能并允许有序访问硬件资源,
管理:输出输入设备、进程、
执行情况、文件系统操作、内存资源管理
Linux内核支持:多任务、多用户
2.Shell
Shell命令解释器:壳------保护内核
当程序执行时,把程序的各种操作指令进行解析执行,
通过shell命令解释器就是让内核对应操作
作用:提供一个方式可以让用户和内核(操作系统)进行交互
3.文件系统
文件系统就是用于管理和组织计算存储
3.shell命令
字符界面操作Linux内核系统
使用shell命令操作linux系统(字符界面)
shell命令完成内核与用户之间的交互
shell命令就是shell 解释器
能够识别的命令能够让内核执行对用操作。
shell命令的输入:在终端提示符,标识命令输入的位置
路径表示:
特殊路径表示:
~:家目录---当前用户的用户目录
.:当前目录
..:当前目录的上一级目录
/:根目录
相对路径
默认从当前的工作路径位置开始,
找到对应的文件或目录 的位置
../../tmp/VMwareDnD/ok.txt
绝对路径
对于linux文件系统,从根目录(/)开始,
来表示一个文件的位置,叫做绝对路径
/tmp/VMwareDnD/ok.txt
1.命令格式
command+[option]+[argument]
命令 选项 参数
命令:shell要解析的指令内容,要执行的内容
选项:改变命令执行动作的类型(命令功能选择)选项
用:-选型表示 选项可以有多个:
-选项1-选项2-选项3或-选项1选项2
参数:命令要作用的目标
man command:查看手册中命令的说明帮助
2.常用命令
pwd没有选项和参数
cd 改变切换当前的工作路径
cd 参数(路径)
mkdir
创建目录文件
mkdir 参数(要创建的目录路径)
-p:如果目录路径不存在,则依次创建,
直到最终要创建的目录创建完成。
touch
创建普通文件
touch + 文件的路径
cat
查看显示指定文件的内容
cat+文件路径file
ln
创建链接文件
+符号链接文件
符号链接文件也叫做软链接文件,
就是对文件创建一个快捷方式,操作符号文件就是操作源文件,
符号链接文件知识对源文件因素
+硬链接文件
在文件系统中,创建一份和源文件完全一致的独立文件,
新文件和源文件会一直保持一致,
删除一个文件对其他文件不会有影响。
In源文件
文件的硬链接数,表示目录中的目录文件数
car
归档与压缩
归档文件:把多个文件打包一个文件
压缩文件:把已经打包的文件进行 压缩处理
-A:新增文件的已存在的备份文件
-c:创建心得备份文件
-d:记录文件的差别
-t:列出备份 文件的内容
-u:添加改变了和现有的文件已经存在的压缩文件、
-x:从备份文件中还原(解压)
-v:显示操作过程
-f:指定本分文件名
1.创建归档文件:
把多个文件合并成一个文件
tar -cvf 归档文件名.tar 文件1 文件2.......
释放归档文件
把归档文件中包含并打包的文件释放出来
tar-xvf 归档文件名.tar
使用gzip算法进行压缩与解压
-z :使用gzip算法与压缩与解压
压缩:
tar -czvf 压缩文件名.tar.gz 文件名 文件1 文件2.............
解压:
tar -xvf 归档文件名.tar.gz
使用bzip算法进行压缩与解压
-j:使用bzip2算法压缩与解压
使用zip算法压缩与解压
压缩:
zip 压缩文件名.zip 文件1 文件2......
unzip 压缩文件名.zip
用户管理
修改密码
passwd 用户名
在工作用户下只能修改当前用户的密码
如果修改其他密码
切换用户
su切换用户
exit退出当前用户
添加用户
只有管理员root添加
sudo adduser 新用户名
****新用户不具备提升为管理员运行的权限,不能使用sudo
修改配置文件:/etc/sudoers
在文件最后添加:
用户名 ALL=(ALL:ALL)ALL
删除用户
sudo userdel-r用户名
用户组管理
查看用户在哪写用户组中
创建用户组
把用户添加
把用户组删除
删除用户组
权限修改
chmod:修改文件的操作权限(读写执行)
执行修改权限,需要文件的所属用户才能执行修改,root用户权限也是可以更改
sudo chmod 权限 文件
权限:
u-[r、w、x]在用户权限中添加权限
u-[r、w、x]在用户权限中删除权限
g+[r、w、x]在用户组权限中添加权限
g-[r、w、x]在用户组权限中宁删除权限
权限:使用二进制位来表示,1表示有,0表示无
可以通过chmod直接设置每一位的值
110 110 110
066
使用八进制方式来表示权限值,进行设置
如:
chmod 0666 xxx.txt 设置xxx.txt文件权限时:用户拥有读写、用户组拥有读写、其他用户拥有读写
在创建文件时:
普通文件权限:0664
目录文件权限:0775
chown:改变文件所属者
要改变所属者,必须是root管理者身份运行
chgrp 用户组 文件
输出重定向
\>>
linux通配符
* 匹配(代替)任意长度的字符串 file _*.txt===>file_abc.txt,file_ok.txt,file_12345.txt
? 匹配(代替)一个字符
file_?.txt ===>file_1.txt,file_a.txt,file_q.txt
file_12.txt(不能)
[...] 匹配(代替)特定的(方括号中写出)
file_[abc123].txt===>filme _a.txt,file_1.txt,file_1.txt,file_c.txt
file_5.txt(不能)
[-]匹配(代替)特定的(方括号指定范围)一个字符
file_[a-e].txt ==>file_a.txt,file_b.txt,file_e.txt
file_f.txt(不能)
[^...]匹配(代替)特定的(除了我方括号写出)一个字符
file_[……159a]
4.软件包管理
直接执行二进制程序,打开软件使用
安装包进行安装,然后进行使用
安装软件:
软件存在依赖(需要有其他环境的支持)
软件包管理:软件及对应的依赖说明
debian Linux软件包管理机制:deb
red hat Linux 软件包机制:rpm
ubuntu :deb
软件包管理器:
dpkg 本地软件包管理器 :离线安装,不能自动处理依赖
安装本地软件包:
dpkg -i 软件包名 .deb路径
查看本机安装事务软件包
dpkg -l
卸载安装的软件
dpkg -r 软件名
卸载安装软件以及配置文件
dpkg_p软件名
apt 在线联网软件包管理
服务器地址(软件源)列表文件:etc/apt/sources.list
获取软件 源地址中有哪些软件(获取软件列表)
apt update
在线下载安装软件
apt install 软件包名
sudo aptinstall net-tools
卸载安装的软件
apt remove 软件
TFTP服务器:类似于网盘
客户端与服务器模式:一个用于上传和下载文件的服务器
安装TFTP:
apt install tfpd-hpa:安装一个TFTP服务,提供一个文件
夹用于上传和下载
apt install tftp :安装一个客户端,从服务端提供的文件夹下载,往服务端上传一个到所提供的文件夹中
apt install tftp :安装一个客户端,从服务端提供的文件夹下载文件,往服务端上传一个到所提供的文件中
配置tftp服务器:
选择那个文件夹作为上传下载
编辑配置:
sudo vim /etc/default/tftpd-hpa
TFTP_USERNAME=“tftp”:服务名
TFTP_DIRECTORY=“/srv/tftp”:选择目录
TFTP_ADDRESS='0.0.0.69':允许哪些客户端地址进行上传下载
TFTP_OPTIONS="-c-l-s":允许服务端创建文件,即 客户端可以上传文件到服务器
配置服务端的文件夹路径后,需要在对应路径有一个工作目录:
mkdir /home/ubuntu/tftp
将该工作目录权限为007
删除用户
nfs服务器:
sudo apt install nfs-kernel-server
编辑nfs服务器配置文件
sudo vim /etc/exports
添加目录共享
/home/ubuntu/nfs:提供共享的目录
hostname(rw,sync,no_subtree_check):hostname
表示允许哪些地址来访问(*表示任意地址)
rw:可读写,sync:同步,no_subtree_check:不检查目录结构
编辑完成,重启对应的nfs服务
解除挂载:
umount/mnt/nfs
安装nfs客户端:
sudo apt install nfs-common
使用nfs客户端 :
sudo install nfs-common
使用nfs客户端挂载的方式,将nfs服务器的共享目录
5.shell 脚本
shell脚本:是一种解释性的编译语言
将多个shell命令 有序存放在文件中,有shell解释器
读取命令执行
多用于做命令控制,批量处理等操作
shell 脚本:
1.文件 通常.sh作为后缀名
2.shell脚本注释,是以#作为标识
3.给shell脚本 添加可执行权限;指定shell解释器来执行
chmod u+x xxx.sh ./xxxx.sh -----1
bash xxxx.sh -----2
shell 脚本注意事项:
1.每一行就是一个shell命令
2.编写规范和shell命令规范一致
3.严格使用标点符号包括空格
shell脚本(编程):
语法:
1.shell变量
不需要指定类型,弱变量类型,一切变量皆认为是字符串
定义方式:
变量名=值
变量的使用:
$变量名-------本质:字符串的替换
"”:如果字符串内容有特殊字符,就解析特殊字符
'' :如果字符串内容有特殊字符,都认为是普通字符
位置变量:
在执行shell脚本是,给定的参数或选项 将通过位置变量进行传递
不需要定义:
$0:shell脚本
$1
$2
.......
$9
如果超过10 ${10}、${11}......
预定义变量:
$#:shell 脚本执行的参数格式
$@:所有位置参数值
$*:所有位置参数值
$?:上一条命令执行时结束状态值
2.shell 输入输出
输出echo“输出内容”“输出内容”
输入read 变量名1 变量2
3.算数运算
算数运算:expr 算数表达式
a=‘expr算数表达式’
a='expr $a1 + $a2 - 5'
4. shell条件表达式
字符串判断:
s1=s2 测试两个字符串的内容是否完成一致
s1!=s2 测试两个字符串的内容是否不一致
-z s1 测试字符串的长度是否为0
-n s1 测试s1 字符串的长度是否不为0
整数测试:
a- eq b测试a与b是否相等
a -ne b测试a与b是否不相等
a -gt b 测试a是否大于b
a -lt b 测试a是否小于b
a -le b 测试是否小于等于b
··::
5.shell中的if结构
单分支:
if[条件表达式】
then
成立命令块
else
不成立命令块
fi
多分支:
if[条件表达式1]
then
成立1命令块
elif[条件表达式2]
then
成立2命令块
elif[条件表达式3]
else
不满足命令
fi
多分支:case结构
case变量in
字符串1)
命令1
..
;;
字符串2)
命令2
..
,,
字符串3)
命令3
..
,,
*)
命令n
..
,,
esac
6.shell 循环
while循环
while[条件表达式]
do
满足
for循环:变量名能够从参数表中取值一次局循环一次
for 变量名 in 参数表
do
命令
done
整数测试:a -eq b测试a与b是否相等
a -ne b测试a与b是否不相等
a -gt b测试a是否大于b
a -ge b测试a是否大于等于b
a -lt b测试a是否小于b
a -le b测试a是否小于等于b
7. 函数
同C语言函数类似,是为了完成某个功能的命令块
function 函数名()
{
命令
}
对于函数参数是不用添加的,是通过位置参数来标识,只需要在调用的时候写上值(在定义时不用写)
函数调用:
函数名 值1 值2.......
函数返回值:
在函数中使用echo 输出内容:
在调用函数时,如果没有
C语言高级
1.调试
使用printf打印信息,来确定是否执行,或值是否正确
2.gdb调试
在执行时,可以查看程序过程中的任意信息,且能够按照我们需要的方式进行执行;可以一步一步的执行,跟踪程序的执行过程。
比如:可以让程序在没有执行完的情况下,停留在某条语句位置,查看变量的值,查看程序到底执行了那些代码,可以监控到程序的每个执行细节
Windows:windbg
maxos:lldb
Linux :gdb
gdb:可以调试: C、C++、go、opencl、object-c
如果需要调试程序:在编译时需要支持调试
-g:编译程序时加上 调试信息
1.打开调试功能
a、输入:gdb打开调试运行的执行程序
输入:gdb调试运行的可执行程序
2,退出调试
(gdb)q
3.gdb命令
|命令|作用
|:-|:-|
|r| run 执行被调试的程序,会执行到第一个断点(如果没有断点则执行程序)
|b|break 设置断点:在源代码中指定某一个设置断点 b
|c|continue 当程序在某一个断点暂停
|n|next 程序执行一行代码,执行当前的代码
|s|step 执行一步代码,通常是执行一行,但是如果这一行是函数,就代表
|p|print打印变量的值,
C语言高级
1.调试
2.指针与数组
指针(重点)
程序的执行都在CPU中执行,在磁盘上的程序需要把程序的指令拿到CPU中执行,
效率不高,
在程序执行所有内容都存储在内存中,
在程序中定义一个变量(int=10),
将是数据10存储到变量a中,a变量就是所占用4个字节空间的数据,
占用对应内存空间,那么数据存储到存储某个地方,就涉及到地址。
在计算机,就是靠变量的地址,可以访问变量中的数据
存储数据,需要存储的内存地址
定义一个变量要占用一个空间,内存空间有地址来区别,所以变量名也只是表示了不同空间
程序中通过一个变量来定义变量,在内存中使用内存空间存储数据
1.指针变量:
内存地址也是一个数据,那么可不可以用一个变量来存储内存地址,把使用变量来存储地址----
这种存储地址的变量就叫做指针变量(指针)
***指针就是存储一个数据内容的内存地址的一种数据类型(指针类型),即指针的内容就是另一个变量地址***
指针存储地址
地址是没有类型
指针两层含义:
1.指着首先是一个变量,就拥有变量的所有属性 :值和类型。它的类型就是指针,值就是另一个变量的地址
指针变量把
2.指针所指向(存储哪个地址,就表示指向地址对应的空间)存储地址
2.指针变量定义
在定义指针时,存储变量的地址。指针存储地址后,怎么直到存储的地址对应的空间到底是什么类型数据,如:p=0x10地址,怎么直到0x10地址对应的空间中是什么数据,所以定义指针变量是,确定
指针存储的地址对应空间的数据类型
定义指针变量:
指向数据类型*指针变量名;
指向类型:是指在这个指针变量指向的数据类型,即指针变量存储地址,指针到底存储的是那种数据类型
数据的地址
3.指针的运算
指针变量是可以存储数据的,打是存储的数据是地址
对应指针的运算只能有部分运算
对于指针的运算也是对地址的运算
px表示指针变量
+(加法):
px+n:指针px向着地址增大的方向移动n个
4.指针变量的大小
对于指针类型,对于指针在定义时说明的实存储哪些变量的地址,
存储的数据类型和数据不是同一个内容
不管任意类型的指针变量,指针变量的大小都是一样的,
在32位系统4字节,在64位系统
5.普通指针与一维数组连续的空间,在这段空间中每一个
一维数组:在内存中数组的元素是一段连续空间
访问数组:由于数组是连续元素后一个/后一个
由于数组元素是连续的,元素地址是相邻的,只要指针存储了元素的地址,
可以使用(+ - )得到数组其他元素地址。
只要数组第零个元素的地址,就可以访问整个数组
对于数组而言,数组名有一定特殊含义,表示数组的首地址
&\a[0]:数组首地址 ==a;
a==&a[0]:数组名就表示数组的首地址
由于数组元素是连续的,元素地址是相邻的,只要指针存储了元素的地址,
可以使用用(+,-)得到数组其他元素的地址
a+1(a存储地址对应类型a[0]----int)
a+n:移动n个数组元素大小的地址,可以移动到数组的每个元素的地址
\*(a+n):取对应地址中的数据===a\[n]
如:int a[5];
a\[2]==*a[a+2]
指针变量存储地址,可以存储数组首地址
int *p=a;//或
指针和数组在本质上还是存在区别
数组名还是要表示整个数组(有整个数组空间存储数据)
指针还是表示存储地址(指针大小为4/8,只是存储地址而言)
数组名是一个常量
7.普通指针与字符数组
对于字符串数组如果是按照字符串进行操作(整体操作,‘0‘结束)
字符数组按照字符串方式,只需要字符串组的首地址就可以操作一个字符串。
指针:存储地址,存储字符串数组的首地址,
这个指针就可以当作数组名操作(指针可以代表数组名----数组首地址)
char *p=buf;//p就代表字符数组首地址
scanf(“%s”,p);//输入字符串到buf数组中
常量字符串:
8.多级指针:
一级:
二级:
三级:
2、指针数组
指针数组:
指针数组就是一个数组,数组中的每一个元素是一个指针
定义:
指针类型 数组名[元素个数]
指正类型:指向数据类型 *
如:
存储5个整型的地址:
int* a\[5]
a数组有5个元素,每个元素都是指正,指针:
指针存储int类型的地址
指针数组还是数组,数组名表示数组首地址;
二级指针可以和指针数组相互替换使用
9.数组指针和二维数组
二维数组:
数组的每一个元素也是一个数组,就把这种数组叫做二维数组
以为数组元素类型,二维数组名[二维数组元素个数][一维数组元素个数]
二维数组中每一个数组元素是一个一维数组,是一维数组的集合,数组是以为数组
是普通数据
3.指针在函数中的使用
1.指针在函数中的定义使用
2.指针作为函数的参数使用
函数的参数为指针(地址),在调用是传递地址,可以得到地址,可以通过地址访问对应内存空间。
返回类型 函数名(指向类型)
调用:
函数名(地址,.....)
如果函数的参数是舒张压类型,在调用时实参就需要数组,但是对于数组而言实参的添加只能是数组名,形式参数的指针就自动退化为对应的指针类型
如:
int a[10]-----int *p;
int *a\[10]----int **p;
int a\[3]\[5]---int(*p)[5];
3.指针类型作为函数的返回值
函数的返回值是指针:也叫做指针函数
指针类型 *函数名()
{
}
函数的结果为一个数据的地址
4.函数指针
在执行程序时,函数在使用时也是存储在内存中(函数就有存储的地址)
所以在调用函数是也是找到函数的地址然后执行函数的内容
函数是存在地址的
函数名 就表示函数的地址
函数指针:用于存储函数的地址指针变量
由于函数的返回值,参数列表的类型都可能各部相同,表示一个
函数都由这几个部分影响,对于函数而言不同返回值,不同参数的函数类型
定义函数指针:
返回类型*指针名(参数列表);
函数指针的使用:
调用函数的指针 对应的函数
函数的
函数类型*p;
2.define
define:内容的替换,是什么内容就原样替换出来,也叫做宏定义
\#define 定义的名字 被替换的内容
如:#defineN10
表示用N来替换10,只要之后使用N就是使用10
(10使用N来替换)
#define p_int int*
存储类型关键字:定义的变量的位置
auto:表示自动存储管理(自动分配,自动释放 )
表示在区存储局部变量,如果局部变量没有添加存储
类型,
register寄存器数据类型:把数据存储到CPU中存储
单元,在执行时,如果能够存储到CPU就进行存储,
CPU已经不能分配,则当作普通窜出类型auto存储
extern提供一个全局变量的引用,在其他文件中定义一个变量,
现在在当前文件要使用其他文件定义的
7.自定义类型(构造类型)
有些数据的表示不能够用 单一的数据类型就能表示出来,
C语言中就赋予类型的扩张型,可以按照C语言允许的方式去自己添加类型,这种叫做构造类型
1.结构体类型
把基本数据类型符合在一起构成新类型,结构类型就是有多个部分构成,共同组合表示一个王城的信息内容
声明结构体:
struct结构体名
{
数据类型1, 成员名1;
数据类型2 成员名2;
.......
};
定义结构体变量:
struct结构体名 变量名;
结构体变量时一个整体,包含了多个成员需要单独结构体变量的成员进行操作
.,成员运算符
结构体变量名.成员名---->访问结构体变量某个成员
结构体变量初始化:
struct 结构体名 变量名={值};
使用结构体指针访问结构体变量:
结构体指针:struct结构体名 *指针名;
指针名->成员名
结构体类型的大小:
2.联合体(共用体)
和结构体类似,也是多个成员符合的类型(多个成员组成)
多个成语公用同一份内存空间
union联合体名
{
数据类型1 成员名1;
数据类型2 成员名2;
数据类型3 成员名3;
......
};
多个成员共用一个空间,每个成员没有单独的空间,空间大小
是最大成员的空间能够整除共用体时,同一时间只能使用一个成员,成员使用
完,才去使用其他成员
3.枚举类型
在使用 之前就已经把类型能够取值的范围意义列举出来,在定义类型
变量是变量就只能从中取值
8.字符串的相关函数
strcpy:字符串的拷贝
9.动态内存
在C语言内存分配中,存在一段内存空间,有我们程序员自己来申请内存空间进行
使用,申请多大,什么时候申请,什么时候释放都是通过我们写的
程序决定,叫做动态内存 -------堆
申请内存:
释放内存:
10.多文件编程
编程程序是,通常一个文件来编写程序,会造成文件中
代码非常庞大不利于阅读,通常程序会使用多个文件来编写
-----多文件编程
头文件:存放各种声明
普通文件 -
目录文件 d
符号链接文件 l
管道文件 p
套接字文件 s
字符设备文件 c
块设备文件 b
编写头文件,进行声明
头文件:存放各种声明内容
编译时,多个文件都进行编译合成一个可执行程序
在多个文件中相互调用,在调用的文件使用声明
(#include“头文件”)
编译:gcc xxxx1.c xxx2.c xxx3.c
gcc编译流程:
1、预处理
处理宏定义,引入头文件等----处理#开头的内容
------.i
2、编译
把C程序翻译成汇编代码 -----.s
gcc -S xx
3、汇编
将汇编代码防疫为二进制机器码
4、链接
将多个二进制文件链接在一起合并成一个可执行程序
gcc xxx1 xxx2 xxx3
make工程管理器
它是一个用于管理编译工程辅助作用的工具软件
make工具是根据文件的描述来进行管理
----文件:makefile(Makefile)
makefile文件编写格式::
目标:依赖(可以没有)