二、Linux系统与C语言高级

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学习的总结,希望对其他人有所帮助。

  1. 熟悉基本命令:学习Linux的第一步是熟悉基本的命令行操作。理解和掌握常用的命令,如ls、cd、mkdir、rm等,对于日常的系统管理和操作是非常有帮助的。

  2. 学习文件系统结构:Linux系统采用了树状的文件系统结构,了解和掌握文件系统的层次结构和基本目录的用途,如/bin、/etc、/home等,可以方便地进行文件和目录的管理。

  3. 理解用户和权限管理:Linux系统中有严格的用户和权限管理机制。学习如何创建用户、分配权限以及如何使用sudo命令提升权限,可以保障系统的安全和稳定。

  4. 掌握软件包管理:学习如何使用包管理器,如apt、yum、dnf等,可以方便地安装、更新和卸载软件包。了解软件包的依赖关系和版本管理是非常重要的。

  5. 学会使用文本编辑器:在Linux系统中,文本编辑器是一个必备的工具。学会使用常见的文本编辑器,如vi、nano、emacs等,对于系统配置和脚本编写非常有帮助。

  6. 熟悉网络配置和服务:Linux系统是一个强大的网络平台,学习如何配置网络接口、设置IP地址、管理防火墙和服务,如ssh、httpd、mysql等,可以搭建自己的网络环境。

  7. 实践和参与开源项目:Linux世界以其开放性和强大的社区精神而闻名。参与开源项目并贡献自己的代码,可以提升自己的技术水平,并且从其他开发者身上学到更多。

  8. 深入学习Shell脚本编程:Shell脚本是Linux系统管理和自动化的关键工具。学习Shell脚本编程可以提高效率,简化系统管理任务,并且实现自己的想法和需求。

总的来说,学习Linux需要坚持不懈的努力和实践。除了学习基本的命令和知识,重要的是要勇于尝试和实践,探索更深层次的功能和应用。通过不断的学习和实践,我们可以成为一名熟练的Linux用户和系统管理员。希望以上总结对于正在学习Linux的朋友们有所帮助。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值