Linux c高级
2021/8/29 7:06:57
本文主要是介绍Linux c高级,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录- 一、Linux
- 1.1、嵌入式
- 1.2、什么是Linux
- 1.3、Linux发行版
- 1.4、Linux体系结构
- 1.5、虚拟4G内存
- 1.6、shell 命令
- 1.7、软件包的管理
- 1.8、图形界面配置配网
- 1.9、文件的压缩和归档
- 1.10、文件相关的内容
- 1.11、find
- 1.12、cut
- 1.13、修改文件的权限、用户、组。
- 1.14、软链接与硬链接
- 1.15、通配符
- 1.16、进程
- 1.17、man 查询函数、库函数、命令的用法
- 1.18、用户管理
- 1.19、磁盘相关的命令
- 1.20、网络知识
- 1.21、环境变量
- 二、shell
- 2.1、实质:shell命令的有序集合
- 2.2、shell命令行解释器
- 2.3、shell脚本
- 2.4、shell脚本的变量
- 2.5、shell 处理数组
- 2.6、read 从终端上输入
- 2.7、shell输入
- 2.8、shell的运算
- 2.9、if else
- 2.10、循环: while [条件]
- 2.11、函数
- 三、c高级
- 3.1、c语言的本质
- 3.2、c语言中如何分配内存
- 3.3、函数
- 3.4、gcc、gdb
- 3.5、存储类型
- 四、makefile
- 4.1、什么是Makefile
- 4.2、什么是make
- 4.3、体验Makefile
- 4.4、Makefile的规则
- 4.5、变量
- 跳转:上一篇、Linux c基础!
- 跳转:下一篇、数据结构与算法!
统一声明:
博客转载 声 明 : 本博客部分内容来源于网络、书籍、及各类手册。
内容宗旨为方便查询、总结备份、开源分享。
部分转载内容均有注明出处,如有侵权请联系博客告知并删除,谢谢!
百度云盘提取码:统一提取码:ziyu
一、Linux
1.1、嵌入式
嵌入式:计算机应用为中心、软硬件可裁剪的系统。
1.2、什么是Linux
- Linux 多任务、分时 的一个操作系统
- GNU GNU is Not Unix 它是一个组织;
- GPL 是一种协议。
1.3、Linux发行版
- Linux本身指的是一个操作系统内核,只有内核是无法使用的。
- 我们系统使用操作系统一个包含内核和一批有用的应用集合,这就叫Linux发行版。
Ubuntu、Redhat就是Linux的不同的发行版。 - Red Hat 服务器
- unbutu 桌面性能好 “人道主义”。
- debian
1.4、Linux体系结构
-------------------------------------------- [0-3G] 0XC000 0000 应用层 app程序、shell命令、shell脚本、程序 | | | | | | 内核层---------------------------系统调用--- [3-4G] 0xffff ffff(代表4G) 1 0000 0000 文件管理 内存管理 进程管理 --> 程序的一次执行过程 硬件管理 网络管理 -------------------------------------------- 硬件层 LED LCD CAMERA 鼠标 键盘
1.5、虚拟4G内存
------------- 4G 内核 ------------- 3G 栈区 自动开辟自动释放 ------------- 堆区 手动malloc ------------- 静态区/数据区 全局/静态 ------------- 字符串常量 ------------- 代码段 ------------- 0
1.6、shell 命令
whoami 我是谁 ls -a -l -r 递归查询 -i inode 一个编号,一种节点 -lh pwd cd cd dir_name cd 路径 绝对路径 相对路径 cd ~ 返回目录 cd cd . cd .. cd - 返回上一步 mkdir -p 递归创建 rm mkdir dir_name 删除空目录 rm -r dir_name touch file_name rm file_name cp cp 路径 路径 复制文件 cp -r -a 目录的复制 mv mv 路径 路径 exit 退出 echo 输出 su 切换用户 sudo 权限 clear 清屏 快捷键:Ctrl+L
1.7、软件包的管理
1.7.1、dpkg:(离线安装)
rxvt _1%3a2.6.4-14 _i386 .deb | | | | 32 | | 软件名 主版本号 修订版本号 体系结构 后缀
软件包安装:
sudo dpkg -i 软件包全称
卸载:
sudo dpkg -r 软件名
清除软件包的配置文件:
sudo dpkg -p 软件名
列举软件的相关信息的清单:
sudo dpkg -L 软件名
查询版本号:
sudo dpkg -l 软件名
查询软件安装包的状态:
sudo dpkg -s 软件名
强制安装:
sudo dpkg -f 软件名
虚拟机自定义伸缩窗口大小
虚拟机 --> 首选项 --> 显示;
更新 vmare tools
点击 虚拟机---> 更新(重装) VMware tools
跳转到一个界面,界面上有VMwareTools-10.3.10-13959562.tar.gz 这个压缩包,
把这个安装包解压在家目录 tar -xvf VMwareTools-10.3.10-13959562.tar.gz (一直按enter键直到结束)
结束后生成一个目录--vmware_tools_distrib, cd 进去这个目录,再执行 ./vmare_install.pl 这个可执行文件就可以了;
1.7.2、把windows的文件复制到Ubuntu中
(1)、拖拽的方式:
直接把文件拖到终端,在前面加上 mv 移动到某一个路径(mv '/tmp/VMwareDnD/VUayTT/char_arr.c' ./my.c)
或者在widows上,鼠标右键点击复制,再转到ubuntu上的终端上点击 右键---> paste filenames 也会有一个路径,同样
在前面加上 mv 移动到当前; ( mv '/tmp/VMwareDnD/VUayTT/char_arr.c' ./)
(2)、创建共享文件夹
虚拟机 -> 设置 -> 选项 -> 共享文件夹 -> 总是启用 ->选择一个windows中的一个文件夹作为共享文件夹
终端访问: cd /mnt/hgfs/myshare
共享文件夹设置失败解决问题:属性,设置兼容性;虚拟机关键。
1.8、图形界面配置配网
1.8.1、编辑 --> 网络编辑器 --> 更改设置 --> 桥接模式 -->选择对应网卡 -->
虚拟机 --> 设置 --> 桥接模式。 网络图标: --> edit conections --> 自动 / 静态 ip:192.168.9.123 子网掩码:255.255.255.0 网关: 192.168.9.1 相关命令: ifconfig 查看当前ip地址 ctrl+c 结束当前进程 ping + ip地址 连接某个ip
1.8.2、apt 需要外网
软件源:
/ect/apt/sources.list
下载的路径:
/var/cache/apt/archives/
更新源:
sudo apt-get update
下载一个软件:
sudo apt install 软件名:
卸载:
sudo apt-get remove 软件名
清空:
sudo apt-get clean 软件名
下载源码:
sudo apt-get source 软件名
1.9、文件的压缩和归档
1.9.1、压缩
针对的是文件 实质: 把文件里的tab/空格等压缩。 压缩的时候,原文件就没有了,生成了压缩文件; 解压的时候压缩文件也变成了原文件; 速率 大小 .gz: 最慢 最小 gzip 1.c --> 1.c.gz .bz2: 次之 次之 bzip2 1.c --> 1.c.bgz2 .xz 最快 最大 xz 1.c --> 1.c.xz
1.9.2、解压
gunzip 1.c.gz --> 1.c bunzip 1.c.bz2 --> 1.c unxz 1.c.xz --> 1.c
1.9.3、归档
归档:针对的是一个目录 “把一个目录变成一个文件” 归档的时候源文件依旧存在,生成一个新的归档文件。 释放的时候,压缩文件也存在。 tar 参数 归档的文件 目录 c 创建归档 v 显示过程 f 后面接文件 x 释放后归档的文件还在 z: 压缩成gzip j: 压缩成bzip2 J: 压缩成xz eg:压缩 tar -cvf test.tar test --> test.tar 释放: tar -xvf test.tar --> test
1.9.4、压缩的实质就是归档并压缩
压缩: tar - vzcf day1.tar.tar.gz day1 --> day1.tar.gz 解压: tar - xzvf day1.tar.tar.gz 万能解压: tar -xvf test.tar.* (* 代表各种格式的压缩包)。
1.10、文件相关的内容
1.10.1、vi 三种模式
新建文件 vi toch
(1)、命令行模式
复制:nyy 粘贴:p 剪切:ndd 撤销:u 返向撤销:Ctrl + r 查找: /string 向下查找n 向上查找N /^string 查找以string开头的字符串 去光标移到到结尾: G 光标移到到开头: g 调整格式:gg=G
(2)、插入模式
a / i / b
(3)、底行模式
w q wq q! wq! x :num 去到某一行 srtnumer:设置行号 vsp 替换: .当前 $最后 g所有 %全文 s/str1/sre2/g 替换 范围:s/str1/sre2/g .,$ s/str1/sre2/g % s/str1/sre2/g 块复制: : 1,3 y --> 复制 1~3行
1.10.2、查看文件
cat head tail nore less(不要) cat 文件名 //查看文件 cat -n 文件名 //连同行号一起查看 head -n 文件名 //查看前n行 head -5 文件名 //查看前5行 tail -n 文件名 //查看后n行 tail -1 文件名 //查看最后1行
1.10.3、> 重定向
cat 1.c > 2.c //把1.c里面的内容放到2.c里面,相当于复制 diff 比较一个文件一不一样,若没有输出内容,文件内容就一样; >> 追加 cat 1.c >> 2.c //把1.c里面的内容追加到2.c | 管道:把前面的结果作为后面的输入。 “|”是管道命令操作符,简称管道符。 利用Linux所提供的管道符“|”将两个命令隔开,管道符左边命令的输出就会作为管道符右边命令的输入。 连续使用管道意味着第一个命令的输出会作为 第二个命令的输入,第二个命令的输出又会作为第三个命令的输入,依此类推。 练习:把一个文件的第5行输出到终端上。 ① head -5 /etc/passwd > 1.c tail -l 1.c ② head -5 /etc/passwd | tail -l
1.10.4、grep 搜索
grep “string” 参数 文件 参数: -n 行号 -R 递归搜索 -i 不区分大小写 -w 精确查找,字符串前后如果有内容就查询不到; grep "include" -n 4.linux_高阶进阶.c
1.11、find
find 路径 -name 文件名
1.12、cut
cut -d : -f 1,2 filename /etc/passwd farsight: x :1000:1000:ubuntu,,,: /home/farsight: /bin/bash 用户名 密码 uid gid 描述 主目录 练习: 查一下当前用户 用户名:UID:GID head -34 /etc/passwd | tail -1 | cut -d : -f 1,3,4 查一下当前用户行号 cat /etc/passwd | grep "farsight" -n | cut -d : -f 1
1.13、修改文件的权限、用户、组。
ls -l
-rw-rw-r-- 1 farsight farsight 18672 6月 15 08:48 4.linux_高阶进阶.c 权限 链接数 用户 组 -: 文件的类型 bcd-lsp rw-:用户的权限 u rw-:组的权限 g r--:其他权限 o 所有权限: ugo 或者 a
ls -l 列出属性 drwxr-xr-x 一个10个字符。第一个字符表示文件类型,后面9个字符表示文件权限。 rwx:r(可读)、w(可写)、x(可执行)。 第一组:表示文件属主权限。 第二组:表示属主所在的组用户的权限。 第三组:表示其他用户的权限。
r:4 w:2 x:1 最高权限:777 r 可读 4 w 可写 2 x 可执行 1 - 无权限 0 有了这个编码规则,则drwxr-xr-x 编码后为755 三个为一组: 7 5 5
(1)修改权限:
第一种修改权限的方法 *** 要把 drwxr--r-- 则对应的编码为744 修改命令:chmod 744 文件名
第二种修改权限的方法: 在原来的权限基础上修改,即增加或减少某权限。 三个组用户的编码依次为:属主u 属主所在的组g 其他用户o 如属主增加可执行权限 chmod u+x 文件名 其他用户增加可写权限 chmod o+w 文件名 属主所在组用户去掉可执行权限 chmod g+x 文件名 chmod 777 2.c 赋最高权限 ls -l 2.c -rwxrwxrwx 1 farsight farsight 431 6月 16 09:24 2.c chmod u-x 2.c ls -l 2.c -rw-rwxrwx 1 farsight farsight 431 6月 16 09:24 2.c chmod g-x 2.c ls -l 2.c -rw-rw-rwx 1 farsight farsight 431 6月 16 09:24 2.c chmod o-w-x 2.c ls -l 2.c -rw-rw-r-- 1 farsight farsight 431 6月 16 09:24 2.c
(2)修改用户:
chown sudo chown 用户名 文件 修改文件所属的用户 sudo chown 用户名:组名 修改文件用户和组 chgrp sudo chgrp root 2.c 修改文件的组
1.14、软链接与硬链接
1.14.1、软链接:相当于windows的快捷方式
创建软连接文件:ln -s 源文件名 符号连接文件名 reg:ln -s src.c linker.c linker.c就是src.c的一个符号连接文件 ln -s 源文件 链接文件 ln -s a.out app 结论: (1)app 相当于a.out 的快捷方式; (2)app 是一个链接文件, a.out 是普通文件; (3)a.out 的链接数不变; (4)把源文件删除或者移动到其他路径,链接文件就不可以用了; (5) 用绝对路径创建软链接,把链接文件移动到其他路径是可以用的; eg: ls -n /home/farsight/210501/day1/day1/a.out app ls -l app lrwxrwxrwx 1 farsight farsight 37 6月 16 14:05 app -> /home/farsight/210501/day1/day1/a.out
1.14.2、硬连接:对文件起别名
ln 源文件名 连接文件 硬连接实际上和源文件在硬盘中是同一个东西,效果类似于硬盘上的一个文件。 结论: (1)链接数变了 (2)两个文件的iNode号是一样的 (3)硬链接的文件可有移动1到其他路径下使用 (4)硬链接文件是一个普通文件
1.15、通配符
* : 匹配所有字符 ? : 匹配一个字符 []: [字符1字符2] 匹配字符1和字符2中的任意一个字符,不能同时匹配两个字符;[1234] == [1,2,3,4] ls name[12].c [字符1 - 字符2] 匹配到从字符1 至 字符2 的所有字符 ls name[A-F].c 如果出问题,清除本地化设置 export LC_ALL = C 还原: unset LC_ALL {}:touch name{1,2,3,4,5}.c 同时创建多个文件;
1.16、进程
程序的一次执行过程
ps
ps -aux
ps -aux | grep a.out 查询a.out这个进程
top 动态检测进程
kill 4797 //kill 进程号 --> 杀死一个进程
1.17、man 查询函数、库函数、命令的用法
man -a 查询所有 man 1 ls 1.表示查询的是Linux命令 man 2 xx 2.表示查询的是Linux api 系统调用 man 3 xx 3.表示查询的是Linux库函数
1.18、用户管理
1.18.1、添加用户
adduser 用户名 /etc/skel 模板文件 /etc/passwd 用户信息 /etc/group 组的信息
1.18.2、切换用户
su 用户名 新用户用不了sudo 解决: sudo su root //进入root用户 chmod u+w /etc/sudoers //修改可执行权限 sudo vi /etc/sudoers //进入权限为普通用户修改 添加: test ALL = (ALL:ALL) ALL //添加普通用户 chmod u-w /etc/sudoers //把权限修改回来
1.18.3、删除用户
deluser 用户名
1.18.4、关机和重启
sudo shutdown -h now 立即关机 sudo shutdown -h 16:00 关机 init 0 关机 sudo shutdown -r now 立即重启 sudo reboot 重启
1.18.5、usermod
sudo usermod -aG farsight mytest 把mytest这个用户追加到farsight这个组里; 用 id 用户名 可以看到效果: id mytest sudo usermod -c hello mytest 把mytest这个用户的第五个描述修改为hello; sudo usermod -d /home/farsight mytest 把mytest 这个用户的家目录改为 /home/farsiht sudo usermod -g farsight mytest 把mytest这个用户的组改为 farsight id mytest uid=1003(mytest) gid=1000(farsight) groups=1000(farsight) sudo usermod -l test1 mytest 把mytest这个用户名改为test1 注意:不要在用户登录的时候修改信息。若果还是报错,把当前终端退出, (exit)
1.18.6、修改密码
sudo passwd user1 为名为user的用户设置密码
1.19、磁盘相关的命令
1.19.1、查看磁盘的相关信息
sudo fdisk -l
/dev/sda: 系统盘 --> Disk /dev/sda: 21.5 GB, 21474836480 bytes
1.19.2、查看磁盘分区信息
df -h
1.19.3、将U盘挂载在Ubuntu上: USB/2.0 3.0
虚拟机 -> 可移动设备 -> flush disk
在家目录创建:mkdir ~/udisk
挂载: sudo mount /dev/sdb1 ~/udisk
就可以进入到udisk中访问u盘:
取消挂载:
sudo umout /dev/sda1 ~/udisk
1.20、网络知识
域名解析服务器: 8.8.8.8 114.114.114.114.114 自己的ip地址: 192.168.6.81 sudo vi /etc/network/interfaces 打开配置文件 auto lo iface lo inet loopback auto eth0 iface eth0 inet dhcp //两个字符串之间是tab键的距离 sudo /etc/init.d/networking restart 让配置文件生效 如果没有图标: sudo vi /etc/NetworkManager/NetworkManager.conf 2 [main] 3 plugins=ifupdown,keyfile 4 dns=dnsmasq 5 6 no-auto-default=00:0C:29:A4:5E:47,00:0C:29:85:E8:39,00:0C:29:02:7A:D6, 7 8 [ifupdown] 9 managed=true //把false 改成 true
1.21、环境变量
env 查看环境变量 查看单个环境变量: echo $PATH PATH 它是用来保存系统可执行程序路径的变量 /usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/farsight/OpenWrt-SDK-ar71xx-for-linux-i686-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin:/home/farsight/gcc-4.6.4/bin echo $HOME 主目录 如何使得a.out可以直接使用: ①只针对当前终端有效。 export PATH=${PATH}:./ export 导入环境变量 PATH 环境变量 = 赋值 ${PATH} 引用环境变量path 里的内容 : 起到分割的作用 ./ 把当前路径加上去 ②在当前用户下生效 vi .bashrc 打开 在最后的位置添加: //export PATH=${PATH}:./ //export PATH=${PATH}:./home/farsight 在主目录下生效 ③在所有文件下省效 PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/game s:/home/farsight/OpenWrt-SDK-ar71xx-for-linux-i686-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/ toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin:/home/farsight" source /etc/environment //让过程更改的环境变量生效 或者 sudo reboot 重启;
二、shell
2.1、实质:shell命令的有序集合
把shell脚本放在一个文件中,那么这个文件就是shell脚本
2.2、shell命令行解释器
sh
csh
ksh
bash --> ubuntu
2.3、shell脚本
2.3.1、后缀为.sh
eg:(1)在家目录创建一个目录 mydir (2)把 /etc/passwd 和 /etc/groff 复制到mydir (3)压缩并归档位mydir.tar.gz eg:#!/bin/bash cd mkdir mydir cp /etc/passwd ./mydir cp -a /etc/groff ./mydir tar -cvzf mydir.tar.gz mydir
2.3.2、shell脚本为解释器语言,不需要编译
2.3.3、运行
(1)创建脚本 :vi demo.sh
在开头加上:#!/bin/bash
(2)修改权限:
chmod 777 demo.sh 修改为可执行的文件
(3)执行脚本
./demo.sh bash demo.sh source demo.sh 三种运行方式的区别: (1)./执行的时候需要赋上可执行的权限,后两者可以直接执行; (2)./和bash在执行的时候会新开一个字终端,最后把结果直接返回给终端。 (3)source 执行的时候在当前终端执行,一般用来让某个脚本生效;
2.4、shell脚本的变量
2.4.1、变量的定义
没有数据类型,不需要提前定义直接使用;
给变量赋值的时候等号左右不能有空格
每一行语句不需要加‘;’
变量名见名知意;
赋值给变量都默认为字符串;
2.4.2、变量的引用
$var
$(var)
2.4.3、在给吧变量赋值的时候可以加双引号和单引号,也可以不加:
单引号和双引号的区别: 单引号和双引号内都可以加空格; 单引号里面不能引用变量 给变量赋值的时候不需要加上 $ var=10 var=11; // 再次赋值 eg:#!/bin/bash a=22 b="open book" c="$a open" echo $a echo $b echo $c 输出: 22 open book 22 open 单行注释: # 多行注释: :<<EOF 被注释的内容 EOF 或者 :<<! 被注释的内容 !
2.4.4、删除变量:变量被删除后不能再次使用
unset var1 eg:myur1="www.baidu.com" unset myur1 echo $myur1 输出: //空格
2.4.5、命令置换
把命令赋值给了一个变量 var=`ls` 或者 var=$(ls) //不输出不会执行 eg: var=`ls` var1=$(ls) echo $var echo $var1
2.4.6、位置变量
$0 $1 $2 $3... $# $* $@ $$ $0 用./ 和 bash执行 代表shell脚本文件名,用source执行代表bash $1 shell脚本文件名后面第一个参数 $2 shell脚本文件后面第二个参数 $* 和 $@ 表示shell文件名后面的所有参数,不包含文件名 $# 表示shell文件名后面所有的参数,不包含文件名 $$ 表示进程号
练习: 用一个变量1保存PATH, 变量2保存HOME, ----> 交换; var1=${PATH} var2=${HOME} echo var1: $var1 echo var2: $var2 var3=$var1 var1=$var2 var2=$var3 echo var1: $var1 echo var2: $var2
2.4.7、shell处理字符串
(1)、字符串的复制
str=hello strl=$str eg:#!/bin/bash str=hello str1=$str echo $str echo $str1 输出: hello hello
(2)、字符串的连接
str=hello str2="$str hello" eg:#!/bin/bash str=hello str1=$str str2="$str1 hello" echo $str echo $str1 echo $str2 输出: hello hello hello hello
(3)、字符串的长度
string=“hdsjf” echo $(#string)
(4)、字符串的提取
strstr() str1[] = "hello world" str2[]= "world" ① ${str:start:len} 从左边的0开始数,数到start的位置,从这个位置输出len个字符; eg:str="www.baidu.com" echo ${str:3:4} 结果: .bai ② ${str:start} 从左边的0开始数,数到start的位置,从这个位置开始输出直到最后一个字符结束; eg:str="www.baidu.com" echo ${str:3} 结果: .baidu.com ③ ${str:0-start:len} 从右边的0开始数,数到start的位置,从这个位置的后一个字符开始输出len个字符; eg:str="www.baidu.com" echo ${str:0-4:3} 结果: .co ④ ${str:0-start} 从右边的0开始数,数到start的位置,从这个位置的后一个字符输出直到最后一个字符结束; eg:str="www.baidu.com" echo ${str:0-7} 结果: idu.com ⑤ ${str#*sub} 从左边开始数,第一遇到 sub , 输出它后面的所有内容; eg: str="www.baidu.com www.baidu.com www.baidu.com" 针对于:⑤-⑧ echo ${str#*bai} 结果:du.com www.baidu.com www.baidu.com ⑥ ${str##*sub} 从左边开始数,最后一次遇到 sub , 输出它后面的所有内容; eg:str="www.baidu.com www.baidu.com www.baidu.com" echo ${str##*bai} 结果 du.com ⑦${str%sub*} 从右边开始数,第一次遇到 sub ,输出它前面的所有内容; ~ eg:str="www.baidu.com www.baidu.com www.baidu.com" echo ${str%bai*} 结果: www.baidu.com www.baidu.com www. ⑧${str%%sub*} 从右边开始数, 最后一次遇到 sub ,输出它前面的所有内容; eg:str="www.baidu.com www.baidu.com www.baidu.com" echo ${str%%bai*} 结果: www.
2.5、shell 处理数组
数组定义:
arr=(1 2 3 4)依次对数组赋值;数组的下标也从0开始数的。
arr=([0]=aaa [2]=bbb) 对数组里面的部分元素
注意:没有被赋值到的地方就为空(不是零)。
2.5.1、数组的引用:数组的下标也是从0开始数的
${数组名字[下标]}
2.5.2、引用整个数组
${arr[*]} 或者 ${arr[@]}
2.5.3、求数组元素的长度
echo ${#arr1[0]} //arr1[0]整个数组的长度
2.5.4、求整个数组里面被赋值的元素的个数
echo ${#arr1[@]}
2.5.5、清空数组
unset arr[0] 清空这个元素
unset arr[*] 清空整个数组
2.5.6、arr=(${arr[*]} "how are you") 在数组后面添加内容
arr=("hello" ${arr[*]}) 在数组前加内容
eg: #!/bin/bash arr=(1 2 3 4) echo ${arr[0]} echo ${arr[2]} echo ${arr[*]} echo ${arr[@]} arr[2]=20; arr[5]=10 echo ${arr[5]} echo --------------- arr1=([0]=hello [3]=56 [6]=bbb) echo arr1:${arr1[0]} echo arr3:${arr1[3]} echo arr6:${arr1[6]} echo arr2:${arr1[2]} echo ${#arr1[0]} echo ${#arr1[@]} unset arr1[0] echo ${arr1[0]} echo ................ unset arr1[*] echo ${arr1[*]} 结果: 1 3 1 2 3 4 1 2 3 4 10 --------------- arr1:hello arr3:56 arr6:bbb arr2: 5 3 ................
2.6、read 从终端上输入
read 变量
2.6.1、如果输入两个变量
用法:read var1 var2 var1 和 var2 的复制通过第一个空格来分割, //空格前面的内容赋值给var1,后面的所有内容赋值给var2 单次输入 eg:#!/bin/bash echo "please enter a var ->:" read var echo var:$var 两次输入: // 两次输入即可输入带空格的字符串; read var1 read var2
2.6.2、read -p "提示" var //输入提示性的东西
2.6.3、read -a arr (数组名) //输入一个数组
read -p "请输入一个数组" -a arr // read -a arr
echo ${arr[*]}
2.6.4、read -n num var
read -n 5 var //输入5个字符以后直接退出
2.6.5、read -t 秒钟 var //在规定的时间内输入,超时自动退出
2.6.6、read -s var //输入的没有回显
eg: read -p "请输入用户名" var1 read -p "请输入密码" -s var2 echo var1 = $var1 echo var2 = $var2 结果: 请输入用户名farsight 请输入密码 var1 = farsight var2 = 1
2.7、shell输入
echo $var echo hello echo "hello" echo 'hello' echo -n "hello world" 不换行
2.8、shell的运算
+ - * / % > < ++ -- ** 幂运算 += -= *= /= && || ! > < == =(shell也可以用来做等于) & | ~ ^
2.8.1、(( ))
((表达式))
((表达式1,表达式2,表达式3)) 执行最后一个表达式的结果
取值:$((表达式))
(1)表达式里面取变量的时候可以加$,也可以不加; (2)可以运算结果赋值给一个变量 ret=$((表达式)) (3)可以支持自加或者自减运算 ((var1++)) echo $var1 (4)运算的时候可以加空格 (5)$? 执行成功,返回上一次执行过程(上一次逻辑为真返回0,上一次逻辑为假返回1) (6)支持整数运算,不支持字符串运用
eg:#/bin/bash var1=10 var2=20 var3=$((var1+var2)) echo var1+var2 = $var3 var3=$(($var1 + $var2)) echo var1+var2 = $var3 ret=$(($var1+$var2)) echo ret = $ret ((var1++)) echo var1=$var1 ((mm=3**2)) echo mm=$mm echo $((mm=3**2)) #复杂运算 echo $((var1 > var2)) echo $((var1 < var2)) echo $? #返回上一次执行结果 ((var2 > var1)) echo $? #shell 逻辑为真返回0,为假返回1 输出: var1+var2 = 30 var1+var2 = 30 ret = 30 var1=11 mm=9 9 0 1 0 0
2.8.2、$ [ ]
ret=$[表达式]
ret=$[表达式1,表达式2,表达式3,......]
(1)需要把执行结果赋值给一个变量 (2)可以支持自加,自加的时候不能加$ (3)在运算的时候变量也可以加$,也可以不加 (4)如果有多个表达式则执行右边的结果 (5)支持整数运算,不支持字符串运用
eg:#/bin/bash var1=10 var2=20 ret=$[var1++] ret=$[$var1+$var2] echo $ret echo $var1 ret=$[1,2,3,3+4] echo $ret ret=$var echo $ret ret=$[var+1] echo $ret ret=$[var * 3] echo $ret ret=$[var / 3] echo $ret 输出: 31 11 7 1 0 0
2.8.3、expr
(1)支持整数运算并且支持字符串的相关操作 (2)expr 可以直接输出结果 (3)expr 的运算需要加空格 (4)expr 的运算,变量的引用需要加$ (5)expr 在赋值的时候需要命令置换 ①var=`expr $var1 + $var2` ②var=$(expr $var1 + $var2) (6)expr 不支持自加 (7)expr 不支持幂运算 (8)expr 识别不了*,需要加\字符 \* \> \< \(\) 不加默认为数组
eg:#/bin/bash var1=10 var2=20 expr var1+var2 expr $var1+$var2 expr $var1 + $var2 var=`expr $var1 + $var2` echo $var var=$(expr $var1 + $var2) echo $var expr $var1++ #不支持自加 expr ++$var1 expr $var1 expr mm=3**2 echo $mm ret=$(expr $mm=3**2) echo ret = $ret expr $var1 \* $var2 输出: var1+var2 10+20 30 30 30 10++ ++10 10 mm=3**2 ret = =3**2 200
2.8.4、字符串操作
匹配字符串:
expr match $var "sub" //从开头匹配字符串,有多少个字符相同就返回多少的数
eg:str="hellowoed" #str="hell owoed" #error 不能加空格 expr match $str "hel" expr match $str he expr match $str "wor" expr match $str w expr length $str #求字符串长度 输出: 3 2 0 0 9
2.9、if else
if [条件] then shell语句1 else shell语句2 fi if [条件] then shell语句1 elif [条件] shell语句2 then shell语句3 else shell语句4 fi 判断: ①[表达式] --> 表达的前后必须加空格\[\]前后也要加空格; ②test 前后加空格
2.9.1、数字大小判断
-eg 等于 -ne 不等于 -gt 大于 -ge 大于等于 -lt 小于 -le 小于等于
2.9.2、逻辑的判断
&& --> -a || --> -o ! --> ! 练习:输入一个成绩, [90-100] A [70-90) B [60-70) C [0-60] D eg:#/bin/bash read -p "please enter a sore:>" num if test $num -gt 100 -o $num -lt 0 then echo "error ---> [0-100]" exit 1 fi if test $num -ge 90 -a $num -le 100 then echo A elif test $num -ge 70 -a $num -lt 90 then echo B elif test $num -ge 60 -a $num -lt 70 then echo C else echo D fi #bash if_score.sh #. if_score.sh # ./if_score.sh source if_score.sh exit num num == 1 非正常退出 num == 0 正常退出 shell文件中:再次调用脚本 #bash if_score.sh #. if_score.sh # ./if_score.sh source if_score.sh
2.9.3、字符串的判断
-n 判断字符串非空
-z 判断字符串为空
= 判断字符串相等
!= 判断字符串不等
> 比较字符串的大小
<
if test -n "$var1" -a -n "$var2"
1参数放前面
2变量的引用需要加" ",不然输入空的时候会报错。
练习:从终端输入两个字符串,判断是否为空,如果不为空则比较大小; eg:#!/bin/bash read var1 read var2 if test -n $var1 -a -n $var2 then if test $var1 \> $var2 then echo "$var1 > $var2" else echo "$var1 < $var2" fi else echo "不空" fi
2.9.4、文件判断
bsp-lcd
-b 判断文件是否存在,并且判断是否为块设备文件
-s 判断文件是否存在,并且判断是否为套接字文件
-p 判断文件是否存在,并且判断是否为管道文件
-f 判断文件是否存在,并且判断是否为普通文件
-c 判断文件是否存在,并且判断是否为字符设备文件
-L 判断文件是否存在,并且判断是否为链接文件
-d 判断文件是否存在,并且判断是否为目录文件
-e 判断文件是否存在,
-s 判断文件是否存在,且判断文件是否为空,文件大小大于0,返回真值。
练习:输入一个文件名字。判断是普通文件还是目录文件 eg:#!/bin/bash file="/home/farsight/HuaQing_vision/qrs210501/2.linux_c高级/day4/" #read -p "请输入一个文件名:" file if [ -f $file ] then echo "普通文件" elif [ -d $file ] then echo "目录文件" else echo "文件不存在" fi
2.9.5、判断文件的权限
-w 判断写权限 -r 判断有没有读权限 -x 判断有没有执行权限
2.9.6、判断文件的时间戳
-nt 比较两个文件的时间戳更新
-ot 比较两个文件的时间戳更旧
练习:输入一个文件名,判断是否具有写权限,如果有,那么将helloworld写在这个文件里,如果没有添加权限再写进去; eg:#!/bin/bash read -p "请输入一个文件名" filename if test -w $filename then echo "helloworld" > $filename else echo "没有写权限" chmod u+w $filename echo "helloworld" > $filename
练习:输入两个文件名,判断时戳 eg:#!/bin/bash read -p "enter file1>:" file1 read -p "enter file2>:" file2 if test -e $file1 -a -e $file2 then if test $file1 -nt $file2 then cat $file1 > $file2 else cat $file2 > $file1 fi else echo "文件不存在" fi
2.9.7、case 表达式 in
参数1 shell 语句1 ;; 参数2 shell 语句2 ;; 参数3 shell 语句3 ;; 参数4 shell 语句4 ;; esac
eg:echo '输入 1 到 4 之间的数字:' echo '你输入的数字为:' read aNum case $aNum in 1) echo '你选择了 1' ;; 2) echo '你选择了 2' ;; 3) echo '你选择了 3' ;; 4) echo '你选择了 4' ;; *) echo '你没有输入 1 到 4 之间的数字' ;; esac
* --> 所有
练习:模拟一个软件的下载的过程 #!/bin/bash read -p "enter num :" app read -p "请选择命令[Y/N/Q]" cmd case $cmd in Y|YES|yes|) echo "$app 正在下载....." ;; N|NO|no|) echo "取消下载 $app....." ;; Q|quit|q|) exit 0 esac
2.10、循环: while [条件]
do 语句 done 无限循环: while true do echo "***" done
练习:写一个加法计算器, 输入一个值就一直累加,输入 exit 退出; eg:#!/bin/bash while read -p "请输入一个整数或者输入q 退出:" num do if test $num = q then exit 0 else ((sum+=$num)) echo ret: $sum fi done
用法1: for((表达式1;表达式2;表达式3)) do shell语句块
用法2: for var in 单词列表 do shlle语句 done 单词列表: 1)如果是散乱的列表,列表中用空格作为分割; 2)顺序的列表: {start..end} eg: for var int {1..100}
2.11、函数
函数的一般形式:
function 函数名()
{
}
(1)shell函数没有形式参数,没有返回值(也可以有) (2)函数中的变量为全局变量 (3)将命令执行的结果作为作为单词列表 (4)for var in `ls` 1.function 代表这是一个函数 (5)使用local 修饰是局部变量
函数的调用: 函数名 函数名:argv[1] argv[2] ... | | | $0 $1 $2
eg:#!/bin/bash function add(){ sum=$((10+20)) } add echo $sum function add1(){ sum=$(($1+$2)) } add1 50 60 echo $sum function add2(){ local sum=$(($1+$2)) return $sum } add2 $1 $2 echo $?
三、c高级
3.1、c语言的本质
操作虚拟的内存
3.2、c语言中如何分配内存
3.2.1、数据类型
(1)、基本数据类型
int float char short long double
(2)、用户自定义的数据类型
数组: 在内存中连续开辟相同数据类型的空间 结构体:描述一个对象,对象具有很多的属性 关键字: struct 结构体的数据类型 == 关键字+结构体名 结构体指针 (01struct.c) 结构体数组 (02struct_arr.c) 字节对齐:32位系统下,4字节对齐, 会画图 共用体:类似于结构体 关键字: union 特性1:共用体中每个成员都共用同一个内存起始地址,共用体占用的内存等于最大的成员占用的内存 特性2:如果对新的成员赋值,会把原来的成员的值覆盖掉
(3)、指针类型
(1)基本用法 & : 取出变量的地址 * : 取出地址的值 05pointer.c (2)特点 : 指针是有粗细的 (3)数组指针(行指针) 07shuzu_zhizhen.c (4)指针数组 08zhizhen_shuzu.c (5)二级指针 09erji_pointer.c (6)不定类型的指针 : void * pthread_create();
3.2.2、程序员手动开辟内存空间
malloc free
#include <stdio.h> #include <stdlib.h> //malloc包含头文件 int main(void) { // 需要一个1000个int类型元素的数组 // 第一步:申请和绑定 int *p = (int *)malloc(1000*sizeof(int)); // 第二步:检验分配是否成功 if (NULL == p) { printf("malloc error.\n"); return -1; } // 第三步:使用申请到的内存 //p = NULL; //p = &a; // 如果在free之前给p另外赋值,那么malloc申请的那段内存就丢失掉了 // malloc后p和返回的内存相绑定,p是那段内存在当前进程的唯一联系人 // 如果p没有free之前就丢了,那么这段内存就永远丢了。丢了的概念就是 // 在操作系统的堆管理器中这段内存是当前进程拿着的,但是你也用不了 // 所以你想申请新的内存来替换使用,这就叫程序“吃内存”,学名叫内存泄漏 //申请后使用 *(p+0) = 1; *(p+1) = 2; printf("*(p+0) = %d.\n", *(p+0)); printf("*(p+1) = %d.\n", *(p+1)); *(p+222) = 133; *(p+223) = 222; // 第四步:释放 free(p); p = NULL; //释放之后p指针就没有指向了;p=NULL,防止野指针 printf("*(p+222) = %d.\n", *(p+222)); printf("*(p+223) = %d.\n", *(p+223)); return 0; }
3.3、函数
3.3.1、函数形式
返回值 函数名(参数)
{
}
3.3.2、函数传参
值传递
地址传递
3.3.3、函数封装
main.c : 主函数, 函数调用
fun.c : 各种方法
fun.h : 函数声明、结构体
3.3.4、指针函数:返回值是一个地址的函数
3.3.5、函数指针:本质是一个指针,指向一个函数
vi指定复制:shift+鼠标选择
3.3.6、函数指针数组:本质上是一个数组,保存的是一个函数指针。
3.3.7、递归函数:自己调用自己。注意必须有终止条件。
3.3.8、回调函数:点餐, 服务员, 厨师
回调函数模型
3.4、gcc、gdb
3.4.1、使用gcc对代码进行编译
-
1>预处理 :
gcc -E 1.c -o 1.i 预处理:用于将所有头文件以及宏定义替换成其真正的内容,预处理之后得到的仍然是文本文件,但文件体积会大很多。 -
2>编译 :
gcc -S 1.c -o 1.s 生成汇编语言源代码文件 -
3>汇编 :
gcc -c 1.c -o 1.o 将上一步的汇编代码转换成机器码,二进制格式 -
4>链接 :
gcc 1.c 生成可执行文件,将多个目标文件以及所需要的库文件(.so等)链接成最终的可执行文件
3.4.1、使用gdb对代码进行调试
编译的时候需要添加一个-g的参数
gcc 08malloc.c -g
使用gdb运行程序
gdb a.out
获取帮助信息:
(gdb)help
查看代码
l 默认显示的是前10行
l 可以向下查看下面的10行
l - 向前显示10行
添加断点
b 行号
如何查看断点
info b
删除断点
delete 断点号
运行代码:
r 运行代码,在断点的位置会停掉
查看数据
p 变量
watch 变量
单步运行
n 单步运行,当遇到函数时不会显示函数执行过程
s 单步运行,当遇到函数时显示函数执行过程
继续运行
c 没有错误就继续向下运行,在断点的位置会停掉
退出调试:
q 退出
3.5、存储类型
存储类型(6种) auto static register extern volatile const
3.5.1、auto: 在定义变量的时候,默认存储类型为auto。
全局变量和局部变量:
#include <stdio.h> int x=10; void func(void) { printf("x = %d\n",x); } int main(int argc, const char *argv[]) { auto int x=5; //作用域 花括号 printf("x = %d\n",x); //5 { auto int x=7;//作用域 花括号 printf("x = %d\n",x); //7 } printf("x = %d\n",x); //5 func(); //10 return 0; }
3.5.2、extern :可以用来声明变量或者函数是在其他文件中
#include <stdio.h> extern int a, b; extern int fun(int , int ); int main() { printf("a = %d\n", a); printf("b = %d\n", b); printf("a+b = %d\n", fun(a,b)); } #include <stdio.h> int a = 12, b = 13; #include <stdio.h> int fun(int a, int b) { return a+b; }
3.5.3、static
(1)、延长变量的生命周期
#include <stdio.h> void func(void) { static int a=1; static int b; //如果a没有被static修饰,默认a在栈上存放,当函数被调用的使用分配栈空间,当函数调用完,栈就会被释放了。所有这里打印的a的值都是2; //如果加上了static修饰,并且static修饰的变量被赋值了,static修饰的变量在静态区种的.data存放着,在函数执行结束的时候,data段不会被释放,所以打印的结果是2 3 4 //static修饰的变量如果没有被初始化,变量在.bss段存放着 a++; printf("b = %d\n",b); printf("a = %d\n",a); } int main(int argc, const char *argv[]) { func(); func(); func(); return 0; }
(2)、限定作用域(对象可以是函数,也可以是变量)
static修饰的变量或者函数只能在当前文件中使用
3.5.4、const :只读的变量
const int a=10;
a=100; //错误的,const修饰的变量不允许修改
(1)、const修饰局部变量 --> 可以改变值 栈区
(2)、const修饰全局变量 --> 不能改变值 只读区
#include <stdio.h> const int b=500; //只读区 int main(int argc, const char *argv[]) { const int a=10; //栈 //a=100; //错误的,const修饰的变量不允许修改 int *p=(int *)&a; *p=100; printf("*p = %d,a = %d\n",*p,a); p=(int *)&b; *p=123; printf("*p = %d,b = %d\n",*p,b); return 0; }
(3)、const修饰指针
#include <stdio.h> int main(int argc, const char *argv[]) { int a=100; int b=234; //第一种 const int *p=&a; *p=50; //p指向的地址中的内容不能修改 p=&b; //p指向的地址可以修改 //第二种 int const *p=&a; *p=50; //p指向的地址中的内容不能修改 p=&b; //p指向的地址可以修改 //第三种 int *const p=&a; *p=50; //p指向的地址中的内容可以修改 p=&b; //p指向的地址不能修改 //第四种 const int *const p=&a; *p=50; //p指向的地址中的内容不能修改 p=&b; //p指向的地址不能修改 return 0; }
3.5.5、register :(寄存器)
register int a;
定义的register类型的变量要比不加register的时候执行的速率要快。
问题1:寄存器类型的变量执行的速率快,能不能把所有的变量都定义成寄存器类型的变量?
答案:不能,在芯片内部寄存器是有个数限制的,比如在A53硬件平台上只有40个寄存器。
问题2:在定义变量的时候const和volatile能不能同时使用?
答案:可以的,只读的状态寄存器
3.5.6、volatile:(易变的)
volatile int a;
(1)、编译器优化 -O3
volatile int *a=&b; //防止编译器对代码进行优化
*a = 110;
*a = 120;
(2)、防止cpu值取数据从缓存(cache register)中取
volatile修饰的变量每次都从内存中取出
(3)、在开发过程中需要定义变量的时候需要加volatile
1.在定义硬件地址的时候。(比如:状态寄存器)
2.在中断处理函数中访问的非自动变量时,需要添加volatile
3.多个线程访问的同一个变量
例如:向0x80000000地址中写入0x12345678值
volatile unsigned int *p=(volatile unsigned int *)0x80000000
*p=0x12345678;
四、makefile
4.1、什么是Makefile
一个文件,对项目进行管理
Makefile可以体现你是否具备大型项目的开发能力
4.2、什么是make
是一个工程管理器,管理较多的文件
是一个可执行程序,通过读取Makefile内容,调用编译器进行编译工作
(本质工作还是GCC在做)
根据文件时间戳来编译文件(文件更新时间)
只编译修改后的文件,而不用全部编译,节省时间。
Makefile是make读入的唯一配置工具
4.3、体验Makefile
all: //---标签 gcc -E test.c -o test.i gcc test.c -Wall -o test //--要做的事情,前面是一个tab键! clean: //---标签 rm test.i test 1.make默认执行all标签下内容 2.make clean 会执行clean标签后的内容,删除文件 all: //---标签 gcc -E test.c -o test.i gcc test.c -Wall -o test .PHONY: //伪指令 clean: rm test.i test 伪目标:不生成目标文件的目标为伪目标 .PHONY: 的作用是将clean文件属性屏蔽掉,只单纯的任务就是一个伪目标
4.4、Makefile的规则
目标:依赖文件
操作
out:main.o fun1.o fun2.o gcc main.o fun1.o fun2.o -o out main.o:main.c gcc -c main.c -o main.o fun1.o:fun1.c gcc -c fun1.c -o fun1.o fun2.o:fun2.c gcc -c fun2.c -o fun2.o
4.5、变量
节省繁复的操作,方便替换
类似shell脚本中的变量
CC=gcc
$(CC)
CC=arm-linux-gcc out:main.o fun1.o fun2.o $(CC) main.o fun1.o fun2.o -o out main.o:main.c $(CC) -c main.c -o main.o fun1.o:fun1.c $(CC) -c fun1.c -o fun1.o fun2.o:fun2.c $(CC) -c fun2.c -o fun2.o CC 默认值gcc CC = arm-linux-gcc RM 默认值为rm 删除命令 CFLAGS 编译器的参数选项 LDFLAGS 编译器链接文件及路径 APP 文件最后生成的可执行程序a.out SRCS 所有的.c文件 OBJS 依赖文件 eg: #编译时的编译选项 CFLAGS = -Wall -o2 -g -std=gnu99 -pthread -I./include -DMYDBG LDFLAGS = -L./lib/x86/ -lcam -L./lib/x86/ -lserial -L./lib/x86/ -ltcp -ljpeg -lpthread #用户自定义变量,保存 可执行程序的名字 APP = server #自定义变量,用来保存某个目录下的所有 C文件 SRCS = $(wildcard ./src/*.c) #自定义变量,将某个变量中的所有C文件,替换成 .o 文件 OBJS = $(patsubst %.c, %.o,$(SRCS)) CC = gcc #CC = arm-linux-gcc all: $(APP) $(APP): $(OBJS) $(CC) -o $(APP) $^ $(LDFLAGS) $(RM) $(OBJS) clean: $(RM) $(OBJS) $(APP)
更多详情makefile 可参考文档
跟我一起学makefile
百度云下载链接:https://pan.baidu.com/s/1McHYZuCSGjpOK19UOqLQeQ
跳转:上一篇、Linux c基础!
待更新。。。
跳转:下一篇、数据结构与算法!
跳转:下一篇、数据结构与算法!
跳转:开头
这篇关于Linux c高级的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-12如何创建可引导的 ESXi USB 安装介质 (macOS, Linux, Windows)
- 2024-11-08linux的 vi编辑器中搜索关键字有哪些常用的命令和技巧?-icode9专业技术文章分享
- 2024-11-08在 Linux 的 vi 或 vim 编辑器中什么命令可以直接跳到文件的结尾?-icode9专业技术文章分享
- 2024-10-22原生鸿蒙操作系统HarmonyOS NEXT(HarmonyOS 5)正式发布
- 2024-10-18操作系统入门教程:新手必看的基本操作指南
- 2024-10-18初学者必看:操作系统入门全攻略
- 2024-10-17操作系统入门教程:轻松掌握操作系统基础知识
- 2024-09-11Linux部署Scrapy学习:入门级指南
- 2024-09-11Linux部署Scrapy:入门级指南
- 2024-08-21【Linux】分区向左扩容的方法