1、Linux系统基础
1.1、什么是Linux
通常Linux就是指代的是Linux内核:能够让计算机跑起来。
Linux操作系统:
Linux内核 + 应用 / 系统软件 构成方便用户进行操作使用的系统。
Linux内核开源,支持多任务、多用户。
Linux是免费开源的内核程序
Linux操作系统:ubuntu、debian、deepin、red hat、centos等。
1.2、Linux系统的体系架构
1.2.1、内核
内核是Linux系统中最底层,提供系统中核心功能并允许有序访问硬件资源。
用于管理:
输入输出设备、进程的执行情况、文件系统的操作、内存管理。
Linux内核支持:
多任务、多用户。
1.2.2、文件系统
文件系统就是用于组织内存和管理计算机存储设备上的大量文件。
windows中使用NTFS文件系统格式
Linux中格式多,目前通用EXT4文件系统格式。
Linux文件系统的逻辑结构(Linux目录结构):
Linux中文件系统把文件组织位倒置的树,每一个文件夹(目录)当作树的分支。
文件系统只有应该起始点,叫做:根( / )。
Linux文件系统把一切所有内容都看作是文件 ----- Linux一切皆文件。
Linux文件系统就是一个倒置的树形结构:
将 / 作为整个文件系统的起点,其他的所有目录都是从根开始的。
/:根目录
/bin:存储系统中最常用的可执行程序。
/boot:存储Linux系统的启动文件。
/dev:存储系统中的设备文件,包括硬盘、鼠标、键盘等。
/etc:存储系统的配置文件,如passwd存储用户信息。
/home:普通用户的家目录位置。
/lib:存放共享库。
/media:存储cd、软盘、usb临时读入的文件。
/mnt:挂载的文件系统挂载点。
/opt:作为可选程序和文件存放目录。
/proc:当前执行的进程的文件存储目录。
/root:超级用户的家目录。
/sbin:作为扩展的,更多的二进制程序存储目录。
/usr:标准库、第三方存储目录。
1.3、shell命令
shell叫做命令解释器,当执行程序时,把程序的各种操作命令进行解释执行,通过命令解释器让内核执行对应操作,可以提供一种用户与操作系统交互的方式。
shell完成内核与用户之间的交互。
shell命令:
向系统内核发出控制请求。
shell解释器:命令解释器,将用户的命令解析位操作系统能够理解的指令,实现用户与内核交互。
shell命令的输入,在终端提示符标识了命令的开始。
终端提示符:
ubuntu @ linuxmachine : ~ $
用户名 分隔符 计算机名 分隔符 当前工作路径 用户权限
shell命令格式:
命令 + 选项 + 参数
command + [option] + [argument]
commadn:命令,shell要解析的内容,要执行的内容。
argument:命令作用(执行)的目标。
有时,命令不一定要携带选项和参数,通常表示使用默认的选项和参数
man command:查找手册中命令command使用说明帮助。
绝对路径与相对路径:
路径:找到某个文件,所经过的目录就叫做路径。‘
绝对路径:从根目录( / )开始所经过的目录扎到对应的文件所经过的目录。指文件在文件系统中的准确位置。
相对路径:从当前的工作目录开始,找到文件所经过的目录就是相对路径。指文件在当前目录的相对位置。
1.3.1、目录命令
- pwd:用于查询显示用户当前的工作路径(用户在文件系统中的位置路径)。
pwd没有选项和参数
- cd:改变用户当前工作路径
cd + 新工作路径
~:当前用户的家目录
. :当前工作目录
.. :上一级工作目录
- mkdir:创建目录文件,在指定路径下创建目录。
mkdir [选项] [要创建目录路径] 新目录名
-p选项:如果副目录不存在则一起创建。
- rmdir:删除空目录。
rmdir [选项] [要删除目录路径] 目录名
-p选项:如果目录中还有其他目录,将一起删除。
- ls:列出目录或文件的信息内容。
ls [选项] [目录路径]
ls:列出当前工作目录的所有内容。
-a选项:查看所有文件(显示隐藏文件)。
-A选项:列出所有文件,包括隐藏文件,但不包括 . .. 。
-i选项:显示所有文件的indoe号(每个文件的唯一标识号)。
-l选项:列出每个文件的详细信息。
drwxr-xr-x 2 ubuntu ubuntu 4096 7月 17 17:23 Desktop
文件类型 | 文件权限 | 文件硬链接 | 文件所有者 | 文件所属组 | 文件大小 | 文件最近修改日期 | 文件名 |
-:普通文件 d:目录文件 p:管道文件 s:套接字文件 c:字符设备文件 b:块设备文件 l:符号链接文件 | 文件只有三种权限: 读(r)、写(w)、执行(x) 有权限为1,没权限为0 显示: 有权限:rwx,没权限:---。 分三组(每组三位,分别表示三种权限): 所属用户、所属组、其他用户 | 相同文件的数量 | 当前文件所属者(即按照第一组权限访问) | 文件用户的组(即按照第二组权限访问) | 当前文件的大小字节 | ||
目录权限: r:能够查看目录中的文件。----ls w:能够在目录下创建、删除、修改文件。 x:能够访问进入目录。----cd | 普通文件:相同文件个数。 目录文件:子目录的个数。 | 目录大小固定位4096 |
1.3.2、文件命令
- cat:读取指定文件的内容(查看文件)
cat [选项] [文件路径] 文件名
-n选项:添加行号。
-E选项:在每行结束末尾田间$符号。
- head:查看文件前几行(默认前10行)
head [选项] [文件路径] 文件名
-n选项:显示前n行。
- tail:查看文件后几行(默认后10行)
tail [选项] [文件路径] 文件名
-n选项:显示后n行。
- touch:在对应路径下(必须存在)创建普通文件
touch [选项] [文件路径] 文件名
如果文件名存在,则改变文件的最后修改时间
- file:判断文件类型
file 文件名
- diff:比较两个文件的不同
diff 文件1 文件2
- cp:将文件拷贝到指定目录中
cp [选项] 源文件路径 目标文件路径[/文件名(拷贝后重命名)]
-r选项:拷贝目录。
- mv:将源文件移动到指定目录中
mv [选项] 源文件路径 目标文件路径[/文件名(移动后重命名)]
- rm:删除目标文件
rm [选项] 目标文件路径
-r选项:删除目录。
1.3.3、操作命令
- 链接文件:符号链接文件、硬链接文件。
符号链接文件(软链接):创建一个快捷方式,操作符号链接文件就是操作源文件,但是删除符号链接对源文件无影响,删除源文件符号链接无法使用,相当于一个快捷方式。
硬链接文件:在文件系统中,创建一份与源文件完全一致的文件,创建的文件和源文件保持一致,但是删除其中一个文件对另外一个文件无影响。
命令:ln [选项] 源文件 目标文件(硬链接文件)
-s选项:创建为符号链接文件(软连接文件)
- 修改文件权限(读、写、执行):执行命令的用户要求是对应要修改权限文件的所有者,才能够修改(普通用户只有修改自己文件的权限)。
命令:chmod 权限值 文件名
权限值表示方式:
用数字表示:直接写九位二进制权限(通常用八进制表示 --- 三位二进制表示一位八进制)
用字符表示:
[u(user)][+ / -][r、w、x],表u示用户部分 添加 / 删除 对应权限
[g(group)][+ / -][r、w、x],表示用户组部分 添加 / 删除 对应权限
[o(other)][+ / -][r、w、x],表示其他用户部分 添加 / 删除 对应权限
超级用户拥有修改所有用户文件的权限
sudo:临时使用(获取)root用户身份(管理员)来执行命令。
使用方法:sudo + 命令
在创建文件时,默认权限:
普通用户:0664
目录文件:0775
- 改变文件所属用户:只有管理员root才能执行
命令:chown 新用户名 文件
- 改变文件所属用户组:只有管理员root才能执行
命令:chgrp 新用户组 文件
1.4、用户与用户组管理
1.4.1、用户管理
- 修改用户密码
命令:passwd 用户名 ---- 只能修改当前用户的密码
提升管理员身份修改用户密码:
sudo passwd 用户名
- 切换用户
命令:su 用户名
- 退出当前登录用户:
命令:exit
- 创建新用户:只有root用户才能新建。
命令:sudo adduser 新用户名
新建用户无sudo权限
如果需要添加sudo权限,则需要在sudoers(/etc中)文件中添加 新建用户的用户名
vim /etc/sudoers
在文件末添加:
新用户名 ALL=(ALL:ALL)ALL
- 删除用户:只有root用户才能新删除
命令:sudo userdel -r 用户名
-r:找所有名字为 要删除用户名的用户。
1.4.2、用户组管理
- 创建用户组:
命令:sudo groupadd 用户组名
- 将用户添加到用户组:一个用户可以拥有多个用户组
命令:sudo gpasswd -a 用户名 用户组
- 查看用户对应用户组:
命令:groups 用户名
- 将用户从用户组中删除
命令:sudo gpasswd -d 用户名 用户组
- 删除用户组
命令:sudo groupdel 用户组名
1.5、linux的压缩与解压
压缩:先进行归档合并为一个文档,再进行压缩
解压:先进行解压操作,然后对归档文件进行释放
1.5.1、归档与释放
- 归档文件:把多个文件打包成一个文件
创建归档文件:
tar -cvf 归档文件名.tar 文件1 文件2 ... ...
- 释放文件:把归档的文件释放成多个文件
tar -xvf 归档文件名.tar
1.5.2、压缩与解压
1.5.2.1、使用gzip算法对文件进行压缩与解压
-z ---- 使用gzip算法对文件进行压缩与解压
- 压缩:把多个文件先归档打包成一个文件,然后使用gzip算法进行压缩
tar -cvzf 压缩文件名.tar.gz 文件1 文件2 ... ... //先归档再压缩
- 解压:先使用gzip解压,再把文件释放。
tar -xvzf 压缩文件名.tar.gz
1.5.2.2、使用bzip2算法对文件进行压缩与解压
-j ---- 使用bzip2算法对文件进行压缩与解压
- 压缩:把多个文件先归档打包成一个文件,然后使用gzip算法进行压缩
tar -cvjf 压缩文件名.tar.bz2 文件1 文件2 ... ... //先归档再压缩
- 解压:先使用gzip解压,再把文件释放。
tar -xvjf 压缩文件名.tar.bz2
1.5.2.3、使用zip算法对文件进行压缩与解压
- 压缩:
命令:zip 压缩文件名.zip 文件1 文件2 ... ...
- 解压:
命令:unzip 压缩文件名.zip
1.6、输出重定向
- >:指定输出到某个文件,会先清空对应位置的内容
输出到终端命令 > 文件
- >>:指定输出到某个文件,以追加的方式输出到指定位置
输出到终端命令 >> 文件
- echo
向终端输出指定。
1.7、软件安装
1.7.1、直接执行二进制程序进行安装
直接执行.exe文件进行软件安装。
1.7.2、包管理工具安装
解析软件包,查找对应的依赖环境,然后安装软件。
- debian linux 软件包机制 ----- 解析 .deb
a、本地离线安装(本地软件包管理)
dpkg:离线包安装
安装命令:sudo dpkg -i 软件包名
卸载命令:sudo dpkg -r 软件名
b、在线安装(在线软件包管理)
在线安装,在计算机中需要配置软件镜像源(软件从哪里下载) ----- /etc/apt/sources.list 软件源地址
apt:在线包管理工具(早期版本:apt-get)
apt就是用于获取安装、编译、卸载、查询于一体的包管理工具,自动检查软件的依赖是否安装。
apt软件管理使用:
sudo apt update:下载(获取)并更新软件源地址中的软件包列表。
sudo apt install 软件包名:下载安装对应的软件。
sudo apt --reinstall install 软件包名:重新再次安装。
sudo apt remove 软件名:卸载对应已安装的软件。
sudo apt clean:清除下载的安装包。
- red hat linux 软件包机制 ----- 解析 .rpm
- 检查网络信息:
ping ip地址或域名:查看是否与对应的ip地址或域名连通,测试网络连接是否正常。
ifconfig:查询本机网络信息(需下载:net-tools)。
1.8、服务器安装与配置
1.8.1、nfs服务器
网络文件共享服务器:提供主机目录用于共享,当客户端来连接这个服务器后,就可以使用我共享的目录。
1、安装nfs服务器软件
服务器:nfs-kernel-server
sudo apt install nfs-kernel-server
2、修改nfs服务器的配置
因为服务器功能为共享文件夹,要修改对应的共享文件夹目录。
sudo vim /etc/exports ----- nfs配置文件(每修改一次配置,需重新启动)
添加:/home/ubuntu/nfsserver *(rw,sync,no_subtree_check)
/home/ubuntu/nfsserver:要共享的文件夹
*:允许那些客户端的ip地址访问nfs服务器。
():客户端允许的功能。
rw:允许读写。
sync:操作文件后同步更新。
no_subtree_check:不检查父目录权限。
如果共享文件夹不存在,则创建对应目录,并设置权限(一般设置777)
3、启动nfs服务器
设置服务器端口为监听状态(开启监听)
sudo service rpcbind start
启动nfs服务
sudo service nfs-kernel-server start / restart / status / stop [启动 / 重启 / 查看状态 / 关闭]
4、查看nfs共享的目录
showmount -e
5、客户端的连接
linux:
连接:mount -t nfs 服务端ip:/共享目录路径(绝对路径) 挂载的位置(通常为 /mnt)
windows:
连接:mount \\服务端的ip地址\共享目录路径(绝对路径) X:(挂载到windows哪个盘,X可以自己取,需为windows没有的盘符名)
断开(解除挂载):umount X:
1.8.2、tftp服务器
tftp:文件上传下载服务器
tftp:tftp文件上传下载服务器功能,提供一个文件夹(目录),可以让其他的客户端从这个目录下载文件,或上传文件到这个目录。
tftp-hpa客户端
ftpd-hpa服务器
1、安装tftp服务器
sudo apt install tftpd-hpa
提供了服务端功能:上传、下载。
2、配置tftp服务器提供的操作功能
sudo vim /etc/default/tftpd-hpa
文件内容:
TFTP_USERNAME="tftp" ------ 服务器程序名。
TFTP_DIRECTORY="/home/ubuntu//tftpboot" ------ 提供了可以进行上传下载的目录(只能把文件上传到这个目录,和从这个目录下载文件)。
TFTP_ADDRESS="0.0.0.0:69" ------ 服务器tftp程序的地址。
TFTP_OPTIONS="-l -c -s" ------ 提供的功能
3、启动tftp服务器
sudo service tftpd-hpa start / restart / status / stop [启动 / 重启 / 查看状态 / 关闭]
4、客户端进行上传文件到tftp服务器,从服务器下载文件。
下载客户端:
sudo apt install tftp-hpa
使用:
命令:tftp 服务端地址
tftp> put 文件名:上传文件(只能上传当前目录文件)
tftp> get 文件名:下载文件(只能下载到当前目录文件)
tftp>q:退出tftp客户端
1.9、通配符
通配符 | 作用 | 例子 |
* | 可以表示匹配任意的字符串 | 1*2.txt:表示可以匹配1开始2.tx结束t的所有名字。 如:11231232.txt、1abc2.txt |
? | 匹配一个长度的字符 | file_?.txt:表示可以匹配file_?开始,中间只有一个字符,以.txt结束的名字。 如:file_1.txt(可以),file_12.txt(不可以) |
[匹配字符] | 从方括号中取一个匹配字符进行匹配 | file_[abc123].txt:只能匹配以file_开始,中间是[abc123]其中一个字符,以.txt结束的一个名字。如:file_a.txt(可以),file_5.txt(不可以) |
[起始范围-结束范围] | 从方括号中取一个对应范围内的字符进行匹配 | file_[a-k].txt:只能匹配以file_开始,中间是a-k其中一个字符,以.txt结束的名字。如:file_a.txt(可以),file_z.txt(不可以) |
[^不匹配的字符] | 除了方括号中的字符,其他字符匹配一个 | file_[^abc].txt:除了a、b、c字符,其他字符可以进行匹配一个。 如:file_1.txt(可以)、file_e.txt(可以)、file_a.txt(不可以) |
1.10、shell脚本
将shell命令按照一定的逻辑关系、顺序组织在一个文件中,组合成一系列完整的功能要求,执行文件就可以将其中的shell命令按照对应顺序逻辑执行。
shell文件就是以 .sh 作为结尾的文件。
- 执行shell脚本(文件)
1、为shell脚本文件添加可执行权限。
可执行文件的执行:
可执行文件的路径 + 文件
./可执行文件名字
2、使用对应的shell解释器来解析执行
在当前ubuntu安装使用的是bash shell解释器
bash 文件名.sh
3、在shell文件中,通常先添加shell解释器的版本说明(使用哪个解释器):用 # 表示
#!/bin/bash --- 解释说明
- shell语法
实现shell脚本的逻辑功能
1、变量
变量:所有变量传递的值都是字符串
定义:变量=值(变量一般大写)
引用(使用)变量:$变量
变量在单引号(' ')中使用不会解析引用变量;在双引号(" ")中使用,会解析引用变量。
2、变量的输入
在shell脚本中,使用read表示输入字符串到变量中:
red 变量1 变量2 ... ...
shell脚本中存在特殊变量,叫做位置变量:ls(命令) -l(参数1) ./(参数2) … …
$1:在线shell脚本时,获取命令行传递的第一个参数
$2:在线shell脚本时,获取命令行传递的第二个参数
... ...
$9:在线shell脚本时,获取命令行传递的第九个参数
$@ / $*:获取命令行传递的所有参数
$?:获取上一条命令执行状态值(成功与否),成功值为0,否则为非0。
3、条件判断
判断条件:test
字符串的判断方式:(s1、s2为变量)
test $s1 = $s2:判断相等
test $s1 != $s2:判断不等
test -z / -n $s1:判断字符串长度是否等于0 / 是否不为0
整数的判断:a、b表示数字字符串(a、b为变量)
test $a -gt / -ge $b:判断 a 是否 大于 / 大于等于 b
test $a -lt / -le $b:判断 a 是否 小于 / 小于等于 b
test $a -eq / -ne $b:判断 a 是否 等于 / 不等于 b
文件的判断:
test -d / -f / -L filename:判断filename是否是目录 / 普通文件 / 符号链接文件
test -e / -s filename:判断filename文件是否存在 / 是否存在且不为空
test -r / -w / -x filename:判断filename存在且是否可读 / 写 / 执行
4、逻辑运算
条件1 -a 条件2:逻辑与,多个条件都为真,结果为真。
条件1 -o 条件2:逻辑或,只要有一个条件为真,结果为真。
!条件:得到的条件取反。
5、if选择结构
语法1:如果满足条件表达式,则执行命令,不满足则跳过。
if [ 条件表达式 ]
then
命令
fi
语法2:如果满足条件表达式则执行命令1,不满足则执行命令2
if [ 条件表达式 ]
then
命令1
else
命令2
fi
语法3:如果满足条件表达式1,则执行命令1,不满足则判断表达式2,满足则执行命令2,... ... 直到最后一个条件为止。
if [ 条件表达式1 ]
then
命令1
elif [ 条件表达式2 ]
then
命令2
... ...
elif [ 条件表达式n-1 ]
then
命令n-1
else
命令n(都不满足则执行)
fi
6、循环结构
算数运算指令:expr
`expr $1 + $2` ---- ` ` 执行这个指令得到结果(tab上面的那个按键)
while循环:
while [ 条件表达式 ] ----- 当满足条件就在线一次
do
命令表
done
for循环:
for 变量名 in 单词表 ----- 如果变量名能够从单词表中取出一个值(单词 ---- 以空格或换行隔开的为一个单词),就执行一次循环
do
命令表
done
C语言for循环格式
for((循环初始语句; 循环条件语句; 条件改变语句))
do
命令表
done
7、函数
函数:实现一个完整功能步骤,需要时直接使用
函数定义:
函数名()
{
命令集合
}
函数掉用:
函数名
带参函数:
如果函数功能需要参数,函数的()中不用写参数,使用位置变量$1,$2,$3作为函数参数来传递参数值。
函数掉用时:
函数名 "参数1" "参数2" "参数3" ... ... ---- 参数1用$1指代,参数2用$2指代... ...
函数返回值:
echo $要返回的变量 ----- 在函数中执行echo命令时,为输出显示;如果函数掉用时有变量赋值,这时echo为返回值
如:i=`add 1 2`,此时echo为返回值,可以使用 echo $i 输出变量 i 的值
2、C语言高级
2.1、指针
指针:在内存空间(定义变量)中申请空间用来存储地址,就叫做指针,也叫指针变量。
指针·就是·操作内存地址,使用内存地址。
2.1.1、指针的定义
- 指针变量的本质就是一个变量。
- 指针变量的定义:
数据类型 *指针变量名
数据类型:储存在哪种数据类型的地址,就指向哪种类型,因此要存储那种数据类型的地址,就定义哪种数据类型。
2.1.2、指针的使用
指针变量 = 地址(要求地址的空间能够使用)
变量地址的获取:通过 & 取地址运算符
指针变量 = &变量名
用变量名来表示代表变量中的值。也可以通过指针来访问变量,指针对所指变量的访问采用间接访问运算符 * 。
*指针名 访问对应地址的数据
指针变量赋值地址:通过指针建立与对应内存空间的联系。
指针取 * :得到建立联系的内存空间的值。
int main()
{
int a = 5, *p;//定义变量a,指针变量p
p = &a;//将a的地址赋值给指针变量p
printf("*p = %d, a = %d, p = %p, &a = %p\n", *p, a, p, &a);
float b, *q;
q = &b;
*q = 2.1;//通过间接访问运算符*来给b赋值
printf("*q = %f, b = %f\n"); return 0;
}
//输出结果: *p = 5, a = 5, p = 0x7ffc8fe4462c, &a = 0x7ffc8fe4462c
//输出结果: *q = 2.100000, b = 2.100000
- 指针变量的初始化:
在定义指针变量时进行赋值,就叫做初始化;
类型 * 指针名 = 地址;
- 野指针
指针记录的地址不明确(存储的地址不知道,或地址对应空间是否具有操作权限不确定),这种指针称为野指针。
野指针不需要直接进行取 *。
- 空指针
指针记录的地址是NULL(地址:0x00)。 ----- 系统规定,NULL地址不允许进行操作,只要操作就会报错。
- 万能指针
void * 类型指针变量,可以存储任意类型的地址,且可以赋值给任意类型的指针。
void *指针,只能存储地址,不能进行取 * 操作。
2.1.3、指针的运算
- 指针 + / - 整数
往指针地址 增大 / 减小 方向移动整数个指针指向类型的大小。
- 指针++ / --
先使用指针,然后 指针 = 指针 + / - 1。
- ++ / -- 指针
先 指针 = 指针 + / - 1,再使用指针。
- 指针 - 指针
获取两个指针之间间隔多少个对应类型的数据。
2.1.4、指针与数组
2.1.4.1、指针与一维数组
一维数组是一段连续的空间存储多个数据元素,在数组中相邻的元素,间隔大小为每个元素数据类型的大小,即 &数组名[元素i] == &数组名[元素i-1] + 数组数据类型大小。
指针能够进行运算,指针 + 1相当于移动一个数据类型的大小,即 指针 + 1 == 指针 + 指向数据类型大小。
如果指针变量存储了数组中的元素地址,指针 + 1,就是数组中下一个元素的地址。因此只要知道数组的起始地址(第零个元素的地址),可以通过指针访问整个数组。
在数组中,数组名就表示数组的首地址。
数组首地址(数组名) + n:偏移n个数据元素大小
*(数组名 + n) == 数组名[n]
因为数组名可以表示数组首地址,而指针变量也可以存储数组首地址,在访问数组的操作时,指针变量和数组名作用一致,所以:
数组名[n]:访问数组的n元素 == 指针名[n]
2.1.4.2、字符串与字符数组
字符串:有多个字符组成一个连续且有序的字符序列。----- "abcdef" >>> 字符串
C语言中,通过字符数组来存储字符串。
字符数组通过访问数组中的元素,就是访问字符串。
如果需要整体访问字符数组中存储的字符串,要求在字符串结束的下一个字符位置存储 '\0'。
'\0'字符表示字符串结束。
- 字符串输数组存储字符串
通常在进行输入输出前把数组初始化为 '\0'。
1、字符数组初始化
char 数组名[数组大小] = "字符串"; ---- 会在后面默认有一个 '\0';
带有元素初始化可以省略数组大小,此时字符串字符大小为字符个数加1。
2、输入字符串存储到字符数组中
scanf("%s", 数组名);
- 输出打印数组中的字符串
printf("%s", 数组名); //打印数组中的所有字符,直到 '\0' 结束。
- 常量字符串的表示:
"abcde" ----- 常量字符串
在常量字符串中,在最后字符串后默认包含 '\0' 字符
在程序中如果写出常量字符串,则常量字符串表示字符串的首地址(第零个字符地址)
- 指针类型的地址都是统一大小:
32位机器:4B
64位机器:8B
2.1.4.3、指针与二维数组
二维数组:二维数组中,每个元素是一个一维数组,在元素(一维数组)中,每个成员就是一个值。
定义:数据类型 二维数组名[行][列]
行:有多少个一维数组
列:每个一维数组有多少个元素
对于二维数组而言,数组名是整个二维数组的首地址,第零个元素的地址,二维数组的元素都是一维数组;即二维数组名表示其中元素,整个一维数组的地址。
数组指针
是一个指针,这个指针用于存储整个数组的地址,指针的指向类型位数组。
定义格式:
数组元素类型 (* 指针变量名) [大小]
int (*p)[4]; // 定义一个指针变量,指针变量存储了整个数组的地址。
数组指针和二维数组名是等价的,因为二维数组表示第零个元素(一维数组)的地址。
2.1.5、指针数组与多级指针
- 指针数组
是一个数组,只是每个元素为指针类型。
定义格式:
指向类型 * 指针数组名字[元素个数];
例:
int * p[5]; ----- 定义包含5个元素,每个元素为指针(int *)
- 多级指针
一级指针:存储变量的地址;
二级指针:存储一级指针的地址;一级指针类型 * 指针名
三级指针:存储二级指针的地址;二级指针类型 * 指针名
... ...
指向类型 * 指针名
2.1.6、指针与函数
- 指针作为函数的参数
把地址作为参数进行传递。
返回值类型 函数名(指针参数1, 指针参数2); 接收传递的是地址。
调用:
函数名(地址 / 指针,地址 / 指针)
如果数组作为参数,会有编译器自动变为对应类型指针。
- 二维数组作为参数
参数为数组指针或二维数组。
- 指针作为函数返回值
作用:返回一个地址。
返回值类型为:数据类型 *
- 函数指针
指针存储的是函数的地址。
指向类型 * 指针变量名
指向类型:函数类型
函数类型表示:返回值类型 (参数1, 参数2,... ...); ---- 除了函数名,其余都是函数类型。
函数指针表示:
返回值类型 (*指针变量名) (参数1, 参数2,... ...)
例:
int (* p)(int, int) --- 存储了返回值类型为int, 参数为int、int函数的地址
只能存储对应类型的地址。
函数名就用于表示函数的地址。 ----- 例:p = 函数名。
掉用函数:
通过函数指针进行掉用。
函数指针名(实参);
2.2、构造类型
由于基本数据类型不能满足需要,需要把多个的数据类型进行组合,共同表示新的复合数据,形成新的类型。构造新的数据类型的方式就叫做构造类型。
结构体(struct)
使用多种数据类型作为成员,进行组合,构成新的类型,就叫做结构体。
-
声明:结构体的类型表示
struct 结构体名
{
类型1 成员1;
类型2 成员2;
... ...
};
在程序中添加一种新的类型,不占用内存空间,只是说明在程序中有一种新类型。
-
定义结构体变量
数据类型 结构体变量名;
数据类型:struct 结构体名
-
结构体的访问
结构体变量名.成员名;
#include <Stdio.h>
#include <string.h> //结构体的定义
struct people
{
//姓名
char name[20];
//年龄
int age;
//性别
char sex;
};
char * mystrcpy(char * dest, char * src)
{
while(*src)
*dest++ = *src++;
*dest = '\0';
return dest;
}
int main()
{
//定义结构体变量
struct people p1, p2;
//结构体的访问
strcpy(p1.name, "zhangsan");
p1.age = 10; p1.sex = 'm';
printf("姓名: %s, 性别: %c, 年龄: %d\n", p1.name, p1.sex, p1.age);
scanf("%s", p2.name);
scanf("%d%*c", &p2.age);
scanf("%c", &p2.sex);
printf("姓名: %s, 性别: %c, 年龄: %d\n", p2.name, p2.sex, p2.age);
return 0;
}
-
结构体变量的初始化
在定义结构体变量时,对其成员进行初始化。
顺序对成员进行初始化:
syruct 结构体名 变量名 = {成员1值,成员2值,... ...};
指定成员初始化:
syruct 结构体名 变量名 = {.某个成员名 = 值1,.某个成员名 = 值2,... ...};
#include <stdio.h>
struct student
{
char id_no[20];
char name[20];
int age; float height;
};
int main()
{
//方法1:全部初始化
struct student s1 = {"1001", "zhangsan", 20, 185.1};//也可以:s1={{'1', '0', '0', '1'},"zhangsan, 20, 185.1"}
//方法2:部分初始化
struct student s2 = {.name = "lisi", .age = 22};//未初始化的部分为0;
printf("学号: %s, 姓名: %s, 年龄: %d, 身高: %.2f\n", s1.id_no, s1.name, s1.age, s1.height);
printf("学号: %s, 姓名: %s, 年龄: %d, 身高: %.2f\n", s2.id_no, s2.name, s2.age, s2.height);
return 0;
}
-
结构体指针如何访问变量的成员
结构体指针:
struct 结构体名 * 指针名 = 结构体地址;
例:
struct student * p = &s1;
访问方式:
指针 -> 成员; //访问结构体指针对应地址中的成员
(*指针).成员;
例:
p->name;
-
结构体特殊声明方式
1、在声明时,同时定义结构体变量
struct 结构体名
{
类型1 成员1;
类型2 成员2;
... ...
}结构体变量名;
2、声明时不写结构体名字
struct
{
类型1 成员1;
类型2 成员2;
... ...
}结构体变量名; ----- 在声明时同时定义结构体变量,但是之后不能使用这个声明进行定义变量。
共用体类型(联合体)(union)
使用多种数据类型作为成员,进行组合,但是使用同一段空间进行存储(多个成员共用一个空间),构成的新的类型,就叫做共用体(联合体)。
使用共用体的问题:同一时刻只能存储一个成员。
所占存储空间为占用最大空间的成员的空间。
- 声明共用体类型:
union 共用体名
{
类型1 成员1;
类型2 成员2;
... ...
};
共用体用法与结构体相同。
枚举类型(enum)
在定义一种新类型时,这个类型能够取值的范围是确定的,通过这个定义的新类型把能够取值的范围一一列举出来,这种类型就叫做枚举。
- 声明枚举类型:
enum 枚举名
{
成员1,
成员2,
... ...
成员n
};
枚举类型中,每个成员代表能够取的一个值。
声明类型时,如果成员没有赋值,成员就等于上一个成员的值+1;如果成员1没有赋值,则为0;
- 定义枚举变量:
enum 枚举名 变量名;
使用:变量名 = 成员;
2.3、字符串函数
头文件:#include
-
拷贝字符串函数
1、strcpy(dest, src);
将字符串 src 首地址拷贝给字符串 dest 的首地址中。
2、strncpy((dest, src,n);
将字符串 src 首地址的前n个,拷贝给字符串 dest 的首地址中。
-
比较字符串函数
1、strcmp(s1, s2);
比较字符串 s1 和 s2 是否相等。
相等返回0,不相等返回当前字符的差值。
2、strncmp(s1, s2,n);
比较字符串 s1 和 s2 前n个字符是否相等。
-
计算字符串长度函数
strlen(s);
计算s字符串的字符个数(不算 '\0');返回值就是字符串长度。
-
字符串拼接函数
1、strcat(dest,src);
把字符串 src 拼接到字符串 dest 后。
2、strncat(dest,src,n);
把字符串 src 前n个字符,拼接到字符串 dest 后。
2.4、动态内存
栈中变量,只要离开的变量的生命周期,变量就会由系统销毁释放。
堆空间:由程序员在程序中自己进行管理的空间,需要使用时进行申请,由自己进行释放销毁。空间的申请与释放都是由程序员在程序中指定,通过地址指针进行访问,就叫做动态内存。
- 申请空间
头文件:#include
void * malloc(size_t size); //malloc函数在堆空间申请指定大小的内存空间。
参数:
size_t size:要申请的字节数。
返回值:
void * :如果申请成功,返回申请的空间首地址;如果申请失败则返回NULL地址。
- 释放空间
头文件:#include
void free(void *ptr); // 释放malloc申请的空间。
参数:
void *ptr:要释放的申请空间的首地址,进行释放空间。
2.5、其它功能
1、类型替换:typrdef
对数据类型额外取一个别名:类型替换;
使用方法:typrdef 原类型名 替换新名;
2、宏替换:define
原样替换被替换中的内容。
使用方法:#include 新名字 被替换的内容
带参数替换
例:#define MAX(A, B) A > B ? A : B
在传入参数时,可以加上括号提高优先级。
例:#define MAX(A, B) (A) > (B) ? (A) : (B)
总结
在过去的学习过程中,我对Linux系统有了一些基础的了解和学习经验,以下是我对Linux学习的总结,希望对其他人有所帮助。
-
熟悉基本命令:学习Linux的第一步是熟悉基本的命令行操作。理解和掌握常用的命令,如ls、cd、mkdir、rm等,对于日常的系统管理和操作是非常有帮助的。
-
学习文件系统结构:Linux系统采用了树状的文件系统结构,了解和掌握文件系统的层次结构和基本目录的用途,如/bin、/etc、/home等,可以方便地进行文件和目录的管理。
-
理解用户和权限管理:Linux系统中有严格的用户和权限管理机制。学习如何创建用户、分配权限以及如何使用sudo命令提升权限,可以保障系统的安全和稳定。
-
掌握软件包管理:学习如何使用包管理器,如apt、yum、dnf等,可以方便地安装、更新和卸载软件包。了解软件包的依赖关系和版本管理是非常重要的。
-
学会使用文本编辑器:在Linux系统中,文本编辑器是一个必备的工具。学会使用常见的文本编辑器,如vi、nano、emacs等,对于系统配置和脚本编写非常有帮助。
-
熟悉网络配置和服务:Linux系统是一个强大的网络平台,学习如何配置网络接口、设置IP地址、管理防火墙和服务,如ssh、httpd、mysql等,可以搭建自己的网络环境。
-
实践和参与开源项目:Linux世界以其开放性和强大的社区精神而闻名。参与开源项目并贡献自己的代码,可以提升自己的技术水平,并且从其他开发者身上学到更多。
-
深入学习Shell脚本编程:Shell脚本是Linux系统管理和自动化的关键工具。学习Shell脚本编程可以提高效率,简化系统管理任务,并且实现自己的想法和需求。
总的来说,学习Linux需要坚持不懈的努力和实践。除了学习基本的命令和知识,重要的是要勇于尝试和实践,探索更深层次的功能和应用。通过不断的学习和实践,我们可以成为一名熟练的Linux用户和系统管理员。希望以上总结对于正在学习Linux的朋友们有所帮助。