华清·嵌入式人工智能·个人C高级笔记

一、Linux基础

shell命令、文件管理、服务器的配置(tftp、nfs)、shell脚本

1.1 Linux基础知识

1.1.1 什么是Linux?

通常Linux就指代的是Linux内核:能够让计算机跑起来(运行)

Linux操作系统:Linux内核 + 应用/系统软件  构成方便用户进行操作使用的系统

Linux内核:开源,支持多任务、多用户

Linux是免费开源的内核程序,Linux操作系统有:ubuntu、debian、deepin、red hat、centos等

1.1.2 Linux系统的系统架构

Linux内核,shell(命令解释器,通过shell提供内核的功能),文件系统,应用程序

(1)内核

内核是linux系统中最底层,提供系统中核心功能并允许有序访问硬件资源

用于管理:输入输出设备、进程的执行情况、文件系统的操作、内存管理

linux内核支持:多任务、多用户

(2)文件系统

文件系统就是用于组织和管理计算机存储设备上的大量文件

windows中使用NTFS文件系统格式

linux中格式多,目前通用EXT4文件系统格式

linux文件系统的逻辑结构(linux目录结构):linux中 文件系统把文件组织为倒置的树,每一个文件夹(目录)当做树的分支

文件系统只有一个起始点叫做根: / ---根

Linux文件系统把一切所有内容都看做文件,Linux一切皆文件

Linux文件系统就是一个 树形的目录结构:将 / 作为整个文件系统的起点,其他的所有目录都是从根开始

Linux文件系统存储文件:

/根目录
/bin存储系统中最常用的可执行程序
/boot存储Linux系统启动文件
/dev存储系统中的设备文件,包括硬盘、鼠标、键盘
/etc存储系统配置文件,如passwd存储用户信息
/home普通用户的家目录位置
/lib存放共享库
/media存储cd、软盘、usb临时读入的文件
/mnt挂载的文件系统挂载点
/opt作为可选程序和文件存放目录
/proc当前执行的进程的文件存储目录
/root超级用户的家目录
/sbin作为扩展的,更多的二进制程序存储目录
/usr标准库、第三方库存储目录

1.1.3 shell

shell叫做命令解释器,当执行程序时,把程序中的各种操作命令进行解释执行,通过命令解释器让内核执行对应操作,可以提供一种用户与操作系统交互的方式

(1)shell命令

shell完成内核与用户之间的交互

shell命令:向系统内核发出控制请求

shell解释器:命令解释器,将用户的命令解析为操作系统能够理解指令,实现用户与内核交互

shell命令的输入,在终端提示符,标识了命令的开始

a、终端提示符:

ubuntu@linuxmachine:~$

当前用户@设备名称:当前工作目录+用户权限

[用户名][分割符][计算机名][分隔符][当前的工作路径][用户权限]

~:代表当前的用户的家(用户)目录

b、shell命令格式:

命令+选项+参数

command + [option] + [argument]

command:命令,shell要解析的内容,要执行的内容

option:改变命令执行动作的类型,选项使用 - 表示,可以有多个选项

argument:命令作用(执行)的目标

有时,命令不一定要携带选项和参数,通常表示使用默认的选项和参数

man command:查询手册可找到command使用说明帮助

c、绝对路径与相对路径:

路径:找到某个文件,所经过的目录就叫做路径

绝对路径:从根目录(/)开始所经过的目录,指文件在文件系统中的准确位置

相对路径:从当前的工作目录开始,找到文件所经过的目录,指文件在当前的相对位置

~:当前用户的家目录

.:当前工作路径

…:当前路径上一级路径

(2)shell目录命令
pwd用于查询显示用户当前的工作路径(用户在文件系统的位置路径)
pwd没有选项和参数
cd改变用户当前的工作路径(改变工作目录)
cd新工作路径:切换当前的工作路径为新工作路径—新的路径必须要存在
切换到当前路径:cd------>cd ~
mkdir创建目录文件,在指定路径下创建目录
mkdir创建目录路径
-p选项:如果父目录不存在则一起创建
rmdir删除空目录
rmdir要删除的目录路径
ls列出当前工作目录的所有项内容
ls + [目录路径]查看对应目录所包含的项内容
ls选项-a:列出所有文件(包括隐藏文件)
-A:列出所有文件(包括隐藏文件,但是排除 . 和 …)
-i:列出文件的inode号
-l:显示文件的详细信息(文件属性)
(3)shell文件命令
cat读取指定文件的内容(查看文件)
cat + [文件路径]-E:在每行结束末尾添加$
-n:添加行号
head查看文件前几行(10行)
head -n显示前n行
tail查看文件最后几行
tail -n显示文件后n行
touch创建一个普通文件
touch 文件路径1 文件路径2 文件路径3在对应路径(必须存在)下创建文件,如果文件名存在,则改变文件的最后修改时间
file + [文件名]判断文件类型
diff [文件1] [文件2]比较两个文件的不同
cp将文件拷贝到指定目录中
cp源文件路径目标路径
cp源文件路径目标路径/文件名
cp选项-r:拷贝目录(会把目录中的所有文件都拷贝)
mv将源文件移动到指定目录中,mv + [源文件] + [目标路径]
mv改名:mv源文件目标路径/目标文件名
rm删除指定路径下的文件,rm文件路径
rm选项-r:删除目录
(4)操作命令.
a、链接

链接文件:符号链接文件、硬链接文件.

符号链接文件(软链接):创建一个快捷方式,操作符号链接文件就是操作源文件,但是删除符号链接对源文件无影响,删除源文件符号链接无法使用.

ln -S 源文件 目标文件(符号链接文件–软链接文件)硬链接文件:在文件系统中,创建一份与源文件完全一致的文件,创建的文件和源文件一致保持一致,但是删除其中一个文件对另一个文件无影响
ln 源文件 目标文件(硬链接文件)修改文件权限(读、写、执行):执行命令的用户要求是对应要修改权限的文件的所有者,才能够修改(普通用户只有改修自己的所有文件的权限),超级用户拥有改所有用户文件的权限

sudo:临时使用(获取)root用户身份(管理员权限)来执行指定命令

chmod [权限] [文件]

b、权限:

用数字表示,9位二进制权限(用八进制表示),8421

用字符表示:

u+[r、w、x]表示用户部分添加对应权限.
u-[r、w、x]表示用户部分删除对应权限.
g+[r、w、x]表示用户组部分添加对应权限.
g-[r、w、x]表示用户组部分删除对应权限.
o+[r、w、x]表示其他用户部分添加对应权限.
o-[r、w、x]表示其他用户部分删除对应权限.

在创建文件时默认权限:

普通文件0664
目录文件0775

改变文件的所属用户:只有管理员root才能修改

chown [用户名][文件]

改变文件的所属用户组:只有管理员身份执行

chgrp[用户组][文件]
c、linux压缩与解压:tar.
压缩:先进行归档合并为一个文件,再进行压缩

解压:先进行解压操作,然后对归档文件进行释放.

归档文件:把多个文件打包成一个文件.

创建归档文件:

tar -cvf 归档文件名.tar 文件1 文件2 文件3 文件4.....

释放归档文件:把归档文件中打包的文件释放出来

tar-xvf归档文件名.tar.

压缩与解压:

使用gzip算法对文件进行压缩与解压:-z

压缩:把多个文件先归档打包成一个文件然后使用gzip算法进行压缩.

tar -cvzf [压缩文件名.tar.gz] 文件1 文件2 文件3 文件4.....

解压:

tar -xvzf [压缩文件名.tar.gz]

使用bzip2对文件进行压缩与解压:-j

压缩:tar -cvjf 压缩文件名.tar.bz2 文件1 文件2 文件3 文件4…

解压:tar -xvjf 压缩文件名.tar.bz2.

使用zip算法进行压缩:

zip 压缩文件名.zip 文件1 文件2 文件3 文件4…

使用zip算法进行解压:unzip 压缩文件名.zip

d、输出重定向.

>:指定输出到某个文件,会先清空对应位置的内容

>>:指定输出到某个文件,以追加方式输出到指定位置

输出到终端 > 文件

输出到终端 >> 文件

(4)用户管理.
a、修改用户

修改用户密码:passwd 用户名-----只能修改当前用户的密码

提升为管理员身份修改用户密码:sudopasswd用户名

切换用户:su用户名

退出当前登录用户:exit

创建新用户:只有root用户才能新建,sudo adduser 新用户名(新建用户无sudo权限,如果需要添加sudo权限,则在sudoers 添加 新用户名)

sudo vim/etc/sudoers

在文件最后添加:

新用户名 ALL=(ALL:ALL) ALL.

删除用户:管理员删除.

sudouserdel-r用户名.

b、创建用户

创建用户组:

sudo groupadd 用户组名

将用户添加到用户组

sudogpasswd-a用户名用户组

查看用户对应的用户组

groups用户名

将用户从用户组删除

sudogpasswd-d用户名用户组

删除用户组:

sudogroupdel用户组名

(5)软件安装.
  • 直接执行二进制程序进行安装.

  • 软件包管理工具安装.

    解析 软件包,查找对应依赖环境,安装软件.

    debian linux 软件包机制-----解析.deb.

    red hat linux 软件包机制-----解析.rpm.

  • 本地离线安装(本地软件包管理).

    dpkg:离线包管理.

    dpkg-i软件包名:安装软件.

    dpkg-r软件名.

  • 在线安装(在线软件包管理):在线安装,在计算机中需要配置软件镜像源(软件从哪里下载)

/etc/apt/source.list 软件源地址列表

检查网络信息:

ping + ip地址或域名:查看是否与对应的ip地址或域名连通,测试网络连接是否正常

ifconfig:查询本机的网络信息(需要安装net-tools)

apt:在线包管理工具(apt-get)

apt就是用于获取、安装、编译、卸载、查询于一体的包管理工具,自动检查软件的依赖是否安装

apt软件管理使用:

sudo apt update:下载(获取)更新 软件源地址中的软件包列表

sudo apt install软件包名:下载安装对应的软件

sudo apt --reinstall install 软件包名:重新再次安装

sudo apt remove软件名:卸载对应的软件

sudo apt clean:清除下载的安装包

(6)服务器安装与配置
a、nfs服务器.

网络文件共享服务器:提供主机中目录用于共享,当客户端来连接这个服务器后,就可以使用我共享的目录

安装nfs服务器软件:

服务器:nfs-kernel-server

sudo apt install nfs-kernel-server

修改nfs服务器的配置:

因为服务器功能为共享 文件夹,所以要修改对应的共享文件夹目录

sudo vim /etc/exports-----nfs配置文件

添加:

/home/ubuntu/nfsserver       *(rw,sync,no_subtree_check)

/home/ubuntu/nfsserver:要共享的文件夹目录

*:允许哪些客户端的ip地址访问nfs服务器

rw:读写

sync:同步更新

no_subtree_check:不检查父目录权限

如果共享目录不存在,则创建对应目录,设置权限

mkdir目录路径

启动nfs服务器:

设置服务器端口为监听状态(开启监听)

sudo service rpcbind start

启动nfs服务

sudo service nfs-kernel-server [start、restart、status、stop]

查看nfs共享的目录:

showmount -e

客户端连接:

linux:

mount -t nfs 服务端ip:/home/ubuntu/nfsserver /mnt 挂载位置

umount/mnt

windows:

连接:

mount \服务端ip\home\ubuntu\nfsserver(绝对路径) X:(挂载到windows哪个盘)

断开:(解除挂载)

umount X:

b、tftp服务器

tftp:文件上传下载服务器

tftp:tftp文件上传下载服务器功能,提供一个文件夹(目录),可以让其他的客户端从这个目录下载文件,或上传文件到这个目录

tftp服务器:

安装tftp服务器:

sudo apt installtftpd-hpa

tftp-hpa(客户端)

提供了服务端功能:上传、下载

配置tftp服务器提供的操作功能(修改配置文件):

sudo vim /etc/default/tftpd-hpa

文件内容:

TFTP_USERNAME=“tftp”--------服务器程序名

TFTP_DIRECTORY=“/srv/tftp”-------提供的可以进行上传下载的目录(只能把文件上传到这个目录和从这个目录下载文件)

TFTP_ADDRESS=“0.0.0.0:69”------服务器的tftp程序的地址

TFTP_OPTIONS=“-l -c -s”

启动tftp服务程序:

sudo service tftpd-hpa start

restart

status

客户端进行上传文件到tftp服务器,从服务器下载文件

sudo apt install tftp-hpa

使用:

tftp服务端地址

tftp> put 文件名:上传文件

tftp>get 文件名:下载文件

tftp>q:退出tftp客户端

(7)通配符.

通配符

作用

例子

*(星号):可以表示匹配任意的字符串

1*2.txt:表示可以匹配1开始以2.txt结束的所有名字:123456782.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.1.4 shell脚本(shell编程).

将shell命令按照一定的逻辑关系,顺序组织在一个文件中,组合成一系列完整的功能要求,执行文件,就可以其中shell命令按照对应的逻辑顺序执行.

shell文件是以.sh作为后缀名.

执行shell脚本(文件):.

(1)为shell脚本文件,添加可执行权限,按照可执行文件的方式执行.

修改为包含可执行权限.

chmod权限文件.

可执行文件,怎么执行.

可执行文件的路径+文件.

/home/ubuntu/linuxC/day3/1.sh.

./1.sh.

.

(2)使用对应的shell解释器来解析执行.

在当前ubuntu安装使用的是bash shell解释器.

bash文件名.sh.

.

在shell文件中,通常先添加shell解释器的版本说明(使用哪种解释器).

#!/bin/bash:说明,使用哪种解释器来解析.

.

shell语法:实现shell脚本的逻辑功能.

a、变量定义.

定义:.

变量=值.

引用变量:.

$变量.

在字符串中中可能会出现要使用变量名情况:.

“”:会解析引用的变量.

‘’:不会解析引用的变量.

.

b、变量的输入.

在shell脚本中,使用 read 表示 输入字符串 到变量中:.

read变量1 变量2 变量3…

shell脚本存在特殊变量,位置变量:.

$1:获取执行shell脚本文件时,命令行传递的第一个参数.

$2:获取执行shell脚本文件时,命令行传递的第二个参数.

$3:获取执行shell脚本文件时,命令行传递的第三个参数.

$9:获取执行shell脚本文件时,命令行传递的第九个参数.

$@ / $*:获取命令行传递的所有参数.

? :获取上一条命令执行的状态值,上一条命令执行成功 ?:获取上一条命令执行的状态值,上一条命令执行成功 ?:获取上一条命令执行的状态值,上一条命令执行成功?的值为0,否则非0.

.

c、条件判断.

判断条件: test.

字符串:s1,s2就表示字符串.

s1 = s2 :判断相等.

s1 != s2 :判断不等.

-z s1 :判断字符串长度是否等于 0.

-n s1 :判断字符串长度不为0.

.

整数:a,b表示数字字符串.

a -gt b :判断a 是否 大于 b.

a -ge b :判断a 是否 大于等于 b.

a -lt b : 判断a 是否 小于 b.

a -le b :判断a 是否 小于等于 b.

a -eq b :判断a 是否 等于 b.

a- ne b :判断a 是否 不等于 b.

文件测试:

-d filename:判断filename是否是一个目录.

-e filename:判断filename文件是否存在.

-f filename:判断filename文件是否是普通文件.

-L filename:判断filename文件是否是符号链接文件.

-s filename:判断filename文件存在且长度不为0.

-r filename:判断文件存在且是否可读.

-w filename:判断文件存在且是否可写.

-x filename:判断文件存在且是否可执行.

d、逻辑运算.

条件1 -a 条件2 :逻辑与,多个条件都为真,结果为真.

条件1 -o 条件2 :逻辑或,只要有一个条件为真,结果为真.

!条件:得到条件取反.

e、if选择结构.

语法1:如果满足条件表达式,则执行命令,不满足就跳过.

if [ 条件表达式 ].

then.

命令.

fi.

语法2:如果满足条件表达式,则执行命令1,不满足则执行命令2.

if [ 条件表达式 ].

then.

命令1.

else.

命令2.

fi.

语法3:如果满足条件表达式1,则执行命令1,不满足则判断表达式2,满足则执行命令2,不满足则判断表达式3,满足则执行命令3,不满足则判断表达式4,…直到最后一个条件为止.

if [ 条件表达式1 ].

then.

命令1.

elif [ 表达式2 ].

then.

命令2.

elif [ 表达式3 ].

then.

命令3.

elif [ 表达式n ].

then.

命令n.

else.

以上都不满足则执行.

fi.

f、循环.

算数运算指令:expr.

expr $1 + $2.

while [ 条件表达式 ] ------ 当满足条件就执行一次.

do.

命令表.

done.

for 变量名 in 单词表-------如果变量名能够从单词表中取出一个值(单词),就执行一次循环.

do.

命令表.

done.

c语言for循环格式.

for((循环初始语句;循环条件语句;条件改变语句)).

do.

命令表.

done.

函数:实现一个完整的功能步骤,需要时直接使用.

函数定义:.

函数名().

{.

命令集合.

}.

函数调用:.

函数名.

函数参数:.

如果函数定义需要参数 ,函数的()中不用写参数,使用位置变量$1,$2,$3… 作为函数的参数,来传递参数值.

函数调用时:.

函数名参数值1 参数值2 参数值3,.

函数返回值:

在函数中执行 echo 命令 输出显示,只要当调用时 有赋值,这时echo 为返回值.

二、C语言高级

指针、构造类型、动态内存管理、多文件与关键字.

1、指针.

是直接访问内存的方式.

内存地址:在内存空间中,对每一个字节都分配了一个唯一的编号,用于区别不同的位置。每个字节都有唯一的地址,用来和内存中的其他字节相区别.

指针:在内存空间(定义变量)申请空间来存储地址,就叫做指针,也叫做指针变量.

指针就是操作内存地址,使用内存地址.

1.1 定义指针变量.

指针变量:本质就是一个变量,存放的是一个内存地址.

指针变量定义的形式:.

指向数据类型 * 指针变量名;.

指向数据类型:存储哪种类型数据的地址,指向哪种类型.

指针变量:定义一个变量,用于存储地址,如果要存储哪种类型的地址,数据类型就是对应的类型.

1.2 指针的使用.

存储地址:.

指针变量 = 地址(要求地址的空间能够使用).

变量的地址获取:通过 & 取地址运算符,得到变量的地址.

指针变量 = &变量.

指针变量访问内容:操作对应地址的数据,通过地址的方式访问数据.

用变量名来表示代表变量中的值.

用指针来访问变量:.

*指针名 访问对应地址(指针存储的地址)的数据空间.

int * p;.

p = &a;.

*p ; // ==== a 表示访问 p存储的地址(即a的地址),对应空间的空间.

指针变量赋值地址:通过指针建立与对应内存空间联系.

指针 取*:得到建立联系的内存空间的值.

指针变量的初始化:.

在定义指针变量时,进行赋值,就叫做初始化.

类型 * 指针名 = 地址;.

野指针:.

指针记录的地址不明确(存储的地址不知道,或地址对应空间是否具有操作权限不确定),这种指针叫做野指针.

野指针不需要直接进行 取 *.

空指针:.

指针记录的地址是NULL(地址:0x00),系统规定NULL地址不允许进行操作.

只要操作就会报错.

空指针通常表示,该指针当前不可用.

万能指针:.

void * 类型指针变量,可以存储任意类型的地址,也可以把指针赋值给其他的任意类型指针变量.

void * 指针,指针存储地址,不能进行 取值操作(取 *),因为指向的类型未知不明确.

1.3 指针的运算.

指针 + / - 整数,表示移动指针 指向 的位置.

+:.

指针 + 整数n.

往地址增大方向,移动 n 个 指向(指针指向,指针存储哪种地址)的数据类型 大小.

int * p;.

p + 5 ==== >移动 5 * 4.

指针 + n == 指针 + n * sizeof(指向类型).

-:.

指针 - 整数.

往地址减小方向,移动指针指向类型(指针存储哪种类型地址)的大小 * 整数大小.

指针 - 整数 * sizeof(指向类型).

.

指针++:.

先使用指针,然后 指针 = 指针 + 1.

++指针:.

先 指针 = 指针 + 1 ,然后再使用指针.

指针–,–指针.

指针 - 指针:.

获取两个指针之间间隔多少个对应类型的数据.

(指针 - 指针) / sizeof(指向类型) .

1.4 指针与一维数组.

一维数组是一段连续的空间存储多个数据元素,在数组中相邻的元素,间隔大小为每个元素类型的大小,即 &数组名[元素i] == &数组名[元素i-1] + 类型大小 .

指针能够进行运算,指针 + 1,移动一个数据类型的大小,即 指针 + 1 == 指针 + 指向类型大小.

如果指针变量存储了数组中的元素地址,指针+1 ,就是数组中下一个元素的地址.

指针与数组的操作方式:.

可以通过指针访问整个数组.

只要知道数组的起始地址(第零个元素的地址),就可以遍历整个数组.

数组首地址:数组的起始地址,就是第零个元素的地址.

int * p = &a[0];.

*(p+n) == a[n].

在数组中,数组名 有个特殊作用。数组名就表示 数组的首地址.

数组名,地址常量.

int a[5];.

a == &a[0].

数组首地址(数组名) + n:偏移n个数据元素大小.

*(数组名 + n) == 数组名[n].

*(a + 3) == a[3].

基于数组名(常量地址),可以将数组名当做指针进行使用,除了不能赋值运算(a = a+1).

.

因为数组名可以表示数组首地址,而指针变量也可以存储数组首地址,在访问数组的操作时,指针变量和数组名作用一致,所以.

数组名[n]:访问数组的n元素 ==== 指针名[n].

int *p,a[5]; .

p = a;.

p + n == a + n//等价.

a[n] == *(p+n) == *(a+n) == p[n].

基于指针变量,可以将指针当做数组用,不能越界.

.

字符串与字符数组.

字符串:有多个字符组成一个连续且有序的字符序列.

“abcdef”------字符串.

.

C程序中,通过字符数组来存储字符串.

字符数组通过访问数组中的元素,就是访问字符串(按照字符数组,每个元素单独访问).

如果需要整体访问字符数组中存储的字符串,要求在字符串结束的下一个字符位置存储’\0’.

'\0’字符就表示 字符串的结束.

.

字符数组存储字符串:.

字符数组初始化存储字符串.

char数组名[大小] = “字符串”;.

.

注意通常,在进行输入前把数组初始化全为’\0’.

输入字符串到字符数组中.

scanf(“%s”,数组名/首地址);.

.

输出打印字符数组中的字符串.

printf(“%s”,数组名);.

.

常量字符串表示:.

“acbde”-----常量字符串.

在常量字符串中,在最后字符后默认包含’\0’字符.

在程序中如果写出常量字符串,则常量字符串表示常量字符串的首地址(第零个字符地址).

如:“abccde”,得到就是字符串的首地址,地址常量.

.

地址,指针类型,都是统一的大小,各个类型之间没有区别.

32位机器:4B.

64位机器:8B.

.

练习:.

1、在数组中有10个数,统计10个数的和(通过指针).

2、输入一个名字,计算是否存在 'x’字符(指针).

.

作业:.

1、输入一个字符串,求字符串的长度.

2、输入两个字符串到两个数组中,然后把两个字符串进行拼接.

.

1.5 指针与二维数组.

二维数组:二维数组中,每个元素是一个一维数组,在元素(一维数组)中,每个成员就是一个值.

二维数组:.

数据类型数组名[行][列].

行:有多少个一维数组.

列:一维数组的元素个数.

.

对于二维数组而言,数组名是整个二维数组的首地址,第零个元素的地址,二维数组的元素都是一维数组,即二维数组数组名表示其中元素,整个一维数组的地址。.

int a[3][4];.

a == &a[0];//a[0]是整个一维数组.

由于a表示整个元素的地址(一维数组的地址),所以进行指针运算时,+1 ,加上 整个一维数组大小.

a:&a[0],第零个一维数组的地址.

a+1:&a[1],第一个一维数组的地址.

a+2:&a[2],第二个一维数组的地址.

.

a[0]:表示二维数组的元素零,第零个一维数组,a[0]是一维数组的数组名,在这个一维数组的首地址 .

a[0] == &a[0][0] .

a[0]+1 == &a[0][1].

a[1]:第一个一维数组,也是这个一维数组的数组名(首地址).

a[1] == &a[1][0].

a[1]+1 == &a[1][1].

.

注意:.

a+1,表示移动二维数组的一个元素(一维数组)大小.

a[0]+1,表示移动一维数组的一个元素(数据类型值)大小.

.

.

数组指针:.

是一个指针,指针用于存储整个数组的地址,指针的指向类型为数组.

定义:.

数组元素类型 (* 指针变量名)[大小];.

int (*p)[4];//定义一个指针变量,指针变量存储 整个数组的地址(int [4]).

.

数组指针和二维数组名是等价的,因为二维数组表示第零个元素(一维数组)的地址.

int a[3][4];.

int (*p)[4];.

p = a;//&a[0].

p+1 == a+1 == &a[1].

*(p+1) == a[1].

*(p+1)+2 == &a[1][2].

((p+1)+2) == a[1][2].

.

1.6 多级指针与指针数组.

指针数组:.

是一个数组,只是每个元素为指针类型.

指向类型 * 指针数组名[元素个数];.

int * p[5];.

定义 包含 5个元素 每个元素为指针(int *).

int a;.

p[2] = &a;.

.

多级指针:.

一级指针:存储变量的地址.

二级指针:存储一级指针的地址:一级指针类型 * 指针名;.

三级指针:存储二级指针的地址:二级指针类型 * 指针名;.

指向类型 * 指针名;.

.

.

int **p;.

int * a[10];.

p = a;.

p+1 == a+1;.

*(p+2) == a[2].

二级指针与指针数组名等价.

作业:.

1、定义一个字符二维数组,输入要存储‘#’号的个数,然后分别输入存储的位置,其他位置默认存储 ‘ ’空格字符.

2、二维数组和数组指针.

int a[2][3];.

int (*p)[3] = a;.

在以下每个表达式中,p = a,求表达式的含义.

a[0].

a[0][2].

*p.

**p.

*a.

**a.

*p++.

**(p+1).

*(p+1)+1.

((p+1)+1).

3、定义二维数组,输入数据,然后求每个元素中的最大值.

4、字符串的替换,输入一个原字符串,然后输入要替换的起始位置,输入新字符串进行替换.

.

1.7 指针与函数.

指针作为函数的参数:可以表示变量的地址,或者是数组名/数组首地址,作用就是表示参数为地址.

把地址作为参数进行传递.

返回值类型 函数名 (指针参数1,指针参数2); 接受传递的是地址.

调用:.

函数名(地址,地址/指针);.

.

如果是数组作为形式参数,会由编译器自动变为对应类型指针.

int sumarray(int p[10],int length) p就是指针 int*.

指针作为函数返回值:返回一个地址,把指针作为函数的结果返回.

函数指针:指针存储是的函数的地址.

函数的类型表示:.

返回值类型(参数1,参数2,参数3,…);.

int (int a,char b);-1.

int (int a,int b);-2.

int (int c,int d);-3.

1和2是不同函数类型,2和3是相同函数类型.

函数指针表示:.

返回值类型(* 指针变量名)(参数1,参数2,参数3,…) .

.

函数地址:.

函数名就是用于表示函数的地址.

函数指针 = 函数名;.

.

调用函数:.

通过函数指针进行调用.

函数指针名(实参);.

2、构造类型.

由于基本数据类型不能满足需要,需要把多个的数据类型进行组合,共同表示新的复合数据,形成新的类型。构造新的数据类型的方式就叫做构造类型.

2.1 结构体.

使用多种数据类型作为成员,进行组合,构成的新的类型,就叫做结构体.

声明结构体:结构体的类型表示.

struct结构体名字.

{.

类型1 成员1;.

类型2 成员2;.

类型3 成员3;.

};.

在程序中添加一种新的类型,不占用内存空间,只是说明在程序中有一中新类型.

.

定义结构体变量:.

struct结构体名字 变量名;.

.

对结构体变量的操作,就是对结构体变量的成员进行操作.

结构体变量访问成员:.

结构体变量名 . 成员名;.

.

.

.

结构体变量初始化:.

在定义结构体变量时,对其成员进行初始化.

.

顺序对成员初始化:.

struct结构体名变量名 = {成员1值,成员2值,成员3值,…};.

指定成员初始化:.

struct结构体名变量名 = { .成员名2 = 成员值,.成员名4 = 成员值,…};.

.

.

结构体指针如何访问变量的成员:.

结构体指针:.

struct结构体名* 指针名 = 结构体地址;.

.

访问方式:.

指针->成员://访问结构体指针对应地址中的成员.

(*指针).成员 == 指针->成员.

.

结构体特殊的声明方式:.

struct结构体名字.

{.

类型1 成员1;.

类型2 成员2;.

类型3 成员3;.

}结构体变量名;--------在声明时同时定义结构体变量.

.

struct.

{.

类型1 成员1;.

类型2 成员2;.

类型3 成员3;.

}结构体变量名;--------在声明时同时定义结构体变量,但是之后不能使用这个声明进行定义变量.

.

2.2 共用体(联合体).

使用多种数据类型作为成员,进行组合,但是使用同一段空间存储(多个成员共用一个空间),构成的新的类型,就叫做共用体.

使用共用体的问题:同一时刻只能操作一个成员.

声明共用体类型:.

union 共用体名.

{.

类型1 成员1;.

类型2 成员2;.

类型3 成员3;.

};.

用法:共用体与结构体一致.

.

2.3 枚举.

枚举就是定义一种新类型时,这个类型能够取值的范围是确定的,通过这个定义的新类型把能欧取值的范围一一列举出来,这种类型就叫做枚举.

声明枚举类型:.

enum枚举名.

{.

成员1,.

成员2,.

成员3,.

};.

枚举类型中,每个成员就代表能够取的一个值.

声明类型时,如果成员没有赋值,成员就等于上一个成员的值+1,如果成员1没有赋值则为0.

.

定义枚举变量:.

enum 枚举名变量名;.

变量名 = 成员;.

.

3、字符串函数.

.

#include <string.h>.

.

//把src首地址的字符串,拷贝到dest首地址中.

char *strcpy(char *dest, const char *src);.

//把src首地址的字符串前n个,拷贝到dest首地址中.

char *strncpy(char *dest, const char *src, size_t n);.

.

//比较字符串s1 和 s2 是否相等,如果相等返回0,如果不等返回当前字符的差值.

int strcmp(const char *s1, const char *s2);.

//比较字符串s1 和 s2 的 前n 个字符 是否相等,如果相等返回0,如果不等返回当前字符的差值.

int strncmp(const char *s1, const char *s2, size_t n);.

.

//计算 s 字符串的字符个数(不算’\0’),返回值就是字符串的长度.

size_t strlen(const char *s);.

.

//把src字符串 拼接到 dest字符串后.

char *strcat(char *dest, const char *src);.

//把src字符串 前n个字符 拼接到 dest字符串后.

char *strncat(char *dest, const char *src, size_t n);.

2.4 动态内存.

栈中变量,只要离开了变量的生命周期,变量就会由系统销毁释放.

堆空间:有程序员在程序中,自己进行管理的空间,需要使用时进行申请,由自己进行释放销毁。空间的申请与释放都是由程序员在程序中指定,通过地址指针进行访问空间,根据指针的类型就按照对应类型进行访问,就叫做动态内存.

申请空间:.

#include <stdlib.h>.

malloc函数在堆空间中申请指定大小的内存空间.

void *malloc(size_t size);.

参数:.

size_t size:要申请的字节数.

返回值:.

void *:如果申请成功,返回申请的空间首地址.

        如果申请失败,返回NULL地址.

释放空间:.

#include <stdlib.h>.

free就是释放malloc申请的空间.

void free(void *ptr);.

参数:.

void *ptr:申请空间的首地址,进行释放空间.

2.5 关键字.

const:.

在定义变量时,使用const关键字修饰,变量不可修改,作用类似于常量.

const数据类型变量名;.

通常情况下const变量要进行初始化.

const修饰指针变量时,有不同的用法:.

指向类型 * const 指针变量名;.

表示指针变量不可修改,但是指向地址中的内容可以修改.

指针变量不可改;.

*指针变量 可以修改;.

指向类型 const * 指针变量名;/ const 指向类型 * 指针变量名;.

表示指针变量可以修改,但是指向地址中的内容不可修改.

指针变量可改;.

*指针变量 不可改;.

const 指向类型 * const 指针变量名;.

指针变量不可改;.

*指针变量 不可改;.

static.

修饰局部变量.

修饰全局变量.

auto.

自动类型,定义在栈中,由系统进行管理.

register.

定义变量在cpu中,如果没有成功则与auto相同.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值