适合前端开发的电脑推荐,合肥正规的seo公司,深圳做网站服务商,深圳网络营销招聘1. c语言中const *p的用法
#xff08;1#xff09;const int *p; 或 int const *p; 指向常量整数的指针#xff0c;通过这个指针不能修改它所指向的整数值#xff0c;但可以修改指针本身来指向其他地址
const int a 10;
const int *p a;
// *p 20; // 错误1const int *p; 或 int const *p; 指向常量整数的指针通过这个指针不能修改它所指向的整数值但可以修改指针本身来指向其他地址
const int a 10;
const int *p a;
// *p 20; // 错误不能通过*p修改a的值
int b 20;
p b; // 合法可以修改指针p使其指向其他地址2int *const p; 常量指针指向一个整数。指针本身是常量不能修改但可以通过指针修改它所指向的整数值
int a 10;
int *const p a;
*p 20; // 合法可以通过p修改a的值
// p b; // 错误不能修改指针p本身3const int *const p; 表示一个指向常量整数的常量指针既不能修改指针所指向的地址也不能通过指针修改它所指向的整数值
const int a 10;
const int *const p a;
// *p 20; // 错误不能通过*p修改a的值
// p b; // 错误不能修改指针p本身2. TCP/IP的四层模型是什么
1应用层 应用层是TCP/IP协议栈的顶层它为应用程序提供网络服务接口。该层协议包括HTTP、FTP、SMTP、Telnet等负责与用户直接交互处理特定的应用程序任务
HTTPHyperText Transfer Protocol用于网页浏览。FTPFile Transfer Protocol用于文件传输。SMTPSimple Mail Transfer Protocol用于电子邮件传输。DNSDomain Name System用于域名解析。
2传输层 传输层负责在两个主机之间建立、维护和终止传输会话并保证数据包的可靠传输。该层主要包含TCP和UDP协议
TCPTransmission Control Protocol提供可靠的、有序的、面向连接的传输服务。它通过三次握手建立连接确保数据包按序到达并通过确认机制保证数据的正确传输。UDPUser Datagram Protocol提供无连接、不可靠的传输服务适用于对速度要求高但对可靠性要求低的场景如实时视频传输。
3网络层 网络层负责将数据包从源传输到目的地主要通过IP协议来实现。该层还包括路由选择、逻辑地址管理等功能
IPInternet Protocol提供数据包的寻址和路由功能是整个互联网的基础。IP协议分为IPv4和IPv6两个版本。其他相关协议包括ICMPInternet Control Message Protocol和ARPAddress Resolution Protocol
4数据链路层 数据链路层负责在相邻节点之间传输数据帧提供物理地址寻址、帧同步、错误检测和纠正等功能。该层协议包括Ethernet、PPPPoint-to-Point Protocol
Ethernet以太网是局域网中最常用的数据链路层协议。PPPPoint-to-Point Protocol用于点对点连接常用于电话拨号连接和一些宽带连接。 3. 数据结构的框架
1线性数据结构一对一 线性数据结构指的是数据元素按顺序排列每个元素只有一个前驱和一个后继常见的线性数据结构有 1. 数组 2. 链表 1单向链表 2双向链表 3循环链表 3. 栈先进后出 4. 队列先进先出
2树型结构一对多 1. 二叉树 2. 二叉搜索树 3. 平衡树 4. 红黑树
3图形结构多对多网状结构
4哈希表 4. 链表的作用
1动态分配内存 链表在需要频繁插入和删除操作的场景中表现优越。由于链表不需要预先分配固定大小的内存可以根据需要动态增加和减少节点节省内存
2实现元素的灵活插入和删除
3实现抽象数据类型如栈、队列等
5. 链表的应用场景
1实现栈和队列的数据结构 单向链表实现入栈出栈、入队出队的操作
2在编译器中实现符号表或字典的实现
3处理大量未知大小的数据集 当需要处理的数据集较大且大小无法预知时链表的动态内存分配优势显现出来特别是频繁的插入和删除操作
4实现哈希表
5浏览器网页的前进和后退 6. 数据库的流程 数据库是一套用于存储、管理和检索数据的系统。数据库的流程可以分为这几个步骤包括设计、创建、操作、优化和维护。
1数据库的设计 1. 需求分析 1确定系统需求包括数据存储、检索、更新和管理需求 2与用户、业务分析师和其他相关方进行交流了解业务流程和数据需求 2. 概念设计 3. 逻辑设计 4. 物理设计
2数据库创建 1. 创建数据库 2. 创建表和约束
3数据操作 1. 数据插入 2. 数据查询 3. 数据更新 4. 数据删除
4数据库优化 1. 查询优化 2. 索引管理 3. 性能监测
5数据库维护 1. 备份和恢复 2. 数据库安全 3. 数据库迁移
6数据库管理 1. 用户管理 2. 日志管理 3. 数据库调整 7. 目录操作流程 8. c语言中#ifndef的作用
1防止重复定义 在大型项目中头文件可能会被多个源文件包含使用#ifndef可以防止多次包含同一个头文件而导致的编译错误 当一个头文件被多次包含时可能会导致重复定义的错误。#ifndef和#define一起使用可以确保头文件内容只被包含一次
2条件编译 根据编译环境的不同选择性编译代码 可以用来根据条件编译特定的代码片段。例如在不同的编译环境中包含不同的代码 9. c语言中头文件#include “stdio.h” 和 #include stdio.h中和有啥区别
1双引号#include header.h包含项目中自定义的头文件 编译器会先在当前目录中搜索头文件如果找不到再去系统目录中搜索
2尖括号#include header.h包含标准库头文件或第三方库头文件 编译器只会在系统标准包含路径中搜索头文件 10. 熟悉哪些协议下载文件常用的协议
1MODBUS协议
2HTTP协议
3FTP协议
4TCP/IP协议
5UDP协议
6下载文件常用的协议 1. HTTP 通过浏览器或下载管理器来下载网页资源、文档、软件等 2. FTP 通常用于下载大型文件或从特定服务器下载 11. 设计一个点对点通信的软件选择TCP还是UDP为什么
1TCP传输控制协议 1. 特点 1可靠性强 2流量控制 根据网络状况调整数据发送速率防止网络阻塞 3连接建立 TCP需要建立连接三次握手有一定延迟 2. 适用场景 1保证文件完整性的文件传输 2消息传递 需要确保消息有序且完整到达的场景如聊天应用程序
2UDP用户数据报协议 1. 特点 1无连接 2不可靠传输 3资源开销小 2. 适用场景 1实时的音视频传输容忍数据丢失 2在线游戏 3广播通信
3选择理由 1. 若通信软件需要可靠的消息传输应该选用TCP 2. 若通信软件强调实时性并且能够容忍数据的丢包和乱序并且需要低延迟则选择UDP 12. 排序算法总结以数组举例
1冒泡排序时间复杂度On^2、排序稳定 1. 原理 重复遍历要排序的数组比较相邻的元素大小如果相邻元素的的顺序错误交换元素的位置直到数组变为顺序结构为之 2. 代码
void BubbleSort(int array[], int len)
{int i 0;int j 0;int tmp 0;for (i 0; i len - 1; i){for (j 0; j len - 1 - i; j){if (array[j] array[j1]){tmp array[j];array[j] array[j1];array[j1] tmp;}}}
} 2插入排序时间复杂度On^2、排序稳定 1. 原理 将数组分为已排序和未排序两部分每次从未排序部分取出一个元素将其插入到已排序部分中的合适位置直到所有的元素都被排序完成。 2. 代码
void InsertSort(int array[], int len)
{int i 0;int j 0;int tmp 0;for (i 0; i len; i){tmp array[i];//暂时存储当前要插入的值j i;while (j 0 a[j-1] tmp)//判断要插入的值是否小于要比较的值{a[j] a[j-1];//把大的数值向后移--j;}a[j] tmp;//找到合适的位置}
} 3选择排序时间复杂度On^2、排序不稳定 1. 原理 每次从未排序部分找到最小最大的元素放入已排序部分的末尾直到所有元素排序完成 2. 代码
void SelectSort(int array[], int len)
{int i 0;int j 0;int tmp 0;int minpos 0;for (i 0; i len-1; i){minpos i;for (j i1; j len; j)//在未排序数组中寻找最小值{if (array[minpos] array[j]){minpos j;//如果当前最小值大于未排序数组元素中的值更新最小值下标} }if (minpos ! i)//如果最小值下标位置已经更新了{tmp array[i];array[i] array[minpos];array[minpos] tmp;}}
} 3. 选择排序不稳定的例子
数组 [4, 5, 3, 5, 2]↑ ↑
初始索引0 1 2 3 4[2, 5, 3, 5, 4][2, 3, 5, 5, 4][2, 3, 4, 5, 5]此时两个5之间的相对前后位置发生了变化 4快速排序时间复杂度On*logn、排序不稳定 采用分治法将一个数组分成较小的子数组然后递归排序这些子数组。 1选取基准元素 2通过基准值将数组划分排列比基准值小的元素放在基准元素的左边比基准值大的元素放在基准值的右边 3递归对基准值左边和右边的数组进行上述操作直到子数组大小为0或一个结束排序 1. 原理图解 1首先从最左边选择1为基准值i 和 j作为位置指针 2将基准值先与j位置数值进行比较10基准值左边比基准值小基准值右边比基准值大所以将j位置数值赋值给i指针位置的覆盖1若发生数值赋值操作固定赋值方的指针转向被赋值指针处继续与基准值进行比较 3从i开始01i向前走21大于基准值的值放在基准值后面将i处的值2赋值给j处的0固定i位置转向j继续进行比较 4重复上述操作直到i与j相遇将基准值赋值给i处完成第一轮排序 5之后展按照上述规则递归处理直到分割的数组只有一个或零个元素完成排序 2. 代码
#include stdio.h
#include string.hvoid print_array(int *a, int len)
{int i 0;for (i 0; i len; i){printf(%d , a[i]);}printf(\n);
}void quick_sort(int *a, int begin, int end)
{if (begin end){return;}int i begin;int j end;int key a[i];//基准值while (i j){while (i j a[j] key){--j;}a[i] a[j];while (i j a[i] key){i;}a[j] a[i];} a[i] key;//遍历一轮quick_sort(a, begin, i-1);quick_sort(a, i1, end);
}int main(void)
{int str[] {1, 2 , -3, -4, 5, 6, 7, -8, 9, 0};int len sizeof(str) / sizeof(str[0]);quick_sort(str, 0, len-1);print_array(str, len);return 0;
}
5希尔排序 13. 数据库类型
1关系型数据库RDBMS 1. MySQL 1特点 开源、易于使用、高性能、 2应用场景 Web开发、电子商务 2. SQLite 1特点 轻量级、适用嵌入式、无需服务器 2应用场景 移动应用、嵌入式系统、 3. Microsoft SQL Server 1特点 商业化、与Windows生态系统集成度高 2应用场景 企业应用
2非关系型数据库NoSQL 1. MongoDB 1特点 文档数据库、、基于JSON的存储、扩展性强 2应用场景 实时分析、大数据应用、物联网loT
3区别 1. 数据模型 1关系型数据库采用表格的关系模型、适合结构化数据和复杂查阅 2非关系型数据库采用键值对、文档、列族或图的形式适合灵活的数据模型 2. 扩展性 1关系型数据库一般纵向扩展 2非关系型数据库一般横向扩展 3. 查询能力 1关系型数据库适用SQL进行复杂查询和操作 2非关系型数据库提供灵活的查询语言和API接口 14. 链表头插尾插哪种效率高
1需要频繁在头部插入节点而不在乎节点顺序头插法更高效
2如果要保持节点插入顺序或实现队列尾插法更合适 15. 链表查重结束的条件
1遍历到链表末尾下一个节点指向NULL
2在遍历过程中发现重复节点 16. 如何调试段错误
1GDB调试 1. 在编译代码时加入-g选项 gcc filename.c -g 2. 使用gdb调试生成代码 gdb a.out 3. GDB调试命令 l 查看代码 b 函数名/行号 设置断点 r 运行代码 n 单步运行 c 直接运行到下一处断点 s 进入函数内部调试 p 变量名 查看变量对应值 q 退出
2打印法调试 在程序可能出现段错误的位置加入打印前一句能够打印出来后一句打印不出来问题就可以定位到两次打印中间的代码部分
3core文件调试法 1. 配置core文件 2. ulimit -c unlimited 3. 编译代码加入-gxuanx gcc filename.c -o filename 4. 运行代码使其产生段错误段错误产生后会生成一个包含错误信息的core文件 5. gdb a.out core能够找到错误产生的位置 17. 数据结构对编程的帮助有哪些
1组织和管理数据
2提高算法效率
3简化代码实现
4解决特定问题
5增强代码可读性和维护性 18. 常用链表的适用场景
1单向链表 1. 实现队列FIFO 2. 动态数据集合例如动态管理学生名单或动态更新的购物车
2双向链表 1. 双向遍历 2. 编辑器的撤销操作
3循环链表 1. 约瑟夫回环问题 2. 时钟算法 19. 熟悉哪些协议下载时用什么协议
1HTTP协议
2TCP/IP协议
3FTP协议
4MODBUS协议
5文件下载时常用HTTP/HTTPS协议 20. 栈区存放什么栈区的大小
1栈区存储的数据 1. 局部变量函数内定义的变量 2. 传递给函数的参数 3. 函数调用后需要范围的地址 4. 临时变量编译器在生成代码时使用的一些临时数据 5. 栈指针
2栈区大小可以修改默认值 1. Windows通常1MB 2. Linux通常8MB 21. 数据区放什么数据区的大小
1数据区存放的数据 1. 已经初始化的静态变量和全局变量 2. 未初始化的静态变量和全局变量 3. 字符串常量
2数据区大小 由操作系统动态管理和分配
3特点 1. 变量未初始化时默认为0 2. 变量在程序编译时开辟空间程序结束时回收空间 22. linux中的常用命令
文件和目录管理
ls列出目录内容。 sh复制代码 ls -l # 以长格式列出目录内容 cd改变当前目录。 sh复制代码 cd /path/to/directory # 切换到指定目录 pwd显示当前工作目录的绝对路径。 sh复制代码 pwd # 显示当前目录 cp复制文件或目录。 sh复制代码 cp source_file destination_file # 复制文件 cp -r source_directory destination_directory # 复制目录 mv移动或重命名文件或目录。 sh复制代码 mv old_name new_name # 重命名文件或目录 mv file_name /path/to/destination # 移动文件 rm删除文件或目录。 sh复制代码 rm file_name # 删除文件 rm -r directory_name # 删除目录 mkdir创建新目录。 sh复制代码 mkdir new_directory # 创建新目录 rmdir删除空目录。 sh复制代码 rmdir empty_directory # 删除空目录
文件内容查看和编辑
cat连接文件并显示内容。 sh复制代码 cat file_name # 显示文件内容 more逐屏查看文件内容。 sh复制代码 more file_name # 逐屏显示文件内容 less逐屏查看文件内容支持前后翻页。 sh复制代码 less file_name # 逐屏显示文件内容 head显示文件开头部分内容。 sh复制代码 head file_name # 显示文件的前10行 head -n 20 file_name # 显示文件的前20行 tail显示文件末尾部分内容。 sh复制代码 tail file_name # 显示文件的后10行 tail -n 20 file_name # 显示文件的后20行 tail -f file_name # 动态显示文件的新内容如日志文件 nano简易文本编辑器。 sh复制代码 nano file_name # 使用nano编辑文件 vim功能强大的文本编辑器。 sh复制代码 vim file_name # 使用vim编辑文件
系统管理
top实时显示系统性能和进程信息。 sh复制代码 top # 实时显示系统信息 ps显示当前进程信息。 sh复制代码 ps aux # 显示所有进程信息 kill终止进程。 sh复制代码 kill process_id # 终止指定进程 kill -9 process_id # 强制终止指定进程 df显示文件系统磁盘空间使用情况。 sh复制代码 df -h # 以人类可读的格式显示磁盘使用情况 du显示文件和目录的磁盘使用情况。 sh复制代码 du -sh directory_name # 显示目录大小 free显示系统内存使用情况。 sh复制代码 free -h # 以人类可读的格式显示内存使用情况 uname显示系统信息。 sh复制代码 uname -a # 显示所有系统信息
网络管理
ping测试网络连接。 sh复制代码 ping www.example.com # 测试与目标主机的网络连接 ifconfig配置网络接口需要超级用户权限。 sh复制代码 ifconfig # 显示网络接口信息 netstat显示网络连接、路由表和网络接口信息。 sh复制代码 netstat -tuln # 显示所有监听端口 ssh通过SSH协议远程登录到另一台主机。 sh复制代码 ssh userhostname # 通过SSH登录远程主机
用户管理
useradd添加新用户需要超级用户权限。 sh复制代码 sudo useradd new_user # 添加新用户 passwd更改用户密码。 sh复制代码 passwd # 更改当前用户密码 sudo passwd user_name # 更改指定用户密码 su切换用户身份。 sh复制代码 su - # 切换到超级用户 su - user_name # 切换到指定用户 sudo以超级用户权限执行命令。 sh复制代码 sudo command # 以超级用户权限执行命令 23. linux下的进程命令
1ps显示当前进程信息
ps aux # 显示所有进程的详细信息 ps -ef # 显示所有进程的完整格式信息
2top实时显示系统性能和进程信息
3pstree以树状图显示进程信息
4kill终止进程
kill process_id # 终止指定进程 kill -9 process_id # 强制终止指定进程 24. linux下的网络命令
1ping测试网络连接
ping www.example.com # 测试与目标主机的网络连接
2ifconfig显示所有网络接口信息
3ip显示和操作网络接口、路由
4netstat显示网络连接、路由表和网络接口信息 25. linux下查看网卡信息命令
1ifconfig显示所有网络接口信息
2ip显示和操作网络接口信息
ip addr show # 显示所有网络接口的地址信息 ip link show # 显示所有网络接口的信息 ip addr show eth0 # 显示特定网络接口eth0的地址信息
26. 单链表和双链表的区别
1单向链表每个节点有数据部分和指向下一个节点的指针 1. 优点 1内存占用少只有一个数据和指向下一个节点的指针 2实现相对简单 2. 缺点 1无法反向遍历 2查找效率低
2双向链表每个节点包含数据部分、指向上一个节点的指针、指向下一个节点的指针 1. 优点 1能够双向遍历 2更高的操作灵活性 2. 缺点 1内存占用多 2实现复杂
3区别 1. 单向链表结构简单、内存占用少、但只能单向遍历、操作灵活性差 2. 双向链表结构复杂、内存占用多但支持双向遍历、操作灵活性高 27. 如果知道某个节点的值想删除怎么操作 1单向链表 两个指针一前一后遍历所有节点寻找到要删除的节点进行删除操作 2双向链表 只需要一个指针进行遍历删除即可 28. 编程时什么时候适合多进程什么时候适合多线程
1多进程 1. 需要任务隔离 当你需要隔离不同任务或模块确保它们之间的崩溃或故障不会影响其他任务时 2. 需要稳定性和安全性 当你需要提高系统的稳定性和安全性时因为每个进程有自己的内存空间崩溃或安全问题不会影响其他进程 3. 资源隔离不需要共享资源 当任务需要独立的资源如文件描述符、网络连接等并且这些资源不能被共享时
2多线程 1. 共享内存场景 多个任务需要频繁访问共享数据时线程可以通过共享内存进行高效的通信 2. 轻量级任务 3. 需要实时性响应 当应用需要响应用户输入或进行实时处理时线程可以在同一个进程中并发执行任务提高响应速度 4 上下文切换开销低 当你需要频繁的上下文切换但进程切换开销过大时线程的上下文切换开销更小 3区别 1. 多进程任务隔离、资源独立性高、稳定性安全性要求高 2. 多线程共享内存、高效资源利用、实时性要求高 29. 列举五个操作进程的命令
1ps查看当前系统的进程信息
ps aux # 显示所有用户的所有进程详细信息 ps -ef # 以完整格式显示所有进程 2top实时显示系统中的进程活动
3kill终止进程
kill PID # 发送SIGTERM信号终止指定PID的进程 kill -9 PID # 发送SIGKILL信号强制终止指定PID的进程 4pstree以树状图显示进程信息
5ulimit设置用户进程的资源限制
ulimit -a # 显示所有限制 ulimit -n number # 设置文件描述符限制
30. 什么是阻塞
1定义 在执行程序时一个操作或进程由于某些原因无法继续执行必须等待某个条件满足后才能继续这种情况下程序或进程会暂停直到阻塞消除
2常见场景 1. IO操作 2. 锁 3. 等待条件 31. 为什么多进程不需要互斥、多线程需要互斥
1多进程不需要互斥因为每个进程都有独立的内存空间进行间不直接共享内存数据不会出现多个进程同时访问和修改同一内存位置的情况
2多线程需要互斥线程共享同一内存空间必须通过同步机制来管理对共享资源的访问防止数据竞争和不一致性
3互斥主要目的是保证数据的完整性和一致性防止多个执行单元线程在同一时间修改共享数据是出现不可预知的结果 32. 数据结构中表、栈、队列的区别
1表 表是一种有序的数据集合每个元素有唯一的位置表可以是动态的能够随时增加或删除元素 插入可以在任意位置插入元素 删除可以删除任意位置的元素 访问可以通过索引访问任何位置的元素
2栈 一种先入后出的数据结构 入栈在栈顶添加元素 出栈从栈顶移出元素 访问只能访问栈顶元素
3队列 先进先出的数据结构 入队在队尾添加元素 出队从队首移除元素 访问只能访问队首和队尾元素
4总结 1. 表有序数据集合可以在任意位置插入、删除和访问适用于需要频繁访问和修改任意位置元素的场景 2. 栈先进后出只能在栈顶进行插入和删除适用于后进先出的场景 3. 队列先进先出只能在队尾插入和队首删除操作适用于需要先进先出的场景 33. 怎么实现文件的拷贝
1linux命令cp
2TCP
3管道 34. 如何定义一个指向整形5个元素的数组指针
int array[5] {1, 2, 3, 4, 5};
int (*pstr)[5] array; 35. Linux中如何测试内存大小
1free 显示系统中内存的使用情况包括总内存、已经使用内存、共享内存、空闲内存、缓存和缓冲区等 free -h
2top 实时显示系统任务信息和内存使用情况 36. 如何在C语言中定义一个能够变长的数组空间
1用malloc分配初始内存空间
#include stdio.h
#include stdlib.hint main() {int initial_size 5;int *array (int *)malloc(initial_size * sizeof(int));if (array NULL) {printf(内存分配失败\n);return 1;}// 使用数组for (int i 0; i initial_size; i) {array[i] i;printf(%d , array[i]);}printf(\n);// 释放内存free(array);return 0;
}2使用realloc来调整数组的大小
#include stdio.h
#include stdlib.hint main() {int initial_size 5;int new_size 10;// 初始分配int *array (int *)malloc(initial_size * sizeof(int));if (array NULL) {printf(内存分配失败\n);return 1;}// 初始化数组for (int i 0; i initial_size; i) {array[i] i;}// 调整大小int *temp (int *)realloc(array, new_size * sizeof(int));if (temp NULL) {printf(内存重新分配失败\n);free(array); // 确保释放原内存return 1;}array temp;// 初始化新空间for (int i initial_size; i new_size; i) {array[i] i;}// 使用新数组for (int i 0; i new_size; i) {printf(%d , array[i]);}printf(\n);// 释放内存free(array);return 0;
}37. linux中如何查看进程的状态图 pstree命令能够以树状图形式显示进程信息 38. 如何使UDP稳定
1超时和确认机制 使用超时和确认机制确保发送的数据包被正确接收
2重传机制 在应用层实现重传机制如果在一定时间内没有收到ACK确认包则重新发送数据包
3错误监测和校验机制
4流量控制和拥塞控制 39. 什么是同步和异步它们的区别是什么
1同步 指任务按顺序执行一个任务必须等前一个任务完成后才能开始下一个任务。 程序阻塞执行当前任务执行完之前后续任务必须等待 任务执行逻辑清晰 会因为其中某个长时间执行的任务导致整体执行延迟变高
2异步 指的是任务可以并发执行不必等待其他任务完成。程序可以继续执行其他任务不会被阻塞
3同步和异步的区别 1. 执行方式 1同步按顺序执行后续任务等待前一项任务完成才能开始执行 2异步任务并发执行不必等待 2. 效率 1同步适合短时间的任务长时间的任务会阻塞程序 2异步适合长时间或IO密集型任务 3. 复杂性 1同步逻辑简单易于调试 2异步逻辑复杂不易调试 40. 介绍数据库的工作原理 数据库的工作原理涉及多方面的知识包括数据存储、检索、索引、事务处理、并发控制、故障恢复等
1数据存储
数据库系统将数据存储在磁盘上的文件中这些文件通常被组织成表。每个表由行记录和列字段组成。
行Row 每行代表一条记录。列Column 每列代表一个数据字段
存储结构
页Page 数据库通常将数据存储在固定大小的页中如4KB或8KB。表空间Tablespace 页进一步组织成表空间用于管理表的数据存储。
2数据检索 数据检索是通过SQL查询语句实现的。查询语句由数据库管理系统DBMS解析、优化和执行
查询处理
解析器Parser 将SQL查询语句解析成语法树。优化器Optimizer 优化查询计划选择最优的执行路径。执行器Executor 执行优化后的查询计划检索数据。
3索引 索引是提高查询速度的关键技术。数据库通过索引来快速定位数据类似于书籍的目录
B-树索引 常见的索引类型适用于范围查询。哈希索引 适用于等值查询。全文索引 用于文本搜索
4事务处理 事务是数据库中的一组操作具有ACID特性原子性、一致性、隔离性、持久性
事务特性
原子性Atomicity 事务中的所有操作要么全部完成要么全部不完成。一致性Consistency 事务使数据库从一个一致状态转换到另一个一致状态。隔离性Isolation 事务的执行彼此隔离。持久性Durability 事务完成后结果持久保存在数据库中。
5并发控制 并发控制确保多个事务能够安全地并发执行避免数据不一致
并发控制方法 锁机制 用于控制对数据的访问。 共享锁S 允许多个事务读取数据。排他锁X 只允许一个事务修改数据。 多版本并发控制MVCC 通过维护数据的多个版本提供高并发性能
6故障恢复
数据库系统通过日志和备份机制实现故障恢复保证数据的可靠性。
恢复机制
日志Log 记录事务操作支持事务回滚和重做。检查点Checkpoint 定期将内存中的数据写入磁盘缩短恢复时间。备份Backup 定期备份数据库防止数据丢失
7数据库架构
数据库系统通常采用客户端-服务器架构。
主要组件
客户端 用户接口发送SQL请求。服务器 处理SQL请求管理数据库。 DBMS内核 实现存储管理、查询处理、事务处理等功能。存储引擎 负责数据的存储和检索
8数据库类型
关系数据库RDBMS 使用表格结构存储数据如MySQL、PostgreSQL。面向对象数据库OODBMS 将对象存储在数据库中。NoSQL数据库 非关系型数据库适用于大数据和分布式存储如MongoDB、Cassandra 41. 互斥和同步的定义和区别
1互斥 1. 定义 互斥是在任何给定的时刻只有一个线程或进程能够访问某个资源或执行某段代码。这是为了防止多个线程同时修改共享资源导致数据不一致 2. 实现方式 加锁机制实现互斥 1互斥锁 2自旋锁 3信号量 4读写锁
2同步 1. 定义 同步是指协调多个线程或进程的执行顺序确保它们按照预期的顺序执行。 2. 实现方式 1条件变量 2信号量 3互斥和同步的区别 1. 互斥 防止多个线程同时访问共享资源确保资源访问的独占性 用于保护共享资源防止数据竞争和不一致 2. 同步 协调多个线程的执行顺序确保线程间的依赖关系和协作 42. linux中与文件相关的命令有哪些
1文件和目录操作 1ls 2cd 3pwd 4mkdir 5rmdir 6rm 7cp 8mv
2文件查看命令 1cat 2more 3less 4head 5head 6tail 3文件搜索与比较 1find
查找文件和目录。示例find /home -name file.txt 在/home目录下查找名为file.txt的文件。 2locate
快速查找文件。示例locate file.txt 查找系统中名为file.txt的文件。 3grep
搜索文件内容。示例grep hello file.txt 搜索file.txt中包含hello的行。 4diff
比较文件内容差异。示例diff file1.txt file2.txt 比较file1.txt和file2.txt的内容差异 5cmp
比较两个文件是否相同。示例cmp file1.txt file2.txt 比较file1.txt和file2.txt。
4文件权限与属性 1chmod
修改文件权限。示例chmod 755 file.txt 设置file.txt的权限为755 2stat
显示文件详细信息。示例stat file.txt 显示file.txt的详细信息
5文件归档和压缩 1tar
归档文件。示例tar -cvf archive.tar dir/ 创建名为archive.tar的归档文件包含目录dir 2gzip
压缩文件。示例gzip file.txt 压缩file.txt生成file.txt.gz 3gunzip
解压缩文件。示例gunzip file.txt.gz 解压file.txt.gz生成file.txt 4zip
创建压缩文件。示例zip archive.zip file1.txt file2.txt 创建名为archive.zip的压缩文件包含file1.txt和file2.txt 5unzip
解压缩文件。示例unzip archive.zip 解压archive.zip
6其他常用命令 1touch
创建空文件或更新文件的修改时间。示例touch newfile.txt 创建名为newfile.txt的空文件 2ln
创建链接文件。示例ln -s file.txt linkfile.txt 创建file.txt的符号链接linkfile.txt 3file
查看文件类型。示例file file.txt 显示file.txt的文件类型 43. 使用进程和网络相关的命令
1进程相关命令 1. ps
ps aux显示所有进程包括其他用户的进程。ps -ef以完整格式显示所有进程 2. top 实时显示系统的资源使用情况包括CPU、内存和每个进程的使用情况 3. kill
kill [PID]终止指定 PID 的进程。kill -9 [PID]强制终止指定 PID 的进程 4. pstree
pstree显示进程树。pstree -p显示进程树并包括 PID
2网络相关命令 1. ifconfig 2. ip 3. ping 4. netstat 显示网络连接、路由表、接口统计等 44. HTTP报文格式 HTTP超文本传输协议是一种用于分布式、协作和超媒体信息系统的应用层协议。它是万维网的数据通信基础。HTTP 报文分为请求报文和响应报文每种报文都包含三个部分起始行、头部字段和消息主体
1请求报文格式 1. 请求行 包含请求方法、请求的 URL 和 HTTP 版本 例如GET /example.html HTTP/1.1 GET 是请求方法/example.html 是请求的资源路径HTTP/1.1 是使用的 HTTP 版本 2. 请求头部 由一系列的键值对组成每行一对常见的头部字段有 Host指定服务器的域名和端口、User-Agent客户端的信息如浏览器类型和版本、Accept客户端能够接受的内容类型等 例如
Host: www.example.comUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0 3. 空行 用于分隔请求头部和请求体 4. 请求体 并非所有的请求都有请求体例如 GET 请求通常没有而 POST 请求常用于携带表单数据、JSON 数据等
2响应报文格式 1. 状态行 包含 HTTP 版本、状态码如 200 表示成功404 表示未找到资源等以及状态描述 例如HTTP/1.1 200 OK 2. 响应头部 与请求头部类似也是一系列的键值对常见的有 Content-Type响应内容的类型、Content-Length响应内容的长度等 例如
Content-Type: text/html; charsetutf-8Content-Length: 1234 3. 空行 分隔响应头部和响应体 4. 响应体 服务器返回的具体内容如 HTML 页面、JSON 数据等 45. 内存碎片、内存泄漏、内存溢出
1内存碎片 由于频繁malloc和free小空间导致大的连续空间由于中间存在小空间被占用而无法得到申请空间的现象称为内存碎片。分为外部碎片和内部碎片
2内存泄漏 指程序在运行过程中分配了空间但未能释放从而导致程序占用的内存不断增加最终可能耗尽系统内存资源。malloc但未能及时free
3内存溢出 也称内存越界操作超过变量范围的空间 46. 原子操作 在多线程或多进程环境中对共享资源的操作能够保证在操作执行过程中不会被终端或干扰的操作。要么完全执行要么完全不执行不存在中间状态 47. 如何利用CPU占用率查看内存信息 top top 命令是一个实时的系统监控工具可以显示 CPU 和内存的使用情况。通过观察 top 输出的信息可以间接分析内存使用情况 48. 什么是MAC地址在数据链路层
1定义 MAC地址是数据链路层地址用在局域网中唯一标识网络接口设备。
2功能 确保网络中的数据能够正确到达目标设备。数据链路层负责处理帧的封装和解封装错误检测和流量控制 48. 详细介绍wireshark
1定义 Wireshark 是一个广泛使用的网络协议分析工具它允许用户捕获和分析网络上的数据包帮助诊断网络问题、进行安全分析和进行协议开发等
2主要功能 1. 数据包捕获 2. 协议分析 Wireshark 支持解码多种网络协议包括 IP、TCP、UDP、HTTP、DNS、SMTP 等 3. 数据过滤 4. 数据分析 5. 到处和报告 49. 什么是时间复杂度和空间复杂度
1时间复杂度时间复杂度越低程序效率越高 衡量算法执行所需的时间也是算法中随着变量的改变时间增长的趋势 1常数时间复杂度 O(1)O(1)O(1): 算法的执行时间与输入规模无关无论输入多大执行时间都是常量 2对数时间复杂度 O(logn)O(\log n)O(logn): 执行时间随着输入规模的对数增长。常见于二分查找算 3线性时间复杂度 O(n): 执行时间与输入规模成正比。比如for循环遍历数组 4线性对数时间复杂度 O(nlogn): 执行时间为 n 和 logn 的乘积.比如快速排序 5二次时间复杂度 O(n2): 执行时间与输入规模的平方成正比/比如冒泡、插入排序
2空间复杂度 空间复杂度衡量算法在执行过程中所需的内存空间。即算法中变量对内存空间大小的影响趋势
3如何分析时间复杂度和空间复杂度 基本操作: 找出算法中最耗时的基本操作如加法、赋值、数组访问等并计算它们的执行次数。 循环: 循环结构通常是影响时间复杂度的关键部分单层循环的时间复杂度通常是 O(n)嵌套循环会叠加复杂度。 递归: 递归算法的时间复杂度通常通过递归方程求解空间复杂度则与递归调用栈的深度相关。 空间开销: 除了考虑变量和数据结构的空间需求还要考虑递归调用栈和临时变量的空间需求。 50. 什么是排序算法的稳定性 在对待排序数据进行排序时两个相同元素的相对位置在排序前后不发生改变贼排序算法稳定 稳定的排序算法排序结束后n1和n2的相对位置不变 51. 快速排序和冒泡排序的对比和区别
1时间复杂度 1. 冒泡排序On^2 2. 快速排序On*logn
2空间复杂度 1. 冒泡排序O1 2. 快速排序Ologn 快速排序虽然是原地排序但用到了递归需要使用栈空间它的空间复杂度取决于递归深度
3稳定性 1. 冒泡排序稳定 2. 快速排序不稳定
4实际应用 1. 冒泡排序时间复杂度较高只能处理数据量小的情况或作为教学算法 2. 快速排序时间复杂度较低广泛应用在实际开发中
5总结 整体看快排比冒泡排序法更优。 它在大多数情况下都能提供较快的排序速度O(nlogn)O(n \log n)O(nlogn)而冒泡排序在处理大数据集时往往表现不佳O(n2)O(n^2)O(n2)。快速排序的唯一缺点是它不是稳定的并且在极端情况下可能会退化为 O(n2)O(n^2)O(n2)。但通过适当的优化快速排序仍然是非常高效的通用排序算法 52. 二叉树的遍历 1前序遍历根节点 - 左子树 - 右子树 深度优先 void pre_order(TreeNode *proot)//前序遍历 根 左 右
{if (NULL proot)//一次前序遍历结束的标志{return ;}printf(%c, proot-data);pre_order(proot-pl);pre_order(proot-pr);
}2中序遍历左子树 - 根节点 - 右子树深度优先
void mid_order(TreeNode *proot)//中序遍历 左 根 右
{if (NULL proot){return ;}mid_order(proot-pl);printf(%c, proot-data);mid_order(proot-pr);
}3后续遍历左子树 - 右子树 - 根节点深度优先
void pos_order(TreeNode *proot)//后续遍历 左 右 根
{if (NULL proot){return ;}pos_order(proot-pl);pos_order(proot-pr);printf(%c, proot-data);
}4层序遍历按层次从上到下、从左到右访问节点广度优先 1. 原理 1利用队列和二叉树的结构特性首先队列为空入队A节点的地址队列非空出队A节点地址打印A节点数据并分别将A节点的左子树节点B和右子树节点D入队队列非空按先入先出的原则先出队B节点打印B节点数据然后依次将B节点的左子树节点E和右子树节点F入队重复执行上述过程直到遍历结束 2代码 //创建队列
QueList *create_queue()
{QueList *pque malloc(sizeof(QueList));if (NULL pque){perror(fail malloc);return NULL;}pque-pfront NULL;pque-prear NULL;pque-clen 0;return pque;
}//入队
int push_queue(QueList *pque, DataType data)
{QueNode *pnode malloc(sizeof(QueNode));if (NULL pnode){perror(fail malloc);return -1;}pnode-data data;pnode-pnext NULL;if (is_empty_queue(pque)){pque-pfront pnode;pque-prear pnode;}else{pque-prear-pnext pnode;pque-prear pnode;}pque-clen;return 0;
}//出队
int pop_queue(QueList *pque, DataType *pdata)
{if (is_empty_queue(pque)){return 1;}QueNode *pfree pque-pfront;pque-pfront pfree-pnext;if (pdata ! NULL){*pdata pfree-data;}free(pfree);pque-clen--;if (NULL pque-pfront){pque-prear NULL;}return 0;
}//层序遍历
void layer_order(TreeNode *proot)//层序遍历
{DataType outdata;QueList *pque create_queue(); if (NULL pque){return ;}push_queue(pque, proot);while (!is_empty_queue(pque)){pop_queue(pque, outdata);printf(%c, outdata-data);if (outdata-pl ! NULL){push_queue(pque, outdata-pl);}if (outdata-pr ! NULL){push_queue(pque, outdata-pr);}}destroy_queue(pque);
} 53. 什么是广度优先遍历和深度优先遍历它们的的区别是是什么
1广度优先遍历Breadth-First Search, BFS 1. 遍历方式 从起始节点开始按照层次顺序逐层遍历先访问距离起始节点最近的节点再访问下一层的节点直到所有节点都被访问 2. 实现方法 通常使用队列Queue数据结构来实现。每次从队列中取出一个节点并将该节点的所有未访问邻居节点依次加入队列 3. 适用场景 适用于需要找到最短路径的场景比如在无权图中寻找最短路径
2深度优先遍历Depth-First Search, DFS 1. 遍历方法 从起始节点开始沿着某一分支不断深入直到无法继续深入为止然后回溯到前一个节点继续遍历未访问的其他分支 2. 实现方式 通常使用栈Stack数据结构来实现可以用递归的方式进行隐式地使用系统栈。每次从栈顶取出一个节点访问其未访问的邻居节点依次入栈继续深入 3. 适用场景 适用于需要遍历完整路径或所有可能路径的场景比如在搜索迷宫时找到所有可能的路线
3区别 1. 顺序BFS按层次顺序遍历DFS按深度顺序遍历 2. 数据结构BFS使用队列DFS使用栈递归实现时使用系统栈 3. 路径BFS优先找到最短路径DFS更适合搜索整棵树或图中的所有路径 54. 介绍内存片 内存片也称为DRAM芯片或内存芯片是计算机内存的主要组件之一用于存储数据和程序代码以供处理器随时访问。内存片在计算机系统中扮演着临时存储的角色具有高速、随机访问的特点
1内存片
内存片通常由多个存储单元cells组成每个单元存储一位数据0或1。这些单元按照行和列排列形成矩阵结构。每个单元由一个晶体管和一个电容器组成
电容器用于存储电荷表示数据位的状态满电表示1放电表示0。晶体管用于控制电容器的充放电状态从而读写数据
2内存片类型
内存片主要有以下几种类型
动态随机存取存储器DRAM这是最常见的内存类型数据存储在电容中由于电容会漏电所以需要定期刷新数据。DRAM速度较快广泛用于计算机主内存RAM。静态随机存取存储器SRAM使用触发器来存储每一位数据不需要像DRAM那样定期刷新因此速度更快但成本更高功耗也更大。常用于CPU缓存。闪存Flash Memory是一种非易失性存储器不需要电源就能保存数据。常见于固态硬盘SSD和USB闪存驱动器。只读存储器ROM数据写入后不能更改通常用于存储固件或操作系统的启动程序。
3工作原理
读操作当处理器需要读取数据时内存控制器会发送行和列地址到内存片。内存片根据地址定位到对应的存储单元并通过晶体管读取电容器中的电荷状态将数据传回处理器。写操作写操作与读操作类似区别在于处理器会将数据写入内存片通过晶体管控制电容器的电荷状态来存储新的数据
4性能指标
容量内存片的存储容量通常以字节为单位现代内存片的容量范围从几百MB到数百GB。速度包括时钟频率如DDR4-3200表示3200 MHz和数据传输速率如3200 MT/s决定了内存的访问速度。延迟表示从处理器发出请求到内存返回数据之间的时间延迟通常以时钟周期为单位表示如CL16
5应用 内存片被广泛应用于各种设备中如个人计算机、服务器、智能手机、平板电脑、嵌入式系统等。它们为处理器提供快速访问的数据存储空间是确保系统高效运行的关键组件 55. 线程池和多进程的区别epoll和线程池的关系和区别epoll能否代替线程池
1线程池 1. 定义 线程池是一种管理和复用线程的技术通过事先创建的一组线程并循环使用它们来处理任务从而减少线程创建和销毁的开销提高系统响应速度和资源利用率 2. 例子 1 现在要与别人打电话我买一部手机跟别人打电话结束后把电话扔掉再与人打电话时再买一部手机与人通信最后再把手机扔掉。这样反复重复浪费钱不如直接买一部手机一直与人打电话不用反复购买电话节省钱 2 以银行取钱为例 1. 一共有五个窗口对应线程池中的提前创建好的五个线程 2. 默认开放三个窗口供用户提供存取服务对应线程池中开放三个能够重复使用的线程 3. 当有人取钱时在空闲窗口存取若窗口已经满了让人在等待区等待窗口空闲对应当任务来临时在线程池中启用线程处理任务若线程池中启用的线程到达上限将后来的任务存入等待队列先进先出中 4. 当银行没有空闲柜台且等待区人数到达上限时银行会恢复未使用的柜台进行营业然后从等待区传唤等待者进行业务办理等待区的其他人往前移动新的用户加入等待区直到柜台全部启动且等待区人数到达上限此时还有新的用户进入时拒绝访问需要到其他银行点去办理对应于线程池中如果正在执行的线程到达上限唤醒未使用的线程将等待队列中的任务加入线程中进行处理若线程池中的线程全部用于进行处理任务且等待队列中无能够加入新任务的节点则无法处理新的任务 3. 线程池的优点 1减少资源消耗 线程池通过复用线程避免了频繁创建和销毁线程带来的资源消耗 2提高响应速度 线程池中的线程可以立即响应任务请求无需等待新线程的创建 3提高系统稳定性 线程池可以控制并发线程的数量避免多线程导致系统资源的耗尽 4灵活的管理机制 可以根据系统负载动态调整线程池的大小适应不同的应用场景
2线程池与多进程的区别 1. 资源开销 1线程池 线程共享同一进程的内存空间线程之间切换开销较小但需要注意线程同步问题 2多进程 每个进程有独立的内存空间进程之间切换开销较大但进程间相互独立不易影响彼此 2. 通信方式 1线程池 线程之间通过共享内存进行通信需要考虑同步机制如锁来避免数据竞争 2多进程 进程之间通常通过IPC如管道、消息队列、共享内存进行通信相对复杂 3. 使用场景 1线程池 适合CPU密集型任务或需要大量并发I/O操作的场景 2多进程 适合需要独立运行、隔离性强的任务特别是需要利用多核CPU的场景
3epoll与线程池的关系和区别 1. 用途 1epoll 用于高效管理和监视大量I/O事件通常用于网络服务器的事件驱动模型 2线程池 用于管理和调度线程执行任务主要解决并发任务的处理问题 2. 协同工作 epoll和线程池可以结合使用 epoll负责监视IO时间当有IO事件发生时将任务分配给线程池中的线程处理从而实现高效的并发IO处理 3. 实现方式 1epoll 通过内核支持实现适用于Linux系统具有高效的事件通知机制 2线程池 通常由应用程序实现依赖于操作系统的线程管理机制
4epoll不能完全代替线程池 epoll主要用于管理和监视I/O事件而线程池用于管理并发任务的执行。它们各自解决不同的问题并且在高并发服务器中经常协同使用以实现高效的事件处理和任务调度
具体示例
高并发网络服务器 epoll 负责监视网络套接字的I/O事件。当有新的I/O事件发生时通过epoll返回的事件通知将处理任务分配给线程池中的空闲线程。线程池中的线程处理具体的I/O读写操作或业务逻辑 56. 常用的进程间通信方法IPC
1管道Pipe
无名管道Unnamed Pipe用于具有亲缘关系的进程间通信如父子进程。有名管道Named Pipe or FIFO用于不具有亲缘关系的进程间通信支持任意进程间的数据传输。
2消息队列 允许进程以消息的形式发送和接收数据通过消息队列标识符进行通信
3信号Signal 用于通知进程某些事件的发生信号是一种异步通信机制
4信号量Semaphore 用于进程间的同步和互斥控制对共享资源的访问
5套接字Socket 主要用于网络通信但也可以用于本地进程间通信通过TCP/IP协议传输数据 57. 无名管道和有名管道的区别
1无名管道
只能用于具有亲缘关系的进程间通信如父子进程。在创建时管道的读端和写端由进程继承。使用 pipe() 系统调用创建。
2有名管道
可以用于不具有亲缘关系的任意进程间通信。有文件系统中的路径名任何进程都可以通过路径名访问管道。使用 mkfifo() 系统调用创建
58. 无名和有名管道的创建
1无名管道 1. 创建管道 使用 pipe() 系统调用创建无名管道
int pipefd[2];
if (pipe(pipefd) -1) {perror(pipe);exit(EXIT_FAILURE);
}2. 使用管道 父进程和子进程分别关闭不需要的端口
pid_t pid fork();
if (pid -1) {perror(fork);exit(EXIT_FAILURE);
} else if (pid 0) {// 子进程close(pipefd[1]); // 关闭写端// 读数据
} else {// 父进程close(pipefd[0]); // 关闭读端// 写数据
}2有名管道 1. 创建有名管道 使用 mkfifo() 系统调用创建有名管道
const char *fifo_path /tmp/myfifo;
if (mkfifo(fifo_path, 0666) -1) {perror(mkfifo);exit(EXIT_FAILURE);
}2. 打开和使用有名管道 使用 open() 系统调用打开有名管道进行读写 1写入端
int fd open(fifo_path, O_WRONLY);
if (fd -1) {perror(open);exit(EXIT_FAILURE);
}
// 写数据
write(fd, Hello, 5);
close(fd);2读取端
int fd open(fifo_path, O_RDONLY);
if (fd -1) {perror(open);exit(EXIT_FAILURE);
}
// 读数据
char buffer[128];
read(fd, buffer, sizeof(buffer));
close(fd);59. 什么是中断上下文什么是中断顶半部和中断底半部
1中断上下文是指处理器在处理中断服务程序时所处的执行环境
2中断顶半部和底半部 1. 中断顶半部中断上半部 为中断处理函数部分一般用于处理过程比较快不会占用太长事件处理的中断任务 2. 中断底半部中断下半部 中断处理中比较耗时的操作一般会放在中断下半部执行以便让中断处理函数快进快出 60. 什么是信号如何使用信号使用信号处理函数需要注意什么可以在信号处理函数中malloc空间吗malloc空间会发生什么
1信号是一种进程间通信IPC机制用于向进程发送通知告知其发生了异步事件。信号可以打断进程的正常执行流以处理特定事件 常见信号
SIGINT (2): 用户中断如CtrlC。SIGKILL (9): 强制终止进程。SIGTERM (15): 请求终止进程。SIGSEGV (11): 段错误非法内存访问。SIGALRM (14): 定时器信号
2 信号的使用和处理 1信号的处理 1. 默认处理系统预定义的默认处理行为如终止进程、忽略信号等 2. 捕获处理进程可以定义自己的信号处理函数信号处理程序来处理特定信号 3. 忽略处理进程可以选择忽略某些信号但SIGKILL和SIGSTOP不能被忽略或捕获 2信号的发送 1. 用户通过键盘输入如CtrlC 2. 进程间通过系统调用kill发送信号 3. 内核发送信号如定时器信号SIGALRM 4. 硬件异常导致的信号如段错误SIGSEGV 3使用信号 1. 发送信号 kill(pid_t pid, int sig) 用于向指定进程发送信号 pid指定接收信号的进程IDsig指定发送的信号类型 2. 捕获信号 signal(int signum, sighandler_t handler) 用于设置信号处理程序 signum是信号编号handler是处理函数的指针可以是一个函数地址、SIG_IGN忽略信号或SIG_DFL使用默认处理 3. 示例代码
#include stdio.h
#include signal.h
#include unistd.hvoid handle_sigint(int sig) {printf(Caught signal %d\n, sig);
}int main() {// 设置SIGINT信号的处理函数signal(SIGINT, handle_sigint);// 无限循环等待信号while (1) {printf(Running...\n);sleep(1);}return 0;
}在这个例子中当用户按下CtrlC时进程会捕获SIGINT信号并调用handle_sigint函数而不是终止进程 3信号处理函数的注意事项 1. 可重入性 信号处理函数应该是可重入的因为它可能在任何时间点被调用。不可重入的函数如printf、malloc、free等在信号处理函数中可能导致未定义行为 2. 最小化处理时间 信号处理函数应该尽量短小快速避免长时间运行影响系统响应 3. 异步信号安全 在信号处理函数中应该只调用异步信号安全async-signal-safe的函数。Linux手册中列出了这些函数包括_exit、signal、write等 4. 共享数据的同步 处理共享数据时需要小心可能需要使用自旋锁等同步机制避免竞态条件
4在信号处理函数中使用malloc 在信号处理函数中调用malloc可能会导致未定义行为。这是因为malloc及其相关函数不是异步信号安全的它们可能使用内部全局数据结构进行内存管理这些数据结构在信号处理函数中可能被不安全地访问和修改 可能发生的问题 1死锁 malloc可能在信号处理函数中尝试获取内存管理锁而该锁可能已被其他代码持有导致死锁 2内存损坏 多线程环境下malloc可能导致内存管理数据结构的并发访问导致内存损坏或崩溃 3结论 为了安全处理信号建议在信号处理函数中避免使用非异步信号安全的函数例如避免在信号处理函数中使用malloc。 处理方法是在主程序中预分配好所需的内存信号处理函数中直接使用这些预分配的内存或只调用异步信号安全的函数确保信号处理函数的可重入性和安全性
5信号的应用场景 1. 进程控制 使用信号来控制进程的启动、停止、终止等 2. 定时操作 使用SIGALRM信号进行定时操作 3. 异常处理 捕获如段错误SIGSEGV等异常进行错误处理 4. 进程间通信 使用信号进行简单的进程间通信和同步 61. 常用代码调试方法包含检测段错误
1GDBGNU调试器 GDB是一个功能强大的调试器可以用于调试C程序。一般步骤是启动GDB设置断点、运行程序、打印变量值调试分母为零的错误 1. 编译代码时加入-g选项 gcc filename.c -g 2. 使用gdb调试生成的代码 gdb a.out 3. gdb调试命令 l 查看代码 b 函数名/行号 设置断点 r 运行代码 n 单步运行 c 直接运行到下一断点处 s 进入函数内部调试 p 变量名 查看变量对应的值 q 退出
2使用printf打印调试 在可能出现错误的位置加入打印前一句能够打印出来后一句打印不出来问题就可以定位到两次打印中间的代码
3core文件调试法检测段错误 1. 配置core文件 2. ulimit -c unlimited 3. 编译代码加入-g选项 gcc filename.c -g 4. 运行代码使其产生段错误段错误产生后会生成一个包含错误信息的core文件 5. gdb a.out core找到错误产生的位置
4使用valgrind进行内存调试 valgrind是一款内存调试工具可以检测内存泄漏、非法内存访问等问题 操作步骤 1. 正常编译程序
gcc -o my_program my_program.c2. 使用valgrind运行程序
valgrind --leak-checkfull ./my_program5使用静态分析工具 静态分析工具如cppcheck可以在编译前检测代码中的潜在问题 1. 安装cppcheck
sudo apt-get install cppcheck2. 使用cppcheck分析代码
cppcheck my_program.c6使用IDE调试 许多集成开发环境IDE如CLion、Code::Blocks、Eclipse等都提供了图形化的调试功能支持设置断点、单步执行、查看变量值等
62. linux中什么是内存泄漏内存泄漏的原理是什么
1内存泄漏 内存泄漏Memory Leak是指程序在运行过程中动态分配的内存未被释放导致这部分内存无法被重用。虽然程序已经不再需要这些内存但由于未能释放它们仍然占用内存资源导致系统的可用内存逐渐减少最终可能引发内存不足的问题
2内存泄漏的原因 内存泄漏的根本原因是程序未能正确管理动态内存分配 1. 未释放内存 程序使用malloc、calloc、realloc等函数分配内存但在使用完后没有调用free释放这部分内存 2. 丢失指针引用 程序分配内存后将指向这块内存的指针覆盖或修改导致无法再访问和释放这块内存
int *ptr (int *)malloc(sizeof(int) * 10);
ptr NULL; // 原来的内存地址丢失无法释放3. 循环引用 特别是在使用复杂数据结构如链表、树时如果存在循环引用可能导致内存无法正确释放
struct node {struct node *next;
};
struct node *n1 (struct node *)malloc(sizeof(struct node));
struct node *n2 (struct node *)malloc(sizeof(struct node));
n1-next n2;
n2-next n1; // 循环引用
free(n1);
free(n2); // 由于循环引用内存不能完全释放63. 踩内存是什么(关于越界访问)越界访问你了解多少当你的程序发生越界访问你怎么调试
1踩内存 1. 定义 程序错误地修改了它无权访问的内存区域。踩内存可能导致不可预见的行为包括程序崩溃、数据损坏和安全漏洞。 2. 出现踩内存的原因 1缓冲区溢出 程序写入超过数组或缓冲区边界的数据导致相邻内存区域被覆盖 2使用已释放的内存 程序在释放内存后继续使用这段内存导致未定义行为 3双重释放 程序试图释放已经释放的内存再次释放可能导致内存管理数据结构的损坏 4程序使用未初始化或已失效的指针导致访问无效内存
2越界访问 1. 定义 越界访问是踩内存的一个具体表现指程序访问了数组或缓冲区边界之外的内存区域 2. 越界访问可能导致产生的问题 1数据损坏 改变其他变量的数据导致程序逻辑错误 2程序崩溃 访问非法内存地址导致段错误Segmentation Fault 3安全漏洞 攻击者可以利用越界访问执行恶意代码或泄露敏感信息
3调试越界访问 1. 使用GDB调试 GDB是一个强大的调试器可以帮助检测和调试越界访问问题 2. 使用valgrind valgrind是一款强大的内存调试工具可以检测内存错误包括越界访问 3. 使用AddressSanitizer AddressSanitizer是一个内存错误检测工具可以在编译时启用 4. 静态分析工具 静态分析工具如cppcheck和clang-tidy可以在编译前检测代码中的潜在问题 64. 什么是网络传输中的丢包和粘包如何解决丢包和粘包
1丢包 1. 定义 丢包是指在数据传输过程中数据包未能到达目的地导致数据的缺失。丢包会影响数据的完整性和传输质量 2. 产生丢包的原因 1网络拥塞 网络中数据流量过大导致路由器和交换机无法处理所有的数据包部分数据包被丢弃 2硬件故障 网络设备如路由器、交换机、网卡等故障导致数据包丢失 3信号干扰 无线网络中由于信号干扰或弱信号导致数据包未能成功传输 4软件问题 网络协议栈中的软件错误或配置错误也可能导致丢包 3. 丢包的解决方法 1使用可靠的传输协议如TCP协议有丢包重传机制 2优化网络环境减少网络拥塞、升级网络设备避免信号干扰 3质量检测和监控使用网络监控工具检测和分析丢包情况及时处理网络故障
2粘包 1. 定义 粘包是指在数据传输过程中多个数据包被连接在一起接收端无法区分这些数据包即不同数据之间缺乏分界线和分隔标志导致数据解析错误。粘包通常发生在TCP传输中因为TCP是流量传输协议 2. 粘包产生的原因 1数据发送过快 发送端连续发送多个数据包而接收方处理速度跟不上导致多个数据包在接收端缓冲区中积累形成一个大的数据包 2TCP协议的特性 TCP是面向字节流的协议它并不关心数据包的边界。在传输过程中TCP会根据网络情况进行分段和重组这可能会导致粘包 3接收方读取数据的方式 接收方读取数据时没有按照预期的数据边界来读取而是一次性读多个数据包的内容 3. 粘包的解决方法 1使用定长消息 每个数据包固定长度接收方每次读取固定长度的数据。但这种方法的效率较低不适合长度变化较大的数据 2使用特殊分隔符 在每个数据包的末尾加一个特殊的分隔符如换行符、特殊字符等接收方读取数据时通过检测分隔符来区分不同的数据包。这种方法比较简单但需要确保分隔符在实际数据中不会出现 3在数据包前加上长度字段 在每个数据包的前面加上一个表示数据包长度的字段通常为定长字段接收方先读取长度字段根据长度字段的值再读取相应长度的数据包。这是比较常用且有效的方法