该文为学习笔记,仅作学习参考,如有错误,望指正!

一. 基础命令

  1. GNU -> GNU is not UNIX;

    GPL -> General Public License;

  2. 内核:内核是 Linux 系统的最底层,提供了系统的核心功能并允许进程以一种有序的方式访问硬件。用于控制进程、输入、输出设备、文件系统操作、管理内存。

  3. Linux 内核支持多用户、多任务模式运行。

    多用户:同时有多个用户访问系统;

    多任务:某个时刻有多个程序运行;

  4. Shell 是一个命令行解释器,它使得用户能够与操作系统进行交互;

  5. vim 是 vi 的升级版,如果想要自己配置 vim 的话,首先要安装 vim(sudo apt-get install vim-gtk),另外需要更改 vim 的配置文件 .vimrc 文件(sudo vim /etc/vim/vimrc),vim ~/.vimrc 如果没有就创建一个名为 ~/.vimrc 的文件,然后在将网上提供的配置文件源码复制进去即可,配置字体配色。

  6. Debian Linux 首先提出“软件包”的管理机制——Deb 软件包**,**将应用程序的二进制文件、配置文档、man/info 帮助页面等文件合并打包在一个文件中,用户使用软件包管理器直接操作软件包,完成获取、安装、卸载、查询等操作。

  7. Name_Version-Reversion_Architecture.deb:软件包名称+软件版本+修订版+体系架构

  8. dpkg:(本地已有软件安装)不可以在线安装软件,不能检查软件包的依赖关系,为了解决软件包依赖性问题和获取问题,就出现了APT工具。

    apt:不仅仅可以完成 dpkg 的功能,而且还可以从网络中下载软件,它会自动检查软件包依赖关系,会将某一软件包依赖的所有软件包都下载并安装软件源,配置文件只是告知 Ubuntu 系统可以访问的镜像站点地址。但那些镜像站点都拥有什么软件资源并不清楚。若是每安装一个软件包,就在服务器上寻找一遍,效率是很低的。因而,就有必要为这些软件资源列个清单(为镜像站点地址建立索引文件),以便本地主机查询。这就是APT软件包管理器的工作原理。

  9. 软件源配置文件就是 /etc/apt/sources.list

  10. 刷新软件源:

    1. 修改了配置文件——/etc/apt/sources.list,将适合自己的软件源替换此文件中的软件源;
    2. 使用 apt-get update 命令刷新软件源,建立最新的索引文件,更新了软件包列表;
  11. dpkg -i:安装一个在本地文件系统上存在的Debian软件包。

    dpkg -r:移除一个已经安装的软件包

    dpkg -P:移除已安装软件包及配置文件

    dpkg -L:列出安装的软件包清单

    dpkg -s:显出软件包的安装状态

  12. apt-get:用于管理软件包,包括安装、卸载、升级等操作;

    sudo apt-get install xchat ,在/var/cache/apt/archives会有已经下载的所有安装包(deb包)

  13. 内核驱动程序目录:/lib/modules/$(uname -r)/kernel

  14. env:环境变量;

    set:自定义变量;

    export:自定义变量转换为环境变量;

    locale:系统支持的语系

  15. x2dos:Linux 与 DOS 之间的格式转换工具;ex:unix2dos -k oldfile newfile;

  16. iconv:语系编码转换;

    ex:iconv -f 原编码 -t 目标编码 oldfile -o newfile

    繁体中文转换为简体中文:iconv -f utf8 -t big4 vi.utf8 |iconv -f big5 -t gb2312 |iconv -f gb2312 -t utf8 -o vi.gb.utf8

  17. KDE:桌面环境

  18. shell:命令行模式传输速度比较快,不容易掉线和信息外流。

二. 基本知识

  1. apt-get install 软件包:在 /var/cache/apt/archives 路径先下载再安装 deb 包。

    apt-get source 软件包:下载源码包,只下载不安装。

    apt-cache policy xchat:查询软件包安装状态。

    apt-get remove xchat:卸载软件包。

    –purge 与 remove 子命令一起使用,完全卸载软件包。

    clean 删除缓存区中所有已下载的包文件。

  2. Shell 是一个命令行解释器,将用户命令解析为操作系统所能理解的指令,实现用户与操作系统的交互。

  3. username@hostname:direction$:用户名+主机名+目录名

  4. 通常一条命令包含三个要素:命令名称、选项、参数。三要素之间使用空格分隔,不能连写到一起。命令名称是必须的,选项和参数都可能是可选项。

    1. 一条命令的三要素之间用空格隔开;
    2. 若将多个命令在一行书写,用分号(;)将各命令隔开;
    3. 如果一条命令不能在一行写完,在行尾使用反斜杠(\)标明该条命令未结束。
  5. 补齐命令与文件名: TAB 自动补齐。

  6. 通配符:

    1. 星号*匹配任意长度的字符串
    2. 问号?匹配一个长度的字符
    3. 方括号[…]匹配其中指定的一个字符
    4. 方括号[ - ]匹配指定的一个字符范围
    5. 方括号[^…]除了其中指定的字符,均可匹配
  7. 输入/输出重定向是改变Shell命令或程序默认的标准输入/输出目标,重新定向到新的目标。

    1. Linux 中默认的标准输入定义为键盘,标准输出定义为终端窗口。
    2. > file 将file文件重定向为输出源,新建模式
    3. >> file 将file文件重定向为输出源,追加模式
    4. < file 将file文件重定向为输入源 wc < file1,将file1中的内容作为输入传给wc命令
    5. 2> 或 &> 将由命令产生的错误信息输入到…:标准输入 0 、标准输出 1、标准错误 2
  8. 命令command2的输出将作为命令command1的参数。需要注意,命令置换的单引号为ESC键下方的 ` 键;

  9. grep -Rn "bool" ./ 在当前目录下递归查找字符串 “bool”,列出所在文件及行号;

  10. head -n file 显示某文件的前 n 行;

    tail -n file 显示某文件的后 n 行;

  11. 文件系统:用于组织和管理计算机存储设备上的大量文件,并提供用户交互接口;

  12. /dev/sda1 设备节点

  13. Ubuntu 设置共享文件目录

    cd /media/VMware\ Tools/
    cp VMwareTools-9.6.0-1294478.tar.gz ~/Desktop
    tar xvf VMwareTools-9.6.0-1294478.tar.gz
    cd vmware-tools-distrib/
    sudo ./vmware-install.pl
    
  14. /dev/sda1 含义? a 代表第一块sata硬盘, 1 第一个分区

    /dev/sdb3 含义? b 代表第二块sata硬盘, 3 第三个分区

  15. 挂载U盘:sudo mount -t vfat /dev/sdb1 ~/usb 将第二块硬盘挂载到指定目录家目录下的usb目录,-t指定文件系统类型。sudo umount ~/usb:解除挂载

  16. Linux 文件系统就是一个树形的分层组织结构。将根(/)作为整个文件系统的唯一起点,其他所有目录都从该点出发。

  17. file:查看文件类型

    参数 英文 说明
    b block 块设备
    c character 字符设备
    d directory 目录
    - 普通文件
    l link 链接文件
    s socket 套接字
    p pipe 管道
  18. 硬链接是利用Linux中为每个文件分配的物理编号——inode建立链接。因此,硬链接不能跨越文件系统。

    1. 软链接(符号链接)是利用文件的路径名建立链接。通常建立软链接使用绝对路径而不是相对路径,以最大限度增加可移植性。
    2. ln [ -s ] target link_name
    3. 软连接,原文件删除,软连接就没有意义
    4. 硬链接,两个文件内容一样,并且更改某一个,另一个也会随之变化;但是删除任何一个,另一个不受影响,可做备份文件。
  19. -rwxrwxr-x 1 linux linux 7158 8月 26 2014 test01

    文件类型,- 是普通文件;文件访问权限,rwx rwx r-x;链接数;文件所有者;文件所有组;文件大小,以字符为单位;上次修改文件或目录的时间;文件名。

  20. touch 命令用于创建一个新文件。

    touch filename:其中filename是文件名。如果这个文件是已有文件,就改变这个文件的最后修改日期;如果文件不存在,就创建新的空文件。

  21. echo "Hello" >> file

    echo $PATH:输出系统环境变量;

  22. 归档文件是将一组文件或目录保存在一个文件中。

    压缩文件也是将一组文件或目录保存一个文件中,并按照某种存储格式保存在磁盘上,所占磁盘空间比其中所有文件总和要少。

    tar [ -t | -x | -u | -c | -v | -f | -j | -z ] tar file filelist
    tar -cjvf day.tar.bz2 *.c:创建了一个bzip2的压缩归档文件。
    tar -czvf day.tar.gz *.c    创建了一个gzip的压缩归档文件。
    tar -xjvf  day.tar.bz2
    tar -xzvf  day.tar.gz
    
  23. ps -aux:列出所有进程信息 ;

    Kill -9 PID:根据进程号杀死指定进程;

  24. 用户管理:Linux用户分组管理,一个用户属于某个组,但是可以属于多个组,某个组可以包含多个用户;/etc/passwd用户登陆时,系统查询这个文件,确定用户的UID并验证用户口令、登陆名、经过加密的口令、UID、默认的GID、个人信息、主目录、登陆shell;

    /etc/group文件 包含了UNIX组的名称和每个组中成员列表。每一行代表一个组,包括4个字段:组名、加密的口令、GID号

    成员列表,彼此号隔开;

  25. adduser newuser:创建普通用户newuser,uid,gid都是从1000后开始的;

  26. deluser --remove-home user1 删除用户user1的同时删除用户的工作目录

  27. del group groupname

  28. su 命令用于临时改变用户身份,具有其他用户的权限。

  29. passwd root 修改密码。

    su - root 切换用户为 root。

  30. chmod : 改变文件或目录的访问权限。

    chown: 改变文件或目录的属主。

  31. - rwx rw- r-- 1 linux linux 40 7月 8 23:54 test.txt

    第一项是由10个字符组成的字符串,例如 “drwxr-xr-x”,说明了该文件/目录的文件类型和文件访问权限。

    第一个字符表示文件类型。

    从左起第2个字符到第10个字符表示文件访问权限。并且以3个字符为一组,分为3组。

    组中的每个位置对应一个指定的权限,其顺序为:读、写、执行。

    3组字符又分别代表文件所有者权限、文件从属组权限以及其他用户权限。

    rwx:代表文件所有者具有可读、可写、可执权限行

    rw-:代表文件所有者所在的组具有的权限:可读、可写,- 权限缺失。

    r–:除了文件所有者及所在组的其他用户具有的权限:可读,- 权限缺失,没有可写和可执行的权限。

    chmod u+x test.txt 给当前用户增加可执行权限
    chmod u-x test.txt 给当前用户去除可执行权限
    chmod a+x test.txt 给所有用户增加可执行权限
    chmod g+x test.txt 给同组的其他用户增加可执行权限
    chmod o+x test.txt 给其他用户(文件所有者及文件同组用户之外的其他用户)增加可执行权限
    
    权限 二进制 十进制
    r… 0100 4
    .w. 0010 2
    …x 0001 1

    chown username 文件:更改文件的所有者为 username;

三. 配置nfs、tftp和网络

  1. man

    man man

    1. Executable programs or shell commands

    2. System calls (functions provided by the kernel)系统调用

    3. Library calls (functions within program libraries)库函数

    4. Special files (usually found in /dev)

    5. File formats and conventions eg /etc/passwd

    6. Games

    7. Miscellaneous (including macro packages and conventions)

      e.g:man(7), groff(7)

    8. System administration commands (usually only for root)

    9. Kernel routines [Non standard]

    Write语句?

    Man语句中1、2、3很重要

  2. ifconfig:查看网络配置信息,eth0为网卡,lo为本地回环地址

  3. Linux世界中,无论是配置静态IP还是动态IP,计算机系统将IP信息保存放在 /etc/network/interfaces

    sudo vi /etc/network/interfaces // 配置网络
    auto eth0
    iface eth0 inet static
    address 192.168.1.209
    netmask 255.255.255.0
    gateway 192.168.1.1
    sudo vim /etc/resolv.conf   // 配置文件,设置 DNS 服务
    nameserver 192.168.1.1
    sudo /etc/init.d/networking restart  // 重启网络
    
  4. 临时指定ip地址:sudo ifconfig eth0 192.168.1.222。

  5. tftp 服务器,完成数据的上传下载。

    sudo apt-get install tftpd-hpa:安装成功之后,在 /etc/default/ 目录下会自动生成一个配置文件 tftpd-hpa, 如果安装不成功,此文件是不存在的,所以切记不要自己去写一个。

    配置文件:# /etc/default/tftpd-hpa
    TFTP_USERNAME="tftp"
    TFTP_DIRECTORY="/tftpboot"    //tftp服务器的工作目录
    TFTP_ADDRESS="0.0.0.0:69"
    TFTP_OPTIONS="-l -c --secure"
    // l:列出文件,c:创建文件
    

    因为配置文件中指明工作目录是 /tftpboot, 所以我们创建此目录,并且改权限为:sudo chmod 777 tftpboot/。重启 tftp 服务:sudo /etc/init.d/tftpd-hpa restart

    tftp ip地址 get&put命令无效?

    get file:下载文件,从服务器的工作目录/tftpboot中来下载。

    put file:上传文件,把当前目录下的file文件上传到tftp服务器的工作目录/tftpboot。

  6. nfs:网络文件系统,完成数据共享。

    sudo dpkg -s nfs-kernel-server 查看是否已经安装nfs,如果没有安装,可以使用以下命令安装:sudo apt-get install nfs-kernel-server,nfs 服务的配置文件:在/etc下 vi exports,添加配置文件 /source/rootfs *(rw,sync,no_subtree_check,no_root_squash)。/source/rootfs 网络文件系统共享目录,需在根目录下新建。

    *:和当前主机在同一网段的所有主机,这些主机都可以访问此网络文件系统; rw:权限;sync :同步;no_subtree_check:不做目录树检查;no_root_squash:登录用户具有root权限;

    重启服务:sudo /etc/init.d/nfs-kernel-server restart

    挂载网络文件系统:sudo mount -t nfs 192.168.1.222:/source/rootfs ./test

    卸载:sudo umount /home/linux/test/

  7. Shell脚本语言是解释型语言。Shell脚本的本质:Shell命令的有序集合。

    程序基本过程分为三步:

    1. 编辑shell 文件:包含任意多行操作系统命令或shell命令的文本文件;一般我们是以".sh"作为shell文件的后缀名。

    2. 赋予shell文件执行权限:用chmod命令修改权限。

    3. 执行shell文件:直接在命令行上调用shell程序;不管test.sh是否具有可执行权限,我们是可以通过"bash test.sh"来指明使用bash来解析执行test.sh文件的。

  8. Shell允许用户建立变量存储数据,但不支持数据类型(整型、字符、浮点型),将任何赋给变量的值都解释为一串字符;shell中的变量不需要声明,直接可以使用。

  9. 变量直接可以使用,count=1 注意:"="前后没有空格。

    变量的调用:在变量前加$。

    使用unset命令删除变量的赋值。

  10. $0 与键入的命令行一样,包含脚本文件名,脚本文件名 + 路径(相对路径/绝对路径)

    ./test.sh 这时$0就是指 ./test.sh

    /home/linux/test.sh 这时$0就是指 /home/linux/test.sh

    $1,$2,……$9 分别包含第一个到第九个命令行参数。

    $# 包含命令行参数的个数

    $@ 包含所有命令行参数:“$1,$2,……$9”

    $? 包含前一个命令的退出状态,上一条命令执行成功,返回 0 ; 不成功,返回非 0

    $* 包含所有命令行参数:“$1,$2,……$9”

    $$ 包含正在执行进程的ID号

  11. PATH :shell搜索路径

  12. 说明性语句:以#号开始到该行结束,不被解释执行

    #! /bin/bash:告诉操作系统使用何种类型的shell来解析当前的shell脚本

  13. 功能性语句: 任意的shell命令、用户程序或其它shell程序。

  14. read

    read从标准输入读入一行, 并赋值给后面的变量,其语法为:read var(后不需分号)。

    read var1 var2 var3:把读入行中的第一个单词(word)赋给var1, 第二个单词赋给var2,…把其余所有的 单词赋给最后一个变量

  15. 算术运算命令expr主要用于进行简单的整数运算,包括加(+)、减(-)、乘(*)、整除(/)和求模(%)(即求余)等操作。反撇号()将expr运算括起来,实际是引用命令的运行结果,最终去做其他操作

  16. test语句可测试三种对象:字符串 整数 文件属性

    -eq; -gt; -ge; -lt; -le;

    测试文件-n;

四. shell 脚本命令,正则表达式

  1. type:查看系统内置变量

  2. declare -i s=100+100:定义数据类型(-a:数组;-i:整型;-x:参数变为环境变量;-r:readonly)

  3. var[index]=content

    var[0]="s"
    var[1]="k"
    var[2]="l"
    echo ${var[0]}, ${var[1]}, ${var[2]}
    
  4. ulimit:用于控制shell程序的资源。

    ulimit -f 10240

  5. alias,unalias:命令别名设置

  6. source:读入环境配置文件

  7. find /home -name .bashrc > list_right 2> list_error

  8. echo "error message" 1>2:创建2并保存error message;

    echo "error message" 1>&2:终端打印;

    echo "error message" 2> /dev/null 1>&2(错误信息丢进垃圾箱);

    2>&1 的意思就是将标准错误重定向到标准输出

  9. cat > file 、cat > file < file1、cat > file << “eof”

  10. \> /dev/null:丢进垃圾箱

  11. cut 截取内容(echo ${PATH}|cut -d ':' -f 1;cat catfile |cut -c 2-

  12. last:显示登陆者信息。

  13. grep:-v 反向选择,-a 将二进制文件以文本文件的方式查找数据;-c 计算查找到字符次数;-i 忽略大小写;-n 输出行号(grep -in 'the' file.txt:查找文件内容)

  14. 分类 sort:-f 忽略大小写;-b 忽略前面的空格;-M 以月份名字来排序;-n 使用纯数字排序;-r 反向排序;-u 相同的数据中仅出现一次(同uniq);-t 分隔符;-k 排序的区间

  15. uniq:-i 忽略大小写;-c 进行计数(重复文件数目)

  16. 统计 wc:-l 仅列出行;-w 列出多少个字;-m 多少字符(默认算\n)

  17. 双定向 tee:-a 追加

  18. 删除替换 trtr -d SET1 删除信息中SET1字符(cat catfile |tr -d ':');-s 替换重复字符(cat catfile |tr [a-z] [A-Z]);tr -d '^M'==tr [^M] [\r]==dos2unix

  19. tab 转换空格 col:-x 将 tab 转换为对等空格(cat man_db.conf |col -x |cat -A |more

  20. cat -A:tab 以 ^l 显示

  21. 类粘贴 join:-i 忽略大小写;-t(join -t 'a' file1 file2:以a为分隔符对比file1和file2,相同则file2按行拼接在file1后)(用前需进行排序)

  22. 粘贴 paste:-d 将两个文件按行粘贴在一起,以 tab 分隔;-file 部分用 - 代替,则该部分内容来自标准输入

  23. tab 转换空格 expendexpend -t n 将tab转换为空格(可自定义空格位数,默认8位)

  24. unexpend:与expend相反

  25. 文件分割 split:-b 按文件大小分割文件(split -b 1k spit.txt spit),-l 以行数分割文件(ls -la /|split -l 10 - lsroot

  26. xargsxargs [-0epn] command;-0 转换特殊字符为一般字符;-e EOF;-p 询问使用者意思;-n 次数

  27. -:使用前一命令的 stdout

  28. dmesg:打印内核产生的信息,包括硬件检测流程

  29. shell脚本的编写习惯:(bash file.sh、./file.sh、source file.sh)

    1. 脚本功能
    2. 版本信息
    3. 作者和联系方式
    4. 版本声明
    5. 历史记录
    6. 脚本内较特殊的命令
    7. 脚本运行时的环境变量预先声明和设置

    shift n:偏移n个参数

  30. test 语句可测试三种对象:(常与判断符号[]一起使用)

    字符串 整数 文件 属性

    命令 说明
    -d name 测试name 是否为一个目录
    -e name name 测试一个文件是否存在
    -f name 测试name 是否为普通文件
    -L name 测试name 是否为符号链接
    -r name 测试name 文件是否存在且为可读
    -w name 测试name 文件是否存在且为可写
    -x name 测试name 文件是否存在且为可执行
    -s name 测试name 文件是否存在且其长度不为0
    f1 -nt f2 测试文件f1 是否比文件f2 更新
    f1 -ot f2 测试文件f1 是否比文件f2 更旧
  31. if 判断

    if 表达式
    then    命令表
    fi
    

    如果表达式为真, 则执行命令表中的命令; 否则退出 if 语句, 即执行 fi 后面的语句。

    逻辑或

    if [ $score -lt 0 ] || [ $score -gt 100 ]
    thenecho "输入的分数非法!"
    fi
    

    逻辑或

    if [ $score -lt 0 -o $score -gt 100 ]
    thenecho "输入的分数非法!"
    fi
    

    逻辑与

    if [ $score -ge 0 -a $score -le 100 ]
    thenecho "输入的分数合法!"
    fi
    

    逻辑与

    if [ $score -ge 0 ] && [ $score -le 100 ]
    thenecho "输入的分数合法!"
    fi
    
  32. 多路分支语句 case 用于多重条件测试, 语法结构清晰自然.

    其语法为:

    case  字符串变量  in模式1)命令表1;;模式2 | 模式3)命令表2;;……模式n)命令表n;;
    esac
    
  33. for 循环

    for  变量名  in  单词表
    do命令表
    done
    变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环体中的命令. 循环次数由单词表中的单词数确定.
    
  34. while 语法结构

    while   命令或表达式
    do命令表
    done
    
  35. 在shell程序中, 常常把完成固定功能、且多次使用的一组命令(语句)封装在一个函数里,每当要使用该功能时只需调用该函数名即可。

    函数在调用前必须先定义,即在顺序上函数说明必须放在调用程序的前面。

    调用程序可传递参数给函数,函数可用return语句把运行结果返回给调用程序。

  36. 变量前面不加local,这个变量就是全局变量,不管是在什么位置;

    变量前加local,这个就是局部变量,只在相应作用域有效。

  37. gdb

    在gcc编译选项中一定要加入‘-g’。

    只有在代码处于“运行”或“暂停”状态时才能查看变量值。

    设置断点后程序在指定行之前停止

  38. shell脚本的调试:sh [-nvx] file.sh;-n 检查语法;-x 输出脚本内容再执行;-v 是用到的脚本输出到终端;

  39. 正则表达式

    1. grep [-A] [-B] [--color=auto] '字符查找' filenamecat spit.txt |grep -n -A3 -B2 --color=auto 'f' file.txt
    2. grep -n 'the' file.txt:查找file.txt文件中存在the的行;
    3. grep -vn 'the' file.txt:反选,查找file.txt文件中不存在the的行
    4. grep -in 't[ae]st' file.txt:[]控制该位置内容
    5. grep -n '[^[:lower:]]oo' vbird.txt == grep -n '[^a-z]oo' vbird.txt
    6. grep -n '^the' vbird.txt:^制表符(行首)
    7. grep -n '\.$' vbird.txt:行尾
    8. grep -n '^$' vbird.txt:输出空行
    9. grep -n 'g..d' vbird.txt:'.'代表一位字符
    10. grep -n 'go*g' vbird.txt:'*'重复前一个字符0到无数次(重复0次即为空)
    11. grep -n 'o\{3,5\}' vbird.txt:限定搜索范围
  40. 增删改查 sed

    1. -n安静模式;-e直接在命令行模式进行sed操作;-f操作结果写入文件;-r使用扩展型正则表达式语法;-i直接修改读取的文件内容;
    2. [n1,[,n2]] function:a新增;c替换;d删除;i插入;p打印;s替换;
  41. 扩展正则表达式

    1. egrep -v '^$|^#' filename
    2. RE字符:+重复一个或一个以上;?重复一个或0个;|或;()找出群组字符集;()+多个重复群组的判别;
    3. 数据处理工具awk:$1,$2,$3;
    4. 比较diff、cmp;
    5. patch:-pN目录层数;-R还原;diff -Naur passwd passwd.new >passwd.patch;
    6. 文件打印设置:pr filename;

五. 指针的代码案例

  1. 指针大小:sizeof(指针)计算指针p的类型大小,64位系统大小为8,32位系统中大小4,在32位系统上,不管指针p指向的是整型数据,还是字符型数据,short型数据,long型数据等,指针p本身所占的内存字节数均为4。

    #include <stdio.h>
    int main(){// 变量 a 的地址就是 int *,4个字节int a = 10;char b = 10;// int * 是一个类型int *p = &a;  // p 指向的是数字 a 的首地址char *q = (char *)p; // q 指向强转为 char 类型指针 p 的地址// int 数据类型说明指针变量指向的那片空间是 int,占有 4 个字节p + 1;  // 指针 p 地址加 1,向后移动 sizeof(p的数据类型) 个字符单位printf("%p\n", p);  // 输出指针 p 的地址printf("%p\n", (char *)p+1);    // 强转为 char 类型指针,地址运算:+ n * sizeof(强转的数据类型)printf("%p\n", q);printf("%p\n", q+1);printf("%d\n", sizeof(p));   // 指针的长度为 4printf("%d\n", sizeof(q));return 0;
    }
    
    [root@localhost ~]# gcc tt.c
    [root@localhost ~]# ./a.out
    0x7ffc0de01764
    0x7ffc0de01765
    0x7ffc0de01764
    0x7ffc0de01765
    8
    8
    
  2. 主机大小端(即字节序)

    大端:低地址存高字节;

    小端:高地址存高字节(左边是高位,右边是低位))

    Ubuntu 一般为小端操作,即低地址存低字节

    #include <stdio.h>
    int main(){unsigned int a = 0x12345678;int *p = &a;char *q = (char *)p;  // 同级指针进行操作printf("%#x\n", *q);   // %#x 表示十六进制输出,%#o 表示八进制输出printf("%#x\n", *(q+1));printf("%#x\n", *(q+2));printf("%#x\n", *(q+3));return 0;
    }
    
    [root@localhost ~]# ./a.out
    0x78
    0x56
    0x34
    0x12
    # 十六进制数的一位相当于二进制的4位;打印一个字节就得取十六进制数的两位
    # ------>小端存储
    # 一个 char *为 8bit ,一个 int 为 4bit ,两个 int 存满一个 char *,所以 12 34 56 78 两两分别存储
    
  3. 指针移动、数组首地址、数组指针的使用

    #include <stdio.h>
    int main(){int a[6] = {3,2,5,6,1,9};// int *p = &a[0];    // 定义了一个 int *型指针 p 指向数组首地址 a[0] (a 也可表示首地址)int *p = a;    // 一维数组名代表的就是数组首元素的地址// C99 语法,编译时加上 std=c99// 注意:i 作用域只限于 for 循环for(int i = 0; i < 6; i++){// printf("a[%d] = %d\n", i, *(a+i));  // *(a+i) 表示指针 a(首地址) 向后移动 i 个单位后取内容// p++ 是可以的,因为 p 是指针变量// a++ 是错误的,因为 a 是地址变量printf("a[%d] = %d\n", i, *p++);    // *p++ 表示指针,p 取内容后,向后移动一个单位}// printf("i = %d\n", i);int (*qq)[6] = &a;    // (*qq)[6] 表示指针数组(指向数组的指针,[6]表示该数组的列数)printf("%p\n", a);printf("%p\n", a+1);   // 首地址:a++ 不可以,a+1 可以printf("%p\n", &a+1);  // & 相当于把列指针提升到行指针,&a+1 位移动一行printf("%p\n", qq+1);   // qq+1 表示数组指针向后移动一个单位return 0;
    }
    
    [root@localhost ~]# gcc tt.c
    [root@localhost ~]# ./a.out
    a[0] = 3
    a[1] = 2
    a[2] = 5
    a[3] = 6
    a[4] = 1
    a[5] = 9
    0x7ffd17bbdab0
    0x7ffd17bbdab4
    0x7ffd17bbdac8
    0x7ffd17bbdac8
    
  4. 指针的使用

    #include <stdio.h>
    int main(){// char str1[] = {'H','e','l','l','o'};char str1[6] = "Hello"; // 字符串赋值给字符数组,最后实际操作的是字符数组里的内容,即 str[6] 为变量char *s = "Hello";  // 字符指针 s 中保存的是字符串常量的首地址,为常量不可变,字符指针里面并没有保存字符串的内容,它只是保存了首地址// str1[2] = 'W';    // str1[2] 为变量可以赋值成功// s[2] = 'w';   // 通过字符指针来间接更改了字符串常量的内容,这是非法的,常量不可修改int i = 0;for(; i < 5; i++){// putchar(*(str1+i));putchar(*(s+i));putchar(10);}// printf("%s\n", str1);printf("%s\n", s); // 输出字符串printf("%p\n", "Hello");    // 输出 Hello 的首地址printf("%p\n", "Hello"+1); // Hello 的首地址加一个字节printf("%p\n", s+1);   // 字符指针 s 增加一个字节printf("%c\n", *(s+1));  // 字符指针 s 增加一个字节再取内容printf("%c\n", *("Hello"+1));  // Hello 首地址加 1 取内容printf("%c\n", *("Hello")+1);   // Hello 首地址取内容后加 1return 0;
    }
    
    [root@localhost ~]# ./a.out
    H
    e
    l
    l
    o
    Hello
    0x402004
    0x402005
    0x402005
    e
    e
    I
    
  5. 示例1:

    #include <stdio.h>
    int main(){char *s[] = {"Hello","World","abcd"}; // 字符指针数组// s[0] 是一个字符指针数组,保存的是字符串 Hello 的首地址;// s[1] 保存的是 World 的首地址// s[3] 保存的是 abcd 的首地址// char *s = "Hello";printf("%c\n", *(s[0]+1));  // 输出 World 的首地址内容int i = 0;char **p = s; // 二级指针 **p 指向字符指针数组 s 的地址for(i = 0; i < 3; i++){// printf("%s\n", *(s+i));    // 加 i 实际是移动 i 个字符串后输出字符串// printf("%s\n", *(p+1));  // 加 i 实际是移动 i 个字符串后输出字符串// printf("%s\n", *p++);printf("%c\n", *(*(p++))); // *(p++) 为 p 指向的字符指针数组首地址 s 的首地址(即取 s 的首个字符串的首地址),*(*(p++)) 为再 s 取地址内的内容后,指针向后移动指向下一个字符串首地址}return 0;
    }
    
    [root@localhost ~]# ./a.out
    e
    H
    W
    a
    
  6. 示例2:

    #include <stdio.h>
    int main(){int a[2][3] = {1,2,3,7,8,9};int i, j;for(i = 0; i < 2; i++){for(j = 0; j < 3; j++){printf("a[%d][%d] = %d\n", i, j, a[i][j]);}}printf("======================================\n");for(i = 0; i < 2; i++){for(j = 0; j < 3; j++){printf("a[%d][%d] = %d\n", i, j, *(a[0]+i*3+j));    // //a[0] & a[0][0] 都表示二维数组首元素的地址}}printf("======================================\n");for(i = 0; i < 2; i++){for(j = 0; j < 3; j++){printf("a[%d][%d] = %d\n", i, j, *(*a+i*3+j));}}printf("======================================\n");for(i = 0; i < 2; i++){for(j = 0; j < 3; j++){printf("a[%d][%d] = %d\n", i, j, *(*(a+i)+j));}}printf("======================================\n");for(i = 0; i < 6; i++){printf("a[%d] = %d\n", i, *(&a[0][0])+i);    // 可定义 *p = &a[0][0],把 &a[0][0] 换成 *p}printf("======================================\n");for(i = 0; i < 6; i++){printf("a[%d] = %d\n", i, *(a[0]+i)); // 可定义 *pp = a[0],把 *a[0] 换成 *pp}printf("======================================\n");for(i = 0; i < 6; i++){printf("a[%d] = %d\n", i, *((*a)+i));}printf("**************************************\n");// 也可以用指针的方式存int (*q)[3]=a;for(i = 0; i < 2; i++){for(j = 0; j < 3; j++){printf("a[%d][%d] = %d\n",i,j,*(*(q+i)+j));}}return 0;
    }
    
    [root@localhost ~]# ./a.out
    a[0][0] = 1
    a[0][1] = 2
    a[0][2] = 3
    a[1][0] = 7
    a[1][1] = 8
    a[1][2] = 9
    ======================================
    a[0][0] = 1
    a[0][1] = 2
    a[0][2] = 3
    a[1][0] = 7
    a[1][1] = 8
    a[1][2] = 9
    ======================================
    a[0][0] = 1
    a[0][1] = 2
    a[0][2] = 3
    a[1][0] = 7
    a[1][1] = 8
    a[1][2] = 9
    ======================================
    a[0][0] = 1
    a[0][1] = 2
    a[0][2] = 3
    a[1][0] = 7
    a[1][1] = 8
    a[1][2] = 9
    ======================================
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 4
    a[4] = 5
    a[5] = 6
    ======================================
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 7
    a[4] = 8
    a[5] = 9
    ======================================
    a[0] = 1
    a[1] = 2
    a[2] = 3
    a[3] = 7
    a[4] = 8
    a[5] = 9
    **************************************
    a[0][0] = 1
    a[0][1] = 2
    a[0][2] = 3
    a[1][0] = 7
    a[1][1] = 8
    a[1][2] = 9
    
  7. 示例3:

    #include <stdio.h>
    int main(){int a = 10;int *p = &a;int **pp = &p;// int ***pp = &pp;printf("%p\t%p\n", p, &a);printf("%d\t%d\n", *p, *(&a));printf("%p\t%p\n", pp, &p);printf("%p\t%p\n", *pp, *(&p));printf("%d\t%d\n", **pp, **(&p));// printf("%p\t%p\n", ppp, &pp);/*int a[] = {3,4};int *s = a;*/char *str[] = {"Hello","World"};    // 字符数组每个元素的类型都是 char *char **q = str;/*printf("%s\n", *q);printf("%p\n", *q);printf("%c\n", **q);*/int i = 0;for(i = 0; i < 2; i++){// puts(*q++); // q++ 是移动一个字符串putchar(*(*q++));    // *q 得到字符数组的第一个元素,只不过这个元素是字符指针类型// puts(*q++)putchar(10);}return 0;
    }
    
    [root@localhost ~]# ./a.out
    0x7ffda491d4a4  0x7ffda491d4a4
    10  10
    0x7ffda491d498  0x7ffda491d498
    0x7ffda491d4a4  0x7ffda491d4a4
    10  10
    H
    W
    
  8. 示例4:

    #include <stdio.h>
    int fun();  // 函数声明
    int add(int, int);
    void swap(int *, int *);int fun(){  // 函数名实际是函数的入口函数// int a = 90;// printf("123456\n");// printf("1234\n");return 2+3;
    }int add(int a, int b){return a+b;
    }void swap(int *a, int *b){/*int tmp = a;a = b;b = tmp;*/int tmp = *a;*a = *b;*b = tmp;
    }int main(){/*int num = 0;num = fun();add(2, 3);printf("%d\n", num);printf("%p\n", fun);*/int a = 2, b = 3;swap(&a, &b);printf("a = %d\tb = %d\n", a, b);return 0;
    }
    
    [root@localhost ~]# ./a.out
    a = 3  b = 2
    
  9. 示例5:

    #include <stdio.h>
    void fun(int *, int);   // 找到二维数组的最大值int findMax(int (*p)[3], int n, int m){int i, j;int max = p[0][0];for(i = 0; i < n; i++){for(j = 0; j < m; j++){if(max < *(*(p+i)+j)){max = *(*(p+i)+j);}}}return max;
    }void show(int (*p)[3], int n){ // 打印二维数组int i = 0;for(; i < n; i++){printf("%d\n", *((*p)+i));}
    }void fun(int *q, int n){int i;for(i = 0; i < n; i++){printf("%d\n", *q++);}
    }int main(int argc, const char *argv[]){int a[] = {4,5,2,1};int b[2][3] = {1,5,3,4,2,7};printf("%d\n", findMax(b, 2, 3));show(b, 6);// fun(a, sizeof(a)/sizeof(b));return 0;
    }
    
    [root@localhost ~]# ./a.out
    7
    1
    5
    3
    4
    2
    7
    

六. 结构体 & Makefile

  1. 函数指针变量说明的一般形式如下: <数据类型> (*<函数指针名称>)(<参数说明列表>);

  2. 函数指针数组是一个包含若干个函数指针变量的数组。

    定义形式如下:

    <数据类型> ( * <函数指针数组名称> [<大小>] ) ( <参数说明列表> );

  3. #define MAX(a,b) ((a)>(b)?(a):(b)) ,这就是一个简单的函数宏,我们同样可以传递参数,实现功能。

  4. 在实际的处理对象中,有许多信息是由多个不同类型的数据组合在一起进行描述,而且这些不同类型的数据是互相联系组成了一个有机的整体。此时,就要用到一种新的构造类型数据——结构体(structure),简称结构。 结构体是用户自定义的新数据类型,在结构体中可以包含若干个不同数据类型和不同意义的数据项(当然也可以相同),从而使这些数据项组合起来反映某一个信息。

  5. 定义一个结构体类型的一般形式为:

    struct 结构体名
    {数据类型   成员名1;数据类型   成员名2;........................数据类型   成员名n;
    };
    

    注意:

    1. 在大括号中的内容也称为“成员列表”或“域表”;
    2. 其中,每个成员名的命名规则与变量名相同;
    3. 数据类型可以是基本变量类型和数组类型,或者是一个结构体类型;
    4. 用分号“;”作为结束符;
    5. 整个结构的定义也用分号作为结束符;
  6. 构造出的结构体类型,它属于C语言的一种数据类型,与整型、实型相当。因此,定义它时不分配空间,只有用它定义变量时才分配空间。

  7. 结构体类型变量的定义方法

    先定义结构体类型再定义变量名,这是C语言中定义结构体类型变量最常见的方式

    struct 结构体名
    {成员列表;
    };
    

    "struct 结构体名"才是一个完整的结构体类型,所以在定义变量时,一定写全,不可省略任何一个。

    struct 结构体名 变量名;

  8. 结构体变量的初始化

    与其他类型变量一样,也可以给结构体的每个成员赋初值,这称为结构体的初始化

    1. 一种是在定义结构体变量时进行初始化;

      语法格式如下:struct 结构体名 变量名={初始数据表};

    2. 另一种是在定义结构体类型时进行结构体变量的初始化。

      struct 结构体名
      {成员列表;
      }变量名={初始数据表};
      
  9. 具有相同结构体类型的结构体变量也可以组成数组,称它们为结构体数组;

  10. 结构体指针

    1. 可以设定一个指针变量用来指向一个结构体变量。

    2. 此时该指针变量的值是结构体变量的起始地址,该指针称为结构体指针。

    3. 结构体指针与前面介绍的各种指针变量在特性和方法上是相同的。

    4. 与前述相同,在程序中结构体指针也是通过访问目标运算*访问它的对象。

    5. 结构体指针在程序中的一般定义形式为:struct 结构体名 *结构指针名;

    6. 其中的结构体名必须是已经定义过的结构体类型。

  11. 在C语言中,不同数据类型的数据可以使用共同的存储区域,这种数据构造类型称为共用体,又称联合体。共用体在定义、说明和使用形式上与结构体相似。

  12. malloc / free

    void * malloc(size_t num)

    void free(void *p)

    malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。

    malloc申请到的是一块连续的内存,有时可能会比所申请的空间大。其有时会申请不到内存,返回NULL。

    malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。

    如果free的参数是NULL的话,没有任何效果。

    释放一块内存中的一部分是不被允许的。

  13. 在 C 语言中,允许使用关键字typedef定义新的数据类型,其语法如下:typedef <已有数据类型> <新数据类型>;

  14. Make 工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件 、时间戳 ,自动发现更新过的文件而减少编译的工作量,同时,它通过读入 Makefile 文件文件的内容来执行大量的编译工作。

  15. Makefile是Make读入的唯一配置文件。

    由make工具创建的目标体(target),通常是目标文件或可执行文件 ;要创建的目标体所依赖的文件(dependency_file);创建每个目标体时需要运行的命令(command);

    注意:命令行前面必须是一个”TAB键”,否则编译错误为:*** missing separator. Stop。

  16. 自动变量

    $* 不包含扩展名的目标文件名称;

    $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件;

    $< 第一个依赖文件的名称;

    $? 所有时间戳比目标文件晚的的依赖文件,并以空格分开;

    $@ 目标文件的完整名称;

    $^ 所有不重复的目标依赖文件,以空格分开;

    $% 如果目标是归档成员,则该变量表示目标的归档成员名称;

嵌入式开发——Linux C学习相关推荐

  1. 嵌入式开发——Linux操作系统

    学习内容及目标:Linux介绍,使用Linux操作(命令),Linux开发工具(会用,够用即可) 1.安装Linux开发环境 vm虚拟机(通过软件的方法模拟pc) 为什么不选择双系统?(因为嵌入式开发 ...

  2. 嵌入式开发有必要学习python吗?

    嵌入式与Python之间在概念上存在着明显的差异,嵌入式是一个开发领域,而python是一种编程语言. 对于新手来说,如果有时间,python是应该去学的.一方面是因为python语言本身相对简单,即 ...

  3. 没必要参加嵌入式开发培训班 (学习嵌入式的资料)

    http://bbs.csdn.net/topics/390803818 ; 你想知道为什么的话,就请接着向下看.我相信你会收获很多的.一定要耐心看完哦,你会收获很多的,相信我!尤其是最后面我提供的资 ...

  4. 嵌入式开发linux工具,嵌入式Linux开发入门之MfgTool工具的使用

    介绍嵌入式linux开发的环境搭建: 一.PC端环境搭建 2.Ubuntu装好后,在终端安装minicom工具,安装命令:sudo apt-get install minicom 注:该工具在后面烧录 ...

  5. 【嵌入式开发】gcc 学习笔记(一) - 编译C程序 及 编译过程

    一. C程序编译过程 编译过程简介 : C语言的源文件 编译成 可执行文件需要四个步骤, 预处理 (Preprocessing) 扩展宏, 编译 (compilation) 得到汇编语言, 汇编 (a ...

  6. 基于c语言的linux嵌入式开发入门

    前言 本文主要包含,c语言基本结构与语法.make及makefile的使用.main函数参数与返回值的说明.标准输入.输出.错误流的介绍以及linux管道的应用. 语言数据类型 联合体也有翻译为共用体 ...

  7. 循序渐进学习嵌入式开发技术

     嵌入式时代已经来临,你还在等什么?   ---循序渐进学习嵌入式开发技术最近经常有用人单位给我打来电话,问我这有没有嵌入式Linux方面的开发人员,他们说他们单位急需要懂得在嵌入式linux环境下的 ...

  8. 嵌入式开发需要学习哪些东西

    刚刚读到这篇文章,对于刚入门嵌入式来说挺有用的,献给向我一样正在迷茫,苦于没有头绪,没人指引的学习朋友们. 主要讨论下嵌入式技术学习方法,主要是针对嵌入式软件. 嵌入式技术是一门边缘科学(又称交叉科学 ...

  9. 嵌入式入门学习笔记6:[转]嵌入式开发需要学习哪些东西

    本文转自迅为开发板iTOP-4412开发板实战手册:http://www.topeetboard.com 刚刚读到这篇文章,对于刚入门嵌入式来说挺有用的,献给向我一样正在迷茫,苦于没有头绪,没人指引的 ...

最新文章

  1. 【HashMap 嵌套 ArrayList】
  2. Android数据库高手秘籍
  3. 目标检测第2步:如何在Windows 10下安装Anaconda?
  4. Android 系统(22)--Android P 行为变更
  5. POST 一张 图像的调试来认识 http post
  6. xv6 Traps, interrupts, and drivers
  7. Navicat for MySQL 视图创建使用方法以及如何查看数据表创建语句
  8. 老年手机英文改中文_老年手机设置成英文怎么办
  9. 如何找到能商用的背景纯音乐
  10. css 设置行内元素顶部对齐
  11. 如何对CAD图纸上的图形进行单独保存起来
  12. python import illegal instruction
  13. 电脑提示ISDone.dll错误怎么办?
  14. 使用深度学习Web项目的手写Marathi印地语字母书写和检测
  15. listen的backlog值分析
  16. 跨境电商的三大平台Amazon、eBay、速卖通,你怎么选择?
  17. mvc中简单从controll传递数据到前台页面(视图)
  18. 链表、二叉树、图的建立与初始化C源代码
  19. 曾经沧海难为水,除却巫山不是云~ 的意思是为思念亡妻
  20. 新160个CrackMe分析-第2组:11-20(上)

热门文章

  1. R语言ggplot2-颜色设置调参详解
  2. Crackme 29
  3. Eclipse不支持tomcat9解决方法
  4. python视频识别_视频人员行为识别(Action Recognition)
  5. try里面return,finally还会执行吗?
  6. 打印机打印无反应,显示打印机已暂停
  7. 工业相机取图到传输时间计算
  8. 在Fritzing中创建自定义元件
  9. try java 的用法,java中try的用法
  10. 信雅纳|2.4TbE网络压测平台,基于400G PAM4的7速网络测试解决方案