
一、指令部分具体指令及其用法二、Linux路径下内容目录名称功能描述/bin存放基本二进制可执行文件如常用命令 ls、cp 等所有用户均可执行/etc存储系统级配置文件如网络配置、用户信息/etc/passwd、服务启动脚本等/dev包含硬件设备文件如 /dev/sda 表示硬盘/dev/tty 表示终端用于硬件交互/home普通用户的主目录每个用户有独立子目录如 /home/ 用户名存放个人文件和配置/lib保存系统运行必需的共享库文件如 C 标准库 libc.so及内核模块支撑程序运行/usr存储用户程序和数据如应用程序、开发工具、库文件、文档等类似集中的 “程序资源库”/root超级用户root的主目录存放其专属文件、配置及管理工具/tmp临时文件存储目录用于存放系统和应用运行时产生的临时数据系统重启时内容通常会被清空/mnt临时挂载点目录用于手动挂载外部存储设备如 U 盘、光盘或其他文件系统/opt第三方软件或附加应用程序的存放目录便于集中管理如 /opt/ 软件名称三、硬软连接区别1. 硬链接创建方式ln 原文件 硬链接名默认不带 -s特点 所有硬链接地位平等没有 “主文件 / 副本” 之分删除任意一个都不影响其他链接。 只有当所有硬链接都被删除且没有进程打开文件时文件数据才会被系统回收。 无法跨文件系统创建也不能链接目录普通用户。2. 软连接创建方式ln -s 原文件/目录 软连接名必须带 -s 参数特点 是独立的文件存储的是目标的路径信息删除软连接不会影响原文件。原文件被移动、重命名或删除后软连接会失效变成红色的 “死链接”。支持跨分区、跨文件系统也可以链接目录使用更灵活。一句话总结硬链接文件的 “别名”共享数据块防误删不能跨分区 / 链接目录。软连接文件的 “快捷方式”记录路径可跨分区 / 链接目录原文件删除后失效。四、环境变量的配置1.临时配置仅当前终端有效如果你只是临时想测试一下某个路径或者不想修改系统文件可以使用 export 命令。命令格式export 变量名变量值示例添加 PATHexport PATH$PATH:/opt/my_new_tool/bin export 声明为全局环境变量子进程、终端都能生效 PATH 系统命令查找路径变量 赋值 $PATH $\ 引用变量 保留**原来所有的旧路径 **不覆盖 : Linux 路径分隔符用来隔开多个路径 /opt/my_new_tool/bin 你要新增的自定义命令路径 把 /opt/my_new_tool/bin 追加到 原有 PATH 后面 ✅ 不会删掉系统原本的命令路径 ✅ 以后可以直接执行这个目录里的程序不用 ./注意$PATH 表示保留原本的路径后面追加新的路径。如果直接写 PATH/xxx原本的系统命令如 ls, cd可能会找不到生效范围只在当前 Shell 会话中有效关闭终端或重启后失效。2.永久配置永久配置写入配置文件 要让环境变量永久生效需要将 export 命令写入到特定的配置文件中。根据作用范围不同分为用户级和系统级。用户级配置推荐 适用场景只针对当前登录的用户生效不影响其他用户。 常用文件~/.bashrc 或 ~/.profile最常用的是 ~/.bashrc。操作步骤(1)打开文件vim ~/.bashrc(2)在文件末尾添加export MY_VARhello export PATH$PATH:/your/custom/path(3)保存退出。(4)立即生效执行 source ~/.bashrc。3.系统级配置全局适用场景对所有用户都生效需要 root 权限。常用文件/etc/profile 或 /etc/environment。操作步骤1打开文件sudo vim /etc/profile2在文件末尾添加export JAVA_HOME/usr/local/java export PATH$PATH:$JAVA_HOME/bin3保存退出。(4)立即生效执行 source /etc/profile。4.环境变量的作用1、指定系统或软件配置2、告诉程序去找依赖3、传递敏感信息4、C语言编译参数5.常见的环境变量及用途变量名用途说明PATH最常用。指定命令的搜索路径。当你输入ls时系统会去 PATH 里的目录找这个可执行文件。HOME当前用户的主目录路径如/home/user。SHELL当前使用的 Shell 解释器如/bin/bash。LANG系统语言和字符集如en_US.UTF-8或zh_CN.UTF-8。LD_LIBRARY_PATH程序运行时查找动态链接库.so 文件的路径。PKG_CONFIG_PATH编译器查找.pc文件的路径用于定位库的头文件和库文件位置。验证配置是否成功配置完成后可以使用以下命令查看变量是否已生效查看特定变量echo $PATH echo $JAVA_HOME查看所有env五、makefile1.Makefile 是什么Makefile 是GNU Make 工具的配置文件用来自动化编译项目。核心解决什么问题项目文件多、依赖复杂手动敲 gcc 命令容易出错、效率低自动判断哪些文件被修改过只重新编译修改过的文件大幅提升编译效率一键执行编译、清理、安装等操作不用记复杂命令2.Makefile 最基础语法万能模板目标: 依赖文件列表 命令1 命令2⚠️ 关键细节命令前面必须是一个 Tab 键不能用空格核心概念目标target要生成的文件比如可执行文件、.o 文件也可以是伪目标比如 clean依赖prerequisites生成目标需要的文件 / 条件命令recipe依赖更新后执行的编译 / 操作命令# 最终目标生成可执行文件 calc # 依赖三个 .o 目标文件必须先生成这三个 calc: main.o add.o sub.o gcc main.o add.o sub.o -o calc # 把三个 .o 链接成可执行文件 calc # 目标生成 main.o # 依赖main.c add.h sub.h头文件变了也要重新编译 main.o: main.c add.h sub.h gcc -c main.c -o main.o # -c只编译不链接生成 main.o # 目标生成 add.o # 依赖add.c add.h add.o: add.c add.h gcc -c add.c -o add.o # -c只编译生成 add.o #当 add.c 或 add.h 发生变化时执行 gcc -c add.c -o add.o重新生成 add.o 目标文件 # 目标生成 sub.o # 依赖sub.c sub.h sub.o: sub.c sub.h gcc -c sub.c -o sub.o # -c只编译生成 sub.o # 伪目标清理编译产生的文件 clean: rm -rf *.o calc # 删除所有 .o 文件 可执行文件 calc3.Makefile 核心符号详解符号含义例子直接赋值会被后面的赋值覆盖CC gcc:立即赋值定义时就计算好不会被覆盖SRC : $(wildcard *.c)?条件赋值变量未定义时才赋值CC ? gcc追加赋值CFLAGS -O2$第一个依赖文件模式规则中代表 %.c$当前目标文件模式规则中代表 %.o$^所有依赖文件去重$(CC) $^ -o $$*不包含扩展名的目标文件名比如 main.o → main执行命令时不在终端打印命令本身echo 编译完成%通配符用于模式匹配%.o: %.c1. $第一个依赖文件# 模式规则所有 .o 文件都由对应的 .c 文件生成 %.o: %.c # $ 代表第一个依赖文件这里就是 %.c gcc -c $ -o $当处理 main.o 时$ 会自动替换成 main.c等价于gcc -c main.c -o main.o2. $当前目标文件# 最终目标生成 calc calc: main.o add.o sub.o # $ 代表当前目标文件这里就是 calc gcc main.o add.o sub.o -o $等价于gcc main.o add.o sub.o -o calc# 也可以用在模式规则里 %.o: %.c gcc -c $ -o $处理 main.o 时$ 就是 main.o3. $^所有依赖文件去重calc: main.o add.o sub.o # $^ 代表所有依赖文件main.o add.o sub.o自动去重 gcc $^ -o $等价于gcc main.o add.o sub.o -o calc如果依赖里有重复的文件$^ 会自动去掉重复项只保留一份4. $*不包含扩展名的目标文件名# 比如目标是 main.o$* 就是 main %.o: %.c gcc -c $ -o $ # $* 可以用来生成不带扩展名的中间文件 echo 编译了 $*.c生成了 $*.o运行 make main.o 时会输出编译了 main.c生成了 main.o5. 执行命令时不打印命令本身clean: # 不加 终端会打印 rm -rf *.o calc rm -rf *.o calc # 加 只打印“清理完成”不打印 echo 命令 echo 清理完成效果对比不加 终端会显示 echo 清理完成再显示文字加 终端只显示 清理完成不会显示 echo 命令本身6.%通配符用于模式匹配# 模式规则所有 .o 文件都由同名的 .c 文件生成 %.o: %.c gcc -c $ -o $这里的 %.o 和 %.c 是一对通配符当你执行 make main.o 时Make 会自动匹配 main.c并执行规则里的命令不用再一个个写 main.o: main.c、add.o: add.c 了7.完整示例# 编译器 CC gcc # 编译选项 CFLAGS -Wall -g # 目标文件列表 OBJS main.o add.o sub.o # 最终可执行文件 TARGET calc # 最终目标链接所有 .o 文件 $(TARGET): $(OBJS) # $^所有依赖文件$当前目标文件 $(CC) $^ -o $ # 不打印 echo 命令本身 echo 链接完成生成可执行文件$ # 模式规则自动编译所有 .c 文件为 .o 文件 %.o: %.c # $第一个依赖文件$当前目标文件 $(CC) $(CFLAGS) -c $ -o $ echo 编译完成$*.c → $*.o # 伪目标清理 .PHONY: clean clean: rm -rf $(OBJS) $(TARGET) echo 清理完成运行结果1.执行 make会自动编译 main.c add.c sub.c 为 .o 文件再链接生成 calc终端只会显示 编译完成main.c → main.o 这类信息不会打印 gcc 命令本身2.执行 make clean会删除所有 .o 文件和 calc并打印 清理完成4.伪目标.PHONY详解伪目标不是一个真实的文件只是一个操作命令的名字比如 clean、install。为什么要加 .PHONY如果当前目录下有一个叫 clean 的文件make clean 会认为目标文件已经存在且无需更新就不会执行 clean 里的命令。用 .PHONY: clean 声明后Make 就会把它当成伪目标不管有没有同名文件都会执行命令。5.Makefile 工作流程理解它的核心逻辑a.执行 make 时默认找第一个目标比如 calcb.检查 calc 的依赖文件main.o add.o sub.o是否存在、是否被修改过c.递归检查每个依赖的依赖比如 main.o 依赖 main.c add.hd.如果 .c 文件比 .o 文件新就重新编译生成 .oe.所有 .o 文件更新完成后执行链接命令生成最终目标6.极简背诵版核心格式目标: 依赖命令前必须是 Tab变量用 定义$(变量名) 引用模式规则 %.o: %.c配合 $ $ 简化代码伪目标用 .PHONY 声明避免和文件重名make 只编译修改过的文件提升效率六、GDB调试流程*编译生成带调试信息的可执行文件 gcc -g 源文件.c -o 可执行文件 例gcc -g main.c -o main 启动gdb调试程序 gdb 可执行文件名 例gdb main 常用调试操作 l 查看源码 b 行号 设置断点 r 运行程序 n 单步跳过 s 单步进入 p 变量名 打印变量 c 继续运行 q 退出gdbgcc -g开启调试r继续运行b打断点n单步跳过s单步进入bt查看程序栈p看变量的值gcc 是什么GNU C Compiler → C 语言编译器作用把 .c 源代码 → 变成 可执行文件gcc 文件名.c → 生成 a.out-o 名字 → 指定可执行文件名-c → 只编译生成 .o-g → 加调试信息给 gdb 用参数含义中文作用-c只编译不链接生成.o目标文件-o指定输出文件名不生成默认 a.out-g生成调试信息给gdb 调试用-Wall显示所有警告帮你找代码错误-I指定头文件路径找.h文件-L指定库文件路径找.so/.a库-l链接库链接系统库如-lpthread七、标准IO的缓存机制和刷新条件缓冲机制1. 全缓冲Full Buffering默认4096字节4KB规则只有当缓冲区被写满或调用fflush强制刷新时数据才会写入内核。适用场景文件流fopen打开的文件默认全缓冲。特点效率最高系统调用次数最少。2. 行缓冲Line Buffering默认1024字节1KB规则遇到换行符\n、缓冲区写满、调用fflush或程序正常退出时数据会被刷新。适用场景标准输入stdin、标准输出stdout终端设备默认行缓冲例子printf(hello);不会立即输出直到遇到\n或程序结束。3. 无缓冲Unbuffered默认0字节规则数据不经过用户缓冲区直接调用系统调用写入内核。适用场景标准错误stderr默认无缓冲错误信息会立即输出方便调试特点效率最低但实时性最强错误信息不会被缓冲延迟。缓存区刷新条件1.缓冲区写满2.调用 fflush(fp) 强制刷新3.程序正常结束4.调用 fclose(fp) 关闭文件5.终端流遇到换行符6.遇到换行符\n仅行缓冲中八、动静态库的区别对比项静态库.a动态库.so链接时机编译链接时程序运行时打包方式直接打包进可执行文件仅留引用不打包可执行文件大小大小运行依赖无必须依赖库文件更新方式需重新编译程序直接替换库文件制作命令ar cr libxxx.a x.ogcc -shared -fPIC -o libxxx.so x.o九、标准IO创建文件的权限用文件IO创建如何编写1.标准IOfopen)没有权限参数创建文件默认权限0666受 umask 修正。// w 模式不存在则创建存在则清空 FILE *fp fopen(test.txt, w);2.文件 IOopen必须在 O_CREAT 时指定 mode 参数实际权限 mode ~umaskopen(test.txt, O_RDWR | O_CREAT | O_TRUNC, 0664);#include stdio.h int main() { // 不存在就创建存在就清空 FILE *fp fopen(test.txt, w); if(NULL fp) { perror(fopen); return -1; } fclose(fp); return 0; }#include stdio.h #include unistd.h #include fcntl.h int main() { // 和 fopen w 完全等价 // O_WRONLY 只写 // O_CREAT 文件不存在则创建 // O_TRUNC 文件存在则清空 // 0666 创建默认权限 int fd open(test.txt, O_WRONLY|O_CREAT|O_TRUNC, 0666); if(-1 fd) { perror(open); return -1; } close(fd); return 0; }十、IO实现拷贝文件和标准IO1.文件IO实现拷贝#include stdio.h #include sys/types.h #include sys/stat.h #include fcntl.h #include unistd.h int main(int argc, const char *argv[]) { // 1.对输入参数的参数个数进行检查 argc if (argc ! 3) { printf(输入的参数个数有误\n); printf(usage: ./a.out src_file dest_file\n); return -1; } // 2.以只读的方式打开源文件 以只写的方式打开目标文件 open // argv[1] 源文件的路径 // argv[2] 目标文件的路径 int src_fd 0; //源文件的文件描述符 //O_RDONLY如果文件不存在则会进行报错,打开文件就会失败 if(-1 (src_fd open(argv[1],O_RDONLY))) { perror(打开源文件失败); return -1; } printf(打开源文件成功,src_fd%d\n,src_fd); int dest_fd 0; //目标文件的文件描述符 //O_WRONLY如果文件不存在则会进行报错.打开文件失败 //以只写的方式打开文件,如果文件不存在则创建新文件 //如果文件存在则将文件中原有的内容进行清空操作 if(-1 (dest_fd open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666))) { perror(打开目标文件失败); return -1; } printf(打开目标文件成功,dest_fd%d\n,dest_fd); // 3.循环读取和写入 read 和 write char buf[1024] {0}; ssize_t ret_read 0; //用来接收read函数的返回值 ssize_t ret_write 0; //用来接收write函数的返回值 while((ret_read read(src_fd,buf,sizeof(buf)))0) { //循环写入操作 ret_write write(dest_fd,buf,ret_read); if(ret_write -1) { perror(写入目标文件失败); return -1; } //检查写入的字节数与读取的字节数是否一致 if(ret_read ! ret_write) { printf(写入的字节数与读取的字节数不一致\n); return -1; } } // 4.关闭文件 close close(src_fd); close(dest_fd); return 0; }2.标准IO实现拷贝#include stdio.h #define BUF_SIZE 1024 // 缓冲区大小 int main(int argc, const char *argv[]) { // 参数校验./a.out 源文件 目标文件 if (argc ! 3) { printf(参数错误\n); printf(用法%s src_file dest_file\n, argv[0]); return 1; } FILE *fp_src fopen(argv[1], r); FILE *fp_dest fopen(argv[2], w); if (fp_src NULL || fp_dest NULL) { perror(文件打开失败); return 1; } char buf[BUF_SIZE] {0}; size_t ret; // 循环块读取 块写入 while ((ret fread(buf, 1, BUF_SIZE, fp_src)) 0) { // 只写入实际读到的字节数 fwrite(buf, 1, ret, fp_dest); } // 关闭流 fclose(fp_src); fclose(fp_dest); printf(文件拷贝完成\n); return 0; }十一、标准IO和文件IO的区别文件 IOLinux 系统调用无用户态缓冲区直接操作内核标准 IOC 标准库函数带用户态缓冲区效率更高跨平台对比项文件 IO系统调用标准 IOC 库函数所属层次系统调用内核提供C 标准库用户态封装头文件unistd.h fcntl.hstdio.h操作对象文件描述符int fd文件指针FILE* fp是否带缓冲区❌ 无用户态缓冲区✅ 带用户态缓冲区全缓冲 / 行缓冲 / 无缓冲效率低频繁陷入内核高减少系统调用次数移植性弱仅 Linux/Unix强Windows/Linux 通用常用函数open/read/write/lseek/closefopen/fread/fwrite/fseek/fclose适用场景设备文件、网络、驱动、底层操作普通文件读写、日志、跨平台程序十二、段错误一般由什么情况引起访问非法内存访问操作系统禁止读写的内存地址如内核空间、未分配内存。野指针、空指针操作指针未初始化、指针为 NULL直接解引用、赋值、读写。数组越界访问数组下标超出定义范围破坏栈内存。修改只读内存例如字符串常量不可修改char *pabc; p[0]1;栈溢出局部数组过大、递归层数过多耗尽栈空间。重复释放 / 多次 free同一块堆内存重复释放破坏内存管理结构。释放后继续使用内存free 销毁空间后继续操作该指针。总结空指针 / 野指针解引用、数组越界、修改常量字符串、栈溢出、非法访问内存、重复释放内存、释放后继续使用。缓冲区的区别最容易考文件 IO每次 read/write 都直接发起系统调用频繁读写会非常慢标准 IO数据先写到用户态缓冲区缓冲区满 / 刷新时才一次性调用系统写入内核大大减少系统调用次数对应关系功能文件 IO标准 IO打开文件open()fopen()读文件read()fread()/fscanf()/getchar()写文件write()fwrite()/fprintf()/putchar()定位文件lseek()fseek()关闭文件close()fclose()用 标准 IO写日志、配置文件、普通文本处理带缓存效率高用 文件 IO设备驱动、网络套接字、实时数据传输无缓存直接操作stdin、stdout、stderr1. 含义stdin 标准输入 键盘stdout 标准输出 终端屏幕stderr 标准错误 终端屏幕2. 文件描述符文件 IO0 → 标准输入 stdin1 → 标准输出 stdout2 → 标准错误 stderr3.标准IO对应FILE *stdin; FILE *stdout; FILE *stderr;4.例子// 往标准输出打印 fprintf(stdout,hello\n); // 往标准错误打印 fprintf(stderr,出错了\n);软硬链接什么时候用特性硬链接软链接符号链接本质多个文件名指向同一个 inode一个文件指向另一个文件的路径跨分区❌ 不能跨分区✅ 可以跨分区链接目录❌ 不能链接目录✅ 可以链接目录原文件删除链接依然有效inode 计数没到 0 就不会删链接失效变成 “断链”大小和原文件一样很小只存路径字符串1.硬链接什么时候用✅ 场景 1需要多个文件名指向同一个文件且不希望文件被误删比如你有一个重要配置文件想在多个地方都能访问又怕不小心删了其中一个导致文件丢失。用法ln /etc/nginx/nginx.conf /home/user/nginx.conf.link效果删 /home/user/nginx.conf.link原文件 /etc/nginx/nginx.conf 完全不受影响。场景 2做文件备份 / 防误删同分区内原理硬链接本质是同一个文件修改任何一个链接所有链接都会同步变化。比如重要日志文件建一个硬链接就算原文件被程序删除inode 计数没到 0进程还开着硬链接依然能看到完整数据。2.❌ 硬链接绝对不能用的情况跨不同磁盘 / 分区比如把 /home 下的文件链接到 /tmp 下链接目录系统默认不允许防止循环链接链接不存在的文件硬链接必须基于已存在的 inode3.软链接什么时候用日常开发 90% 的场景都用它✅ 场景 1简化路径快速访问深层目录 / 文件比如你经常要进 /opt/software/nginx-1.24.0/conf/每次输路径太麻烦。用法ln -s /opt/software/nginx-1.24.0/conf/ ~/nginx-conf效果直接 cd ~/nginx-conf 就能进去不用输长路径。✅ 场景 2软件版本切换比如 Python、JDK比如你同时装了 Python3.8 和 Python3.10想随时切换默认版本。用法ln -s /usr/bin/python3.10 /usr/bin/python想切回 3.8 时删掉旧链接重新建就行不用改环境变量。✅ 场景 3跨分区 / 跨磁盘链接文件比如你在系统盘装了程序数据存在数据盘用软链接把数据盘的目录链接到程序的默认路径下。硬链接做不到但软链接可以。✅ 场景 4给编译后的可执行文件创建快捷方式比如你自己编译了一个 myapp想直接在终端输入 myapp 就能运行不用写 ./myapp 或者绝对路径。用法ln -s /home/user/myapp/bin/myapp /usr/local/bin/myapp软链接的坑原文件 / 目录删除 / 移动后链接会失效比如你把原文件 nginx.conf 删了软链接就变成了无效的 “红名文件”打开会报错。怎么选同分区、想防误删、多入口访问同一份数据 → 用硬链接跨分区、简化路径、版本切换、快捷方式 → 用软链接绝大多数场景都用它