新沂市网站建设,设计官网需要的流程,123上网,卖服装设计稿的平台1. static的作用2. 引用与指针的区别3. .h头文件中的ifndef/define/endif 的作用4 #includefile.h与#includefile.h的区别?5 描述实时系统的基本特性6 全局变量和局部变量在内存中是否有区别?如果有#xff0c;是什么区别?7 什么是平衡二叉树?8 堆栈溢…1. static的作用2. 引用与指针的区别3. .h头文件中的ifndef/define/endif 的作用4 #includefile.h与#includefile.h的区别?5 描述实时系统的基本特性6 全局变量和局部变量在内存中是否有区别?如果有是什么区别?7 什么是平衡二叉树?8 堆栈溢出一般是由什么原因导致的?9 冒泡排序算法的时间复杂度是什么?10 什么函数不能声明为虚函数11 栈和队列的区别12 switch不支持的参数类型13 局部变量是否可以和全局变量重名14 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?15 简述程序的内存分配16 解释堆和栈的区别17 gcc四部曲18 const关键字19 volatile关键字20 三种基本的数据类型21 结构体与联合体的区别22 const与#define相比的优点23 简述数组与指针的区别24 如何判断程序是由c编译还是c编译25 讨论含参数的宏与函数的优缺点26 什么是中断27 什么是boa服务器28 共享内存如何使用29.消息队列如何使用30.怎样实现进程间同步31.网关有什么作用32.线程间的同步互斥是怎么实现的33.什么是同步什么是互斥34.文件流指针指的是什么35.文件i/o和标准i/o的区别两者描述文件的方式36.UDP可不可以实现可靠的数据传输37.TCP的缺点39.register关键字解析38.介绍selectpollepoll40.符号关键字unsigned41.函数指针指针函数指针数组数组指针42.出现野指针的情况43.结构体枚举宏定义44.进程线程程序的区别45.动态库和静态库的区别46.什么是回调函数47.地址能否用%u打印48.声明变量和定义变量的区别49.赋值和赋初值有什么区别50.如何引用一个定义过的外部变量51.为什么函数形参数组和指针可以互换52.形参和实参有什么区别53.void指针就是空指针么有什么作用54.指针数组地址之间有什么关系55.字符设备块设备管道等在linux下的统称是什么56.查看一个文件类型有哪几种方式57.Linux下常用安装工具58.分别解释shell命令shellshell脚本59.printf与scanf操作的是否是同一个文件60.Linux常用的文件系统类型如何查看文件系统类型61.windows下有没有文件系统文件系统有何作用62.头文件和库文件一般在哪个路径下63.系统如何区别同名的文件64.系统如何区别不同的进程。65.查看文件有哪些命令66.如何修改文件的权限67.什么是符号链接68.数据结构主要研究的是什么69.数组和链表的区别逻辑结构、内存存储、访问方式三个方面辨析70.快速排序的算法71.hash查找的算法72.判断单链表是否有环[73.判断一个括号字符串是否匹配正确如果括号有多种怎么做如[]正确[(()错误74.简述系统调用75.如何将程序执行直接运行于后台76.进程的状态77.简述创建子进程中的写时拷贝技术78.线程池的使用79.简述互斥锁的实现原理80.简述死锁的情景81.简述信号量的原理82.管道的通信原理83.用户进程对信号的响应方式84.ISO七层网络通信结构每层的主要作用主要的协议85.TCP/IP四层网络通信结构86.io模型有哪几种87.如何实现并发服务器并发服务器的实现方式以及有什么异同88.网络超时检测的本质和实现方式89.udp本地通信需要注意哪些方面90.怎么修改文件描述符的标志位91.TCP和UDP的区别92.TCP的三次握手和四次挥手分别作用主要做什么93.new、delete、malloc、free关系94.delete与delete[]区别95.C有哪些性质面向对象特点96.子类析构时要调用父类的析构函数吗97.多态虚函数纯虚函数98.什么是“引用”申明和使用“引用”要注意哪些问题99.将“引用”作为函数参数有哪些特点100.在什么时候需要使用“常引用” 1. static的作用
静态局部变量
延长局部变量的生命周期至整个程序运行期间但作用域仍限于定义它的函数内部。
静态全局变量
限制全局变量的作用域至定义它的文件防止其在其他文件中被访问。
静态成员变量
使成员变量属于类而非类的实例所有对象共享同一个静态成员变量。
静态成员函数
使成员函数属于类而非类的实例可以通过类名直接调用且只能访问静态成员变量和静态成员函数。2. 引用与指针的区别 引用
引用是另一个变量的别名必须在定义时初始化且不能为空。
引用一旦初始化后就不能再指向其他变量。
不需要手动管理内存引用本身不占用额外内存.指针
指针是一个变量存储另一个变量的地址可以不初始化或指向nullptr。
指针可以在其生命周期内指向不同的对象或变量
需要手动管理内存可能涉及动态内存分配和释放。
3. .h头文件中的ifndef/define/endif 的作用 #ifndef、#define和#endif预处理指令用于防止头文件内容被多次包含.具体作用如下
#ifndef检查指定的宏是否未定义如果未定义则执行后续代码。
#define定义一个宏确保后续包含该头文件时#ifndef检查将失败避免重复包含。
#endif结束#ifndef块。4 #includefile.h与#includefile.h的区别?
区别在于搜索路径和顺序#include file.h编译器在系统的标准包含目录中搜索头文件通常用于标准库或第三方库头文件。
#include file.h编译器首先在当前源文件所在目录搜索头文件若未找到则转至标准包含目录通常用于项目自定义头文件。5 描述实时系统的基本特性
实时系统的基本特性包括时间约束性必须在规定时间内完成任务处理。
可预测性系统行为和性能需在给定时间内可预测。
确定性相同事件的响应时间应一致。
可靠性系统需在各种环境下稳定运行。
优先级调度采用优先级调度机制确保高优先级任务优先处理。
资源管理有效管理资源确保关键任务获得所需计算资源。
容错性具备一定容错能力确保系统稳定性和可靠性。
这些特性确保实时系统在严格时间约束下对外部事件作出及时、准确的响应。6 全局变量和局部变量在内存中是否有区别?如果有是什么区别?
全局变量和局部变量在内存中的主要区别如下全局变量存储在全局数据区程序启动时分配结束时释放。
全局变量从程序启动到结束持续存在。
全局变量在整个程序中可访问。未初始化的全局变量自动初始化为零或空值。局部变量存储在栈上随函数调用动态分配和释放。
局部变量仅在其定义的代码块执行期间存在。
局部变量仅在其定义的代码块内可访问。
7 什么是平衡二叉树?
平衡二叉树是一种特殊的二叉搜索树
其每个节点的左右子树高度差不超过1确保树的高度保持在O(log n)
从而保证插入、删除和查找操作的时间复杂度为O(log n)。常见的平衡二叉树包括AVL树和红黑树。
8 堆栈溢出一般是由什么原因导致的?
递归调用过深递归层次过深导致堆栈内存不断增加。
局部变量过多或过大大量或大内存占用的局部变量导致堆栈空间耗尽。
堆栈大小限制程序所需堆栈空间超过系统或编译器设定的限制。
无限循环或错误逻辑程序逻辑错误导致函数不断被调用堆栈空间耗尽。
缓冲区溢出未正确检查边界的缓冲区操作破坏堆栈结构。9 冒泡排序算法的时间复杂度是什么?
冒泡排序算法的时间复杂度是O(n^2)原因是每一次循环都需要进行n-1次比较10 什么函数不能声明为虚函数
静态成员函数属于类而非实例不与特定对象关联。
内联函数编译时展开与虚函数的运行时动态绑定不兼容。
构造函数用于对象创建虚函数机制在对象创建后生效。
友元函数虽可访问私有成员但不属于类成员函数。
全局函数不属于任何类。11 栈和队列的区别
数据存储方式
栈后进先出LIFO数据从栈顶插入和删除。
队列先进先出FIFO数据从队尾插入从队头删除。操作方式
栈主要操作是压栈插入和弹栈删除。
队列主要操作是入队插入和出队删除。12 switch不支持的参数类型
浮点类型如float和double因比较复杂且可能有精度问题。
字符串类型如std::string因字符串比较和匹配复杂。
自定义对象类型因switch仅支持整数和枚举类型。
布尔类型虽为整数类型但通常用if-else更直观。13 局部变量是否可以和全局变量重名
在C中局部变量可以与全局变量重名。当局部变量与全局变量重名时
在局部变量的作用域内局部变量会屏蔽隐藏同名的全局变量。
这意味着在局部变量的作用域内访问该变量名时将引用局部变量而不是全局变量。14 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
全局变量不应定义在可被多个.C文件包含的头文件中因为这会导致重复定义错误。
每个包含该头文件的.C文件都会有一份全局变量的定义链接时会引发重复定义错误。
正确的做法是将全局变量的声明放在头文件中并在一个.C文件中进行定义。
头文件中使用extern关键字声明全局变量表示该变量在其他地方定义。15 简述程序的内存分配
栈Stack存储函数的局部变量、参数和返回地址自动管理后进先出。
堆Heap动态内存分配由程序员通过new和delete操作符手动管理。
全局/静态存储区存储全局变量和静态变量生命周期从程序启动到结束。
常量存储区存储常量数据如字符串常量和const修饰的变量不可修改。
代码段存储程序的机器指令只读防止运行时修改。16 解释堆和栈的区别
栈
自动管理由编译器负责函数调用时分配返回时释放。
局部变量和函数参数的生命周期由函数调用和返回决定。
访问速度较快因为栈的内存分配和释放是连续的。
后进先出LIFO内存分配和释放按固定顺序进行。堆
手动管理由程序员通过new和delete操作符显式分配和释放。
动态分配的内存生命周期由程序员控制直到显式释放。
访问速度较慢因为堆的内存分配和释放是动态的可能涉及内存碎片和复杂的分配算法。
内存分配和释放没有固定顺序可以按需进行。
17 gcc四部曲
预处理处理预处理指令生成预处理后的源文件。 (展开宏定义包含头文件内容移除注释等)
编译将预处理后的源文件编译成汇编代码。 (词法分析、语法分析、语义分析和代码优化生成对应的汇编代码。)
汇编将汇编代码汇编成目标文件。 (汇编语言文件转换成机器代码)
链接将目标文件与库链接生成可执行文件。18 const关键字
const关键字可以提高代码的安全性、保护数据不被修改。1. 常量变量定义初始化后不可更改的变量。
2. 常量指针指针指向的值不可变。指针本身不可变。指针和指针指向的值都不可变。
3. 常量成员函数在类中修饰成员函数表示该函数不会修改类的成员变量。
4. 常量函数参数在函数参数中使用表示函数内部不能修改该参数的值。
5. 常量返回值修饰函数返回值表示返回值不可修改。
19 volatile关键字
(答案存疑)
volatile关键字在C中用于告诉编译器
某个变量的值可能会在程序的控制之外被改变
因此编译器不应该对该变量进行优化。20 三种基本的数据类型
整型Integer、浮点型Floating-Point和字符型Character21 结构体与联合体的区别 结构体
每个成员有独立内存总大小是各成员大小之和(考虑内存对齐)。
可同时存储多个不同类型的数据。可同时访问和修改所有成员。
适用于多数据存储表示复杂对象。联合体
所有成员共享内存大小等于最大成员的大小。
同一时间只能存储一个成员的值。只能访问和修改当前存储的成员。
适用于节省内存或实现多态。
22 const与#define相比的优点 const
提供类型检查确保类型安全。
具有作用域可在局部或类作用域定义。
可被调试器识别和显示便于调试。
可存储在只读存储区优化内存管理。
更易读和维护有明确的类型和作用域。#define
无类型信息缺乏类型检查。
全局作用域易引发命名冲突。
预处理阶段被替换难以调试。
不占用内存空间。
代码中直接替换可能导致代码膨胀和可读性下降。23 简述数组与指针的区别
1. 定义和初始化
数组需指定元素类型和数量。
指针需指定指向的变量类型。
2. 内存分配
数组静态分配连续内存。
指针可动态分配内存。
3. 访问元素
数组用下标访问。
指针用指针运算访问。
4. 赋值和复制
数组不能直接赋值需逐元素复制。
指针可以直接赋值。
5. 函数参数传递
数组退化为指针传递首地址。
指针传递指针变量的值地址。
6. 类型信息
数组数组名表示整个数组。
指针表示指向的变量类型。24 如何判断程序是由c编译还是c编译
C源文件通常使用.c扩展名。 生成的目标文件通常带有c标记。
C源文件通常使用.cpp、.cc、.cxx等扩展名。 生成的目标文件通常带有cpp或cxx标记。25 讨论含参数的宏与函数的优缺点
宏函数
预处理阶段展开无函数调用开销执行速度快。
避免函数调用的堆栈操作适用于性能敏感代码。
可接受任意类型参数不进行类型检查。
可读性和维护性差宏代码在预处理阶段展开可能导致代码膨胀难以调试。
宏定义分散不易阅读和维护。
不进行类型检查可能导致类型相关的错误。函数:
函数有明确的定义和调用代码结构清晰易于阅读和维护。
便于调试和测试。
编译器进行类型检查确保类型安全减少运行时错误。
函数调用涉及堆栈操作可能带来额外开销
26 什么是中断
中断是计算机系统中的一种机制用于在执行程序的过程中
临时暂停当前任务转而处理更为紧急或重要的任务。
中断可以由硬件设备或软件触发
处理过程包括中断请求、中断响应、保存现场、中断处理和恢复现场。
这一机制提高了系统的响应速度和处理能力广泛应用于设备驱动程序、操作系统内核和实时系统等领域。27 什么是boa服务器
OA服务器是一种轻量级、高性能的Web服务器软件
专为嵌入式系统和资源受限的环境设计。
它具有代码量小、占用资源少、处理性能高、配置简单、稳定可靠等特点。
BOA服务器广泛应用于嵌入式Linux系统
提供基本的HTTP服务如静态网页访问和简单的CGI脚本执行
适用于物联网设备、路由器、网络存储设备等领域。28 共享内存如何使用
共享内存是一种高效的进程间通信机制
通过系统调用创建、附加、使用、分离和删除共享内存段
实现多个进程间的数据共享。使用时需注意同步问题以确保数据一致性。常见的同步机制包括信号量、互斥锁等
-----------------
1创建共享内存
使用系统调用如shmget创建一个新的共享内存段或者获取一个已存在的共享内存段的标识符。
2附加共享内存
使用系统调用如shmat将共享内存段附加到进程的地址空间中使得进程可以访问这块内存。
3使用共享内存
进程可以直接读写附加到其地址空间中的共享内存区域进行数据交换。
4分离共享内存
当进程不再需要访问共享内存时使用系统调用如shmdt将共享内存段从其地址空间中分离。
5删除共享内存
当所有进程都不再需要使用共享内存时使用系统调用如shmctl删除共享内存段释放系统资源。
29.消息队列如何使用
消息队列是一种进程间通信IPC机制允许多个进程通过发送和接收消息来进行异步通信。以下是消息队列的基本使用步骤创建消息队列
使用系统调用如msgget创建一个新的消息队列或者获取一个已存在的消息队列的标识符。发送消息
使用系统调用如msgsnd将消息发送到消息队列中。消息通常包含一个类型字段和一个数据字段。接收消息
使用系统调用如msgrcv从消息队列中接收消息。接收方可以根据消息类型选择性地接收消息。控制消息队列
使用系统调用如msgctl对消息队列进行控制操作如修改队列属性、删除队列等。消息队列的使用提供了进程间异步通信的能力
发送方和接收方不需要同时处于活动状态
消息会在队列中等待直到被处理。这种机制适用于需要解耦和异步处理的场景。30.怎样实现进程间同步
进程间同步的常见方法包括信号量
计数器控制共享资源访问通过semget、semop、semctl系统调用实现。互斥锁Mutex
二进制信号量确保同一时间只有一个进程访问资源通过pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock实现。条件变量Condition Variable
允许进程在特定条件满足时等待或唤醒通过pthread_cond_init、pthread_cond_wait、pthread_cond_signal实现。文件锁File Lock
通过文件系统提供的锁机制控制对文件的访问通过fcntl系统调用实现。这些方法确保进程按序访问共享资源避免数据竞争和不一致。31.网关有什么作用
网关是连接不同网络的关键设备主要作用包括协议转换在不同网络协议间进行转换。
数据转发将数据从一个网络传输到另一个网络。
安全控制实施防火墙等安全策略保护网络免受威胁。
地址转换进行网络地址转换NAT实现私有IP与公共IP的转换。
路由选择根据路由表选择最佳路径确保数据高效传输。
服务提供提供DHCP、DNS等服务简化网络管理。网关确保网络间的顺畅通信和安全防护是网络通信的桥梁和安全屏障。32.线程间的同步互斥是怎么实现的
线程间同步互斥的实现方法包括互斥锁Mutex
通过pthread_mutex_init、pthread_mutex_lock、pthread_mutex_unlock实现确保同一时间只有一个线程访问资源。条件变量Condition Variable
通过pthread_cond_init、pthread_cond_wait、pthread_cond_signal实现允许线程在特定条件满足时等待或唤醒。读写锁Reader-Writer Lock
通过pthread_rwlock_init、pthread_rwlock_rdlock、pthread_rwlock_wrlock、pthread_rwlock_unlock实现允许多个读线程同时访问但写线程独占访问。信号量Semaphore
通过sem_init、sem_wait、sem_post实现控制对共享资源的访问。这些机制确保线程按序访问共享资源避免数据竞争和不一致。33.什么是同步什么是互斥
同步Synchronization确保多个线程或进程按特定顺序执行避免竞态条件常用机制包括条件变量、信号量、屏障等。互斥Mutual Exclusion确保同一时间只有一个线程或进程访问共享资源常用机制包括互斥锁、临界区等。34.文件流指针指的是什么
文件流指针File Stream Pointer指向文件内部位置的指针用于指示当前读写操作的位置通过fopen、fread、fwrite、fseek等函数操作。35.文件i/o和标准i/o的区别两者描述文件的方式
文件I/O低级I/O
直接使用系统调用如open、read、write、close操作文件描述符性能高但编程复杂。标准I/O高级I/O
使用标准库函数如fopen、fread、fwrite、fclose操作文件流指针提供缓冲机制编程简单但性能稍低。描述文件方式
文件I/O使用文件描述符整数。
标准I/O使用文件流指针FILE*。36.UDP可不可以实现可靠的数据传输
UDP本身不可靠但可通过应用层实现可靠性使用确认机制、重传机制、序号和校验和等手段在应用层实现类似TCP的可靠性。37.TCP的缺点
TCP缺点头部较大开销高。
传输速度受拥塞控制影响可能较慢。
连接建立需三次握手延迟较高。
不支持多播和广播。39.register关键字解析
register关键字建议编译器将变量存储在寄存器中提高访问速度。
编译器可忽略此建议现代编译器优化能力强register使用较少。限制不能取地址不能用于数组和结构体。 38.介绍selectpollepoll
select监控多个文件描述符FD最大数量有限通常1024。
使用位图表示FD集合每次调用需传递整个集合效率低。
适用于简单、FD数量少的场景。
poll使用链表管理FD无最大数量限制。
每次调用需传递整个链表效率随数量增加下降。
适用于FD数量较多但仍有限的场景。
epollLinux特有高效处理大量FD。
使用事件驱动仅通知有事件发生的FD无需遍历所有FD。
支持边缘触发ET和水平触发LT性能稳定适用于高并发场景。40.符号关键字unsigned
unsigned关键字用于声明无符号整数类型表示数值范围从0开始无负数。
常见用法unsigned int、unsigned char、unsigned long等。
增加正数范围减少负数范围。41.函数指针指针函数指针数组数组指针
函数指针
指向函数的指针用于调用函数声明如int (*func_ptr)(int, int);。指针函数
返回指针的函数如int* func(int x);。指针数组
存储指针的数组如int* arr[10];。数组指针
指向数组的指针如int (*arr_ptr)[10];。42.出现野指针的情况
野指针情况未初始化指针如int* p;。
释放内存后未置空如free(p); p NULL;。
指针越界访问超出分配内存范围。
多线程环境下未同步访问共享指针。43.结构体枚举宏定义
结构体
用户定义的数据类型组合多个不同类型数据如struct Point { int x; int y; };。枚举
定义一组命名常量如enum Color { RED, GREEN, BLUE };。宏定义
预处理器指令定义常量或代码片段如#define PI 3.14#define SQUARE(x) ((x) * (x))。44.进程线程程序的区别
进程操作系统资源分配和调度基本单位拥有独立内存空间、文件描述符等资源。
进程间通信IPC复杂如管道、消息队列、共享内存等。
创建、销毁、切换开销大。线程进程内执行单元共享进程资源内存、文件独立执行流。
线程间通信简单通过共享内存或线程同步机制如互斥锁、条件变量。
创建、销毁、切换开销小适用于并发处理。程序静态代码和数据的集合存储在磁盘上未运行状态。
通过操作系统加载和执行转化为进程开始运行。
程序本身不占用系统资源进程是程序的动态执行实例。45.动态库和静态库的区别
静态库编译时链接到可执行文件包含所有代码和数据。
可执行文件体积大部署简单运行时无需外部库。动态库运行时加载多个程序共享节省内存。
可执行文件体积小需依赖外部库部署复杂。
更新动态库不影响可执行文件便于维护。46.什么是回调函数
回调函数作为参数传递给其他函数的函数在特定事件或条件触发时被调用。
实现异步编程、事件驱动编程提高代码灵活性和可扩展性。
常见于事件处理、异步操作、库函数接口等场景。47.地址能否用%u打印
地址通常不能用%u打印%u用于无符号整数地址类型为指针如void*。
应使用%p格式符打印指针地址如printf(%p, ptr);。
确保类型匹配避免未定义行为。48.声明变量和定义变量的区别
声明变量
告知编译器变量存在但不分配内存如extern int x;。定义变量
实际分配内存创建变量如int x;。
定义隐含声明但声明不隐含定义。区别
声明不分配内存定义分配内存。
多个声明合法重复定义非法。49.赋值和赋初值有什么区别
赋值
将值赋予已存在的变量如int x; x 10;。赋初值
在变量定义时赋予初始值如int x 10;。区别
赋值操作变量已存在赋初值伴随变量定义。
赋初值确保变量初始状态避免未定义行为。50.如何引用一个定义过的外部变量
引用外部变量使用extern关键字声明如extern int x;。
确保外部变量在其他文件中已定义如int x;。
编译器链接时解析外部变量引用。51.为什么函数形参数组和指针可以互换
函数形参数组和指针互换原因数组名在函数参数列表中退化为指向首元素的指针。
如void func(int arr[])等同于void func(int *arr)。
编译器处理数组参数为指针传递数组地址提高效率。
区别数组参数声明更直观指针参数更灵活。
数组参数隐含大小信息指针参数无此信息。52.形参和实参有什么区别
形参是函数定义时声明的参数用于接收调用时传递的值
实参是函数调用时传递给函数的具体值或变量。
简单来说形参是“形式上的参数”实参是“实际的参数”。53.void指针就是空指针么有什么作用
void指针void *是一种特殊类型的指针它可以指向任何数据类型
但本身不指定具体类型。它不是空指针NULL或nullptr
空指针表示指针不指向任何有效的内存地址。void指针的作用包括通用数据类型的指针适用于需要处理多种数据类型的函数。
在函数参数中使用实现泛型编程。
动态内存分配时返回的指针类型通常是void *。54.指针数组地址之间有什么关系
指针、数组和地址之间有密切的关系指针指针是一个变量存储另一个变量的内存地址。
数组数组是一组相同类型的元素的集合数组名本身代表数组首元素的地址。
地址地址是内存中存储单元的编号通过地址可以访问存储在该位置的数据。关系如下
数组名可以看作指向数组首元素的常量指针。
指针可以用来访问和操作数组元素。
通过指针和数组名可以对内存地址进行操作和访问55.字符设备块设备管道等在linux下的统称是什么
在Linux下字符设备、块设备、管道等统称为特殊文件或设备文件。
它们通常位于/dev目录下用于与硬件设备或特定系统功能进行交互。56.查看一个文件类型有哪几种方式
查看文件类型有以下几种方式file命令使用file命令可以查看文件的类型。file filenamels -l命令使用ls -l命令查看文件的详细信息第一列显示文件类型和权限。ls -l filenamestat命令使用stat命令查看文件的详细状态信息。stat filename文件扩展名虽然Linux不依赖文件扩展名来判断文件类型但某些应用程序和用户习惯使用扩展名来标识文件类型。57.Linux下常用安装工具
APTAdvanced Package ToolDebian及其衍生发行版如Ubuntu的包管理工具。sudo apt updatesudo apt install package_nameYUMYellowdog Updater, ModifiedRed Hat及其衍生发行版如CentOS的包管理工具。sudo yum install package_nameDNFDandified YUMYUM的继任者用于Fedora和较新的Red Hat发行版。sudo dnf install package_namePacmanArch Linux及其衍生发行版的包管理工具。sudo pacman -S package_nameZypperopenSUSE的包管理工具。sudo zypper install package_nameSnap和Flatpak用于跨发行版的通用包管理工具。sudo snap install package_namesudo flatpak install package_name
58.分别解释shell命令shellshell脚本
Shell命令Shell命令是用户通过Shell命令行解释器输入的指令用于执行特定的操作如文件管理、进程控制、系统配置等。例如ls、cd、mkdir等。ShellShell是操作系统的外壳作为用户与内核之间的接口负责解释和执行用户输入的命令。常见的Shell有BashBourne Again SHell、Zsh、Fish等。Shell脚本Shell脚本是用Shell语言编写的脚本文件包含一系列Shell命令和控制结构如循环、条件判断等用于自动化执行一系列任务。Shell脚本通常以.sh为扩展名可以通过sh或bash等Shell解释器执行。59.printf与scanf操作的是否是同一个文件
printf和scanf操作的默认情况下是同一个文件即标准输入输出文件。具体来说printf用于向标准输出通常是终端屏幕打印数据。
scanf用于从标准输入通常是键盘读取数据。
在默认情况下标准输出和标准输入分别对应文件描述符1和0。
用户可以通过重定向操作符如、、将这些标准流重定向到其他文件或设备。60.Linux常用的文件系统类型如何查看文件系统类型
Linux常用的文件系统类型包括ext4第四代扩展文件系统是大多数Linux发行版的默认文件系统。
ext3第三代扩展文件系统是ext4的前身。
ext2第二代扩展文件系统。
XFS高性能的日志文件系统常用于大型文件系统和高性能计算。
BtrfsB-tree文件系统具有高级功能如快照、数据校验和、动态inode分配等。
NTFSWindows的默认文件系统在Linux中可以通过NTFS-3G等驱动程序进行读写。
FAT32常见的跨平台文件系统兼容性好但功能有限。查看文件系统类型的方法df命令使用df -T命令查看挂载点上的文件系统类型。df -Tlsblk命令使用lsblk -f命令查看块设备的文件系统类型。lsblk -ffile命令使用file -s命令查看特定设备上的文件系统类型。file -s /dev/sda1blkid命令使用blkid命令查看块设备的UUID和文件系统类型。blkid
61.windows下有没有文件系统文件系统有何作用
Windows操作系统下有多种文件系统常见的包括NTFSNew Technology File SystemWindows的默认文件系统支持大容量磁盘、文件权限控制、加密、压缩等高级功能。
FAT32File Allocation Table 32较早的文件系统兼容性好但文件大小和分区大小有限制。
exFATExtended File Allocation Table用于闪存驱动器和大容量存储设备支持更大的文件和分区。文件系统的作用主要包括
组织和管理文件文件系统负责在存储设备上组织和管理文件包括文件的存储位置、目录结构、文件名等。
数据存储和检索文件系统提供数据存储和检索的机制确保数据能够高效、可靠地存储和访问。
文件权限和安全某些文件系统如NTFS提供文件权限控制、加密等功能保护数据安全。
磁盘空间管理文件系统管理磁盘空间分配和回收存储空间确保磁盘空间的高效利用。
总之文件系统是操作系统中负责管理文件和目录、控制文件存储和检索的关键组件。62.头文件和库文件一般在哪个路径下
头文件和库文件在不同操作系统及编译环境下的默认路径有所不同头文件Header FilesLinux通常位于/usr/include或/usr/local/include目录下。
Windows通常位于编译器或开发环境的安装目录下的include文件夹中例如Visual Studio的VC\include目录。库文件Library Files
Linux通常位于/usr/lib或/usr/local/lib目录下。
Windows通常位于编译器或开发环境的安装目录下的lib文件夹中例如Visual Studio的VC\lib目录。此外用户也可以自定义头文件和库文件的路径通过编译器的选项如-I指定头文件路径-L指定库文件路径来指定。63.系统如何区别同名的文件
系统通过以下几种方式来区别同名文件目录结构文件系统通过文件所在的目录来区分同名文件。例如/home/user1/file.txt和/home/user2/file.txt是两个不同的文件即使它们具有相同的文件名。文件路径完整的文件路径包括目录和文件名唯一标识一个文件。例如C:\Documents\file.txt和C:\Downloads\file.txt是两个不同的文件。文件扩展名虽然文件扩展名不是必须的但在某些情况下扩展名可以用来区分同名文件。例如file.txt和file.doc是两个不同的文件。文件属性某些文件系统支持文件属性如标签、颜色标记等这些属性可以用来区分同名文件。文件系统UUID某些文件系统如NTFS为每个文件分配唯一的UUIDUniversally Unique Identifier即使文件名相同UUID也能唯一标识文件。硬链接和符号链接硬链接和符号链接可以指向同一个文件但它们在文件系统中表现为不同的条目。总之文件系统通过文件的完整路径、目录结构、扩展名、属性、UUID等方式来确保同名文件在系统中能够被正确区分和管理。64.系统如何区别不同的进程。
系统通过以下几种方式来区别不同的进程进程IDPID每个进程在系统中都有一个唯一的进程IDPID这是一个正整数用于标识进程。PID由操作系统内核分配并在进程的生命周期内保持不变。父进程IDPPID每个进程都有一个父进程IDPPID表示创建该进程的父进程的PID。通过PPID可以追踪进程的创建关系。进程名称进程通常有一个名称可以通过命令行工具如ps、top查看。虽然名称不是唯一的但结合PID可以唯一标识一个进程。进程状态进程在不同状态下如运行、等待、停止等可以被区分。状态信息可以通过系统调用或命令行工具查看。用户和组ID进程运行在特定的用户和组上下文中用户IDUID和组IDGID可以用来区分不同用户或组的进程。内存地址空间每个进程都有独立的内存地址空间包括代码段、数据段、堆、栈等。通过内存地址空间的隔离系统可以区分不同的进程。文件描述符每个进程都有一组文件描述符用于管理打开的文件和设备。文件描述符的集合可以用来区分不同的进程。进程控制块PCB操作系统内核为每个进程维护一个进程控制块PCB包含进程的所有信息如PID、状态、优先级、寄存器值等。PCB是内核区分和管理进程的核心数据结构。通过这些方式操作系统能够有效地管理和区分系统中的不同进程。65.查看文件有哪些命令
在Linux和Unix系统中有多种命令可以用来查看文件内容和属性。以下是一些常用的命令cat显示文件的全部内容。cat filenamemore分页显示文件内容适合查看长文件。more filenameless与more类似但功能更强大支持向前和向后滚动。less filenamehead显示文件的前几行默认10行。head filenametail显示文件的最后几行默认10行常用于查看日志文件的更新。tail filenamenl显示文件内容并添加行号。nl filenameod以八进制或其他格式显示文件内容用于查看二进制文件。od filenamefile显示文件类型。file filenamestat显示文件的详细状态信息。stat filenamels列出目录内容包括文件和子目录。ls -l filenamewc统计文件的行数、字数和字节数。wc filenamegrep搜索文件中包含特定模式的行。grep pattern filename这些命令提供了多种方式来查看文件的内容和属性用户可以根据需要选择合适的命令。66.如何修改文件的权限
简要概述如何修改文件权限使用chmod命令通过chmod命令修改文件权限。符号模式用户类别u用户g组o其他a所有
操作添加-移除设置
权限r读w写x执行
示例chmod ux file给用户添加执行权限
八进制模式每位八进制数对应一组权限4读2写1执行
组合这些值来表示权限例如7421即rwx
示例chmod 755 file设置用户读、写、执行权限组和其他用户读、执行权限
通过这些方式可以灵活地修改文件的权限。67.什么是符号链接
简要概述符号链接定义符号链接Symbolic Link又称软链接Soft Link是一种特殊类型的文件指向另一个文件或目录。
特点
指向性可以指向文件或目录跨文件系统。
独立性有自己的inode和权限不影响目标文件或目录。
透明性访问时自动重定向到目标。
脆弱性目标删除或移动后链接失效。
创建使用ln -s命令语法为ln -s 目标文件或目录 符号链接文件。
符号链接类似于Windows中的快捷方式用于方便地访问文件或目录68.数据结构主要研究的是什么
数据结构主要研究的是如何在计算机中组织和存储数据以便高效地进行操作。具体来说数据结构研究以下几个方面数据组织研究如何将数据元素按照一定的逻辑关系组织起来形成一个数据集合。常见的数据组织方式包括线性结构如数组、链表、树形结构如二叉树、B树和图形结构如图、网络。数据存储研究如何在计算机内存中存储数据以便快速访问和操作。不同的数据结构有不同的存储方式例如数组在内存中是连续存储的而链表则是通过指针链接的。数据操作研究如何对数据进行增、删、改、查等操作以及这些操作的时间复杂度和空间复杂度。高效的数据操作是数据结构研究的核心内容之一。算法设计数据结构与算法紧密相关研究数据结构的同时也需要设计相应的算法来操作这些数据结构。例如针对不同的数据结构设计排序、搜索、遍历等算法。性能分析研究不同数据结构和算法的性能包括时间复杂度操作所需的时间和空间复杂度操作所需的内存空间以便选择最适合特定应用场景的数据结构和算法。总之数据结构主要研究数据的组织、存储、操作和性能分析旨在提供高效的数据处理方法以满足各种应用需求。69.数组和链表的区别逻辑结构、内存存储、访问方式三个方面辨析
数组和链表是两种常见的数据结构它们在逻辑结构、内存存储和访问方式上有显著的区别逻辑结构
数组数组的元素在逻辑上是连续的每个元素有一个固定的位置索引可以通过索引直接访问任意元素。
链表链表的元素在逻辑上通过指针或引用链接在一起每个元素节点包含数据和指向下一个节点的指针。访问链表中的元素通常需要从头节点开始逐个遍历。内存存储
数组数组的元素在内存中是连续存储的这使得数组可以通过基地址和元素大小快速计算出任意元素的内存地址。
链表链表的元素在内存中可以是非连续存储的每个节点通过指针链接。这种存储方式使得链表在插入和删除操作时更为灵活但需要额外的内存空间来存储指针。访问方式
数组数组支持随机访问即可以通过索引直接访问任意位置的元素时间复杂度为O(1)。
链表链表支持顺序访问访问某个元素需要从头节点开始逐个遍历时间复杂度为O(n)其中n是链表的长度。总结
数组逻辑上连续内存中连续存储支持随机访问。
链表逻辑上通过指针链接内存中可以非连续存储支持顺序访问。数组和链表各有优缺点选择哪种数据结构取决于具体的应用场景和操作需求。70.快速排序的算法
快速排序QuickSort是一种高效的排序算法采用分治法策略。其主要步骤包括选择基准值从数列中选择一个元素作为基准pivot。
分区操作重新排列数列将所有比基准值小的元素放在基准前面所有比基准值大的元素放在基准后面。分区完成后基准元素处于其最终位置。
递归排序对基准左右两边的子数列递归地进行快速排序。快速排序的核心在于分区操作通过选择合适的基准值和分区策略可以实现高效的排序。
快速排序的平均时间复杂度为O(n log n)
但在最坏情况下如每次选择的基准值都是最小或最大元素时间复杂度为O(n^2)。#include iostream
#include vector// 分区函数
int partition(std::vectorint arr, int low, int high) {int pivot arr[high]; // 选择最后一个元素作为基准int i low - 1; // i是较小元素的索引for (int j low; j high; j) {if (arr[j] pivot) {i;std::swap(arr[i], arr[j]);}}std::swap(arr[i 1], arr[high]);return i 1;
}// 快速排序函数
void quicksort(std::vectorint arr, int low, int high) {if (low high) {int pi partition(arr, low, high);quicksort(arr, low, pi - 1); // 递归排序左子数列quicksort(arr, pi 1, high); // 递归排序右子数列}
}int main() {std::vectorint arr {10, 7, 8, 9, 1, 5};int n arr.size();quicksort(arr, 0, n - 1);std::cout Sorted array: ;for (int i : arr) {std::cout i ;}std::cout std::endl;return 0;
}
71.hash查找的算法
哈希查找Hash Search是一种基于哈希表Hash Table的查找算法。哈希表是一种数据结构通过哈希函数将键Key映射到表中的一个位置从而实现快速的插入、删除和查找操作。哈希查找的核心在于哈希函数的设计和冲突解决方法。哈希查找的基本步骤
哈希函数将键转换为哈希表中的索引。一个好的哈希函数应该尽可能均匀地分布键减少冲突。
冲突解决当两个或多个键映射到同一个位置时需要解决冲突。常见的冲突解决方法有链地址法Chaining和开放地址法Open Addressing。
查找操作根据键计算哈希值找到对应的索引然后在该位置查找目标元素。#include iostream
#include vector
#include listclass HashTable {
private:int size;std::vectorstd::liststd::pairint, std::string table;int hashFunction(int key) {return key % size;}public:HashTable(int s) : size(s) {table.resize(size);}void insert(int key, std::string value) {int hashIndex hashFunction(key);for (auto pair : table[hashIndex]) {if (pair.first key) {pair.second value;return;}}table[hashIndex].push_back(std::make_pair(key, value));}std::string search(int key) {int hashIndex hashFunction(key);for (const auto pair : table[hashIndex]) {if (pair.first key) {return pair.second;}}throw std::out_of_range(Key not found);}void remove(int key) {int hashIndex hashFunction(key);for (auto it table[hashIndex].begin(); it ! table[hashIndex].end(); it) {if (it-first key) {table[hashIndex].erase(it);return;}}}
};int main() {HashTable ht(10);ht.insert(1, Value1);ht.insert(11, Value11);ht.insert(21, Value21);try {std::cout Search 1: ht.search(1) std::endl;std::cout Search 11: ht.search(11) std::endl;std::cout Search 21: ht.search(21) std::endl;std::cout Search 31: ht.search(31) std::endl; // This will throw an exception} catch (const std::out_of_range e) {std::cerr Exception: e.what() std::endl;}ht.remove(11);try {std::cout Search 11 after removal: ht.search(11) std::endl; // This will throw an exception} catch (const std::out_of_range e) {std::cerr Exception: e.what() std::endl;}return 0;
}
72.判断单链表是否有环
判断单链表是否有环是一个经典的问题常用的解决方法是使用快慢指针Floyds Tortoise and Hare Algorithm。该算法通过两个指针以不同的速度遍历链表如果链表中有环快指针最终会追上慢指针。算法步骤
初始化两个指针慢指针tortoise和快指针hare都指向链表的头节点。
慢指针每次移动一步快指针每次移动两步。
如果链表中有环快指针最终会追上慢指针即两个指针会相遇。
如果快指针到达链表的末尾即指向NULL则链表中没有环。#include iostream// 定义链表节点结构
struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};// 判断链表是否有环的函数
bool hasCycle(ListNode *head) {if (head NULL || head-next NULL) {return false;}ListNode *slow head;ListNode *fast head-next;while (slow ! fast) {if (fast NULL || fast-next NULL) {return false;}slow slow-next;fast fast-next-next;}return true;
}int main() {// 创建一个有环的链表ListNode *head new ListNode(1);head-next new ListNode(2);head-next-next new ListNode(3);head-next-next-next head-next; // 创建环if (hasCycle(head)) {std::cout 链表中有环 std::endl;} else {std::cout 链表中没有环 std::endl;}// 清理内存注意有环的链表会导致无限循环这里不进行清理return 0;
}
73.判断一个括号字符串是否匹配正确如果括号有多种怎么做如[]正确[[(()错误
判断一个括号字符串是否匹配正确可以使用栈Stack数据结构来实现。栈的特点是后进先出LIFO非常适合用于处理括号匹配问题。算法步骤
初始化一个空栈。
遍历字符串中的每一个字符
如果是左括号如(, [, {将其压入栈中。
如果是右括号如), ], }检查栈是否为空
如果栈为空说明没有匹配的左括号返回不匹配。
如果栈不为空弹出栈顶元素检查是否与当前右括号匹配。如果不匹配返回不匹配。
遍历结束后检查栈是否为空
如果栈为空说明所有括号都匹配正确返回匹配。
如果栈不为空说明有未匹配的左括号返回不匹配。#include iostream
#include stack
#include unordered_map// 判断括号字符串是否匹配正确的函数
bool isValid(const std::string s) {std::stackchar stack;std::unordered_mapchar, char bracketMap {{), (},{], [},{}, {}};for (char ch : s) {if (bracketMap.find(ch) ! bracketMap.end()) {// 当前字符是右括号if (stack.empty()) {return false;}char topElement stack.top();stack.pop();if (topElement ! bracketMap[ch]) {return false;}} else {// 当前字符是左括号stack.push(ch);}}return stack.empty();
}int main() {std::string s1 (([]));std::string s2 [[(()];if (isValid(s1)) {std::cout s1 是匹配的 std::endl;} else {std::cout s1 是不匹配的 std::endl;}if (isValid(s2)) {std::cout s2 是匹配的 std::endl;} else {std::cout s2 是不匹配的 std::endl;}return 0;
}
74.简述系统调用
系统调用System Call是操作系统提供给应用程序的一组接口用于请求操作系统内核执行某些特权操作或访问受保护的资源。系统调用是应用程序与操作系统之间的桥梁使得应用程序可以安全、高效地使用底层硬件和操作系统服务。系统调用的主要功能
进程控制创建和终止进程获取和设置进程属性等待事件信号处理等。
文件管理创建、打开、关闭、读取、写入文件获取和设置文件属性等。
设备管理请求和释放设备读取和写入设备获取和设置设备属性等。
内存管理分配和释放内存映射文件到内存获取和设置内存属性等。
进程间通信管道、消息队列、信号量、共享内存等。
网络通信套接字Socket接口用于网络通信。系统调用的执行过程
用户态到内核态的切换应用程序通过特定的指令如x86架构的int 0x80或syscall指令发起系统调用导致CPU从用户态切换到内核态。
系统调用号每个系统调用都有一个唯一的编号系统调用号用于标识具体的系统调用。
参数传递系统调用的参数通常通过寄存器传递给内核。
内核处理内核根据系统调用号和参数执行相应的操作如访问硬件、修改内核数据结构等。
返回结果内核将系统调用的结果返回给应用程序并从内核态切换回用户态。75.如何将程序执行直接运行于后台
1. 使用 符号
在命令行中可以在命令末尾添加 符号使程序在后台运行。command
例如
./my_program 2. 使用 nohup 命令
nohup 命令可以使程序在后台运行并且忽略挂起信号SIGHUP即使终端关闭程序也会继续运行。nohup command 例如
nohup ./my_program
(还可补充)76.进程的状态
进程是操作系统中运行的程序的实例它们在执行过程中会经历不同的状态。常见的进程状态包括1. 新建New
进程刚刚被创建但还未被操作系统调度执行。2. 就绪Ready
进程已经准备好运行等待操作系统分配CPU时间片。3. 运行Running
进程正在CPU上执行。4. 阻塞Blocked
进程由于等待某些事件如I/O操作完成、信号量可用等而暂停执行即使CPU空闲该进程也不会被调度。5. 挂起Suspended
进程被暂时移出内存通常是因为内存不足或管理员干预。挂起的进程不占用CPU资源直到被重新调入内存。6. 终止Terminated
进程执行完毕或被操作系统终止。新建|v就绪 ----- 运行 ----- 阻塞| | |v v v挂起 挂起 挂起| | |v v v终止 终止 终止
77.简述创建子进程中的写时拷贝技术
写时拷贝Copy-On-Write简称COW是一种优化技术主要用于在创建子进程时减少内存开销。传统的进程创建方式会为子进程复制父进程的整个地址空间这会导致大量的内存复制操作。写时拷贝技术通过延迟复制只在需要修改数据时才进行实际的内存复制从而提高效率。写时拷贝的工作原理
初始共享当创建子进程时操作系统并不立即复制父进程的地址空间而是让父进程和子进程共享同一份物理内存。
写时复制当任何一个进程父进程或子进程尝试修改共享内存中的数据时操作系统会检测到这一操作并为该进程分配新的物理内存页然后将修改前的数据复制到新的内存页中再进行修改。
独立内存经过写时复制后父进程和子进程的内存页变得独立各自拥有自己的副本互不干扰。优点
减少内存开销在创建子进程时不需要立即复制整个地址空间节省了大量内存。
提高效率只有在实际需要修改数据时才进行复制减少了不必要的内存复制操作提高了系统性能。78.线程池的使用
线程池Thread Pool是一种并发编程技术用于管理和复用线程以提高程序的性能和资源利用率。
线程池通过预先创建一组线程并将任务分配给这些线程来执行从而避免了频繁创建和销毁线程的开销。线程池的主要优点
减少线程创建和销毁的开销线程池中的线程是预先创建的任务执行完毕后不会立即销毁而是返回到线程池中等待下一个任务。
提高响应速度任务可以立即分配给线程池中的空闲线程执行无需等待新线程的创建。
控制并发数量线程池可以限制同时运行的线程数量避免系统资源被过度消耗。线程池的基本组成
任务队列用于存储待执行的任务。
工作线程线程池中预先创建的线程负责从任务队列中取出任务并执行。
任务提交接口用于向线程池提交任务。
线程池管理器负责线程池的初始化、任务分配、线程管理等。线程池的使用步骤
创建线程池初始化线程池指定线程池的大小即工作线程的数量。
提交任务将任务提交给线程池线程池会自动分配给空闲的工作线程执行。
执行任务工作线程从任务队列中取出任务并执行。
关闭线程池任务执行完毕后关闭线程池释放资源。79.简述互斥锁的实现原理
互斥锁Mutex全称Mutual Exclusion是一种同步机制用于确保在多线程环境中同一时间只有一个线程可以访问共享资源。互斥锁的实现原理主要基于操作系统的内核支持和原子操作。互斥锁的基本原理
锁定Lock当一个线程尝试锁定互斥锁时如果锁是可用的即未被其他线程持有该线程将成功获得锁并可以访问共享资源。如果锁已被其他线程持有尝试锁定的线程将被阻塞直到锁变为可用。
解锁Unlock持有锁的线程在访问完共享资源后必须释放锁使其他线程可以获得锁并访问共享资源。互斥锁的实现细节
原子操作互斥锁的核心是原子操作确保锁的状态在多线程环境中不会出现竞态条件。原子操作通常由硬件支持确保操作在执行过程中不会被中断。
内核支持操作系统内核提供互斥锁的实现包括锁的创建、销毁、锁定和解锁等操作。内核通过调度机制管理线程的阻塞和唤醒。
等待队列当多个线程尝试锁定同一个互斥锁时内核会维护一个等待队列按顺序阻塞这些线程。当锁被释放时内核会从等待队列中选择一个线程唤醒使其获得锁。互斥锁的状态
可用Unlocked锁未被任何线程持有可以被任意线程锁定。
锁定Locked锁被某个线程持有其他线程尝试锁定时将被阻塞。80.简述死锁的情景
死锁Deadlock是指在多线程或多进程系统中两个或多个线程或进程互相持有对方所需的资源并且都在等待对方释放资源从而导致所有涉及的线程或进程都无法继续执行的状态。死锁是一种常见的并发问题可能导致系统停滞。死锁的四个必要条件
互斥条件Mutual Exclusion资源不能被多个线程或进程同时访问必须独占使用。
占有并等待Hold and Wait线程或进程已经持有一个或多个资源并且正在等待获取其他线程或进程持有的资源。
不可抢占No Preemption资源不能被强制抢占只能由持有资源的线程或进程主动释放。
循环等待Circular Wait存在一组线程或进程形成一个循环链每个线程或进程都在等待下一个线程或进程持有的资源。死锁的典型情景
资源分配图如果资源分配图中存在环路则可能发生死锁。环路表示一组线程或进程和资源之间的循环依赖关系。
银行家算法银行家算法是一种避免死锁的算法通过预先检查资源分配状态确保系统不会进入不安全状态即可能发生死锁的状态。死锁的解决方法
预防死锁通过破坏死锁的四个必要条件之一来预防死锁的发生。例如可以通过资源分级、一次性请求所有资源、资源抢占等方式来预防死锁。
避免死锁在运行时动态检查资源分配状态确保系统始终处于安全状态。银行家算法是一种典型的避免死锁的方法。
检测和恢复死锁定期检测系统中是否存在死锁一旦检测到死锁采取措施恢复系统如终止某些线程或进程、回滚事务等。81.简述信号量的原理
信号量Semaphore是一种用于多线程或多进程环境中同步和互斥的机制。信号量通过一个整数值来控制对共享资源的访问可以用于实现线程间的同步和资源管理。信号量的原理基于计数器和等待队列。信号量的基本原理
计数器信号量维护一个整数计数器表示可用资源的数量。计数器的初始值可以设置为资源的初始数量。
P操作等待操作Proberen线程尝试获取资源时执行P操作。如果计数器大于零表示有可用资源线程可以继续执行并将计数器减一。如果计数器为零表示没有可用资源线程将被阻塞进入等待队列。
V操作信号操作Verhogen线程释放资源时执行V操作。计数器加一并唤醒等待队列中的一个线程使其可以继续执行。信号量的类型
二进制信号量Binary Semaphore计数器的值只能为0或1类似于互斥锁但信号量可以被任意线程释放。
计数信号量Counting Semaphore计数器的值可以是任意非负整数用于控制多个资源的访问。信号量的实现细节
原子操作信号量的P操作和V操作必须是原子操作确保在多线程环境中的正确性。原子操作通常由硬件支持确保操作在执行过程中不会被中断。
等待队列信号量维护一个等待队列用于存储被阻塞的线程。当计数器为零时尝试获取资源的线程将被加入等待队列。当计数器增加时信号量会从等待队列中唤醒一个线程。82.管道的通信原理
管道Pipe是一种用于进程间通信Inter-Process Communication, IPC的机制。管道允许一个进程将其输出直接连接到另一个进程的输入从而实现数据的单向或双向传输。管道的通信原理基于操作系统的内核支持通过创建一个共享的内存缓冲区来传递数据。管道的基本原理
创建管道操作系统在内核中创建一个共享的内存缓冲区用于存储数据。管道有两个端点读端和写端。数据传输写进程将数据写入管道的写端数据被存储在共享的内存缓冲区中。读进程从管道的读端读取数据数据从共享的内存缓冲区中取出。阻塞和非阻塞操作如果管道的缓冲区已满写进程将被阻塞直到有空间可用。如果管道的缓冲区为空读进程将被阻塞直到有数据可用。关闭管道当进程不再需要使用管道时可以关闭管道的读端或写端。当所有读端和写端都关闭时管道将被销毁。管道的类型
匿名管道Anonymous Pipe通常用于父子进程之间的通信通过pipe系统调用创建。匿名管道是单向的只能用于具有亲缘关系的进程之间。
命名管道Named Pipe也称为FIFOFirst In, First Out通过mkfifo系统调用创建。命名管道是双向的可以用于任意进程之间的通信。83.用户进程对信号的响应方式
在Unix和类Unix操作系统中信号Signal是一种用于进程间通信的机制用于通知进程发生了某个事件。用户进程可以通过多种方式响应信号具体取决于信号的处理方式。信号的响应方式
默认处理Default Action每个信号都有一个默认的处理方式由操作系统定义。常见的默认处理方式包括终止进程、忽略信号、暂停进程、继续进程等。
忽略信号Ignore Signal进程可以选择忽略某个信号即不对该信号做出任何响应。通过调用signal或sigaction函数并将处理函数设置为SIG_IGN可以忽略信号。
捕获信号Catch Signal进程可以捕获信号并执行自定义的处理函数。通过调用signal或sigaction函数并将处理函数设置为自定义函数可以捕获信号并执行相应的处理逻辑。常见的信号及其默认处理方式
SIGINT中断信号通常由用户按下CtrlC产生。默认处理方式是终止进程。
SIGTERM终止信号通常由kill命令产生。默认处理方式是终止进程。
SIGKILL强制终止信号无法被捕获或忽略。默认处理方式是终止进程。
SIGSTOP暂停信号无法被捕获或忽略。默认处理方式是暂停进程。
SIGCONT继续信号默认处理方式是继续执行暂停的进程。
SIGUSR1 和 SIGUSR2用户定义的信号默认处理方式是终止进程。84.ISO七层网络通信结构每层的主要作用主要的协议
ISO七层网络通信结构也称为OSIOpen Systems Interconnection模型是一个概念性的框架
用于描述网络通信中各个层次的功能和协议。每一层都有特定的作用和相关的协议。以下是各层的主要作用和主要的协议1. 物理层Physical Layer
主要作用负责传输原始比特流处理电压、物理介质、数据速率等物理特性。
主要协议RS-232、EthernetIEEE 802.3、USB、Bluetooth、Wi-FiIEEE 802.11。
2. 数据链路层Data Link Layer
主要作用将原始比特流组织成数据帧提供节点到节点的传输进行错误检测和纠正。
主要协议EthernetIEEE 802.3、PPPPoint-to-Point Protocol、HDLCHigh-Level Data Link Control、ARPAddress Resolution Protocol。
3. 网络层Network Layer
主要作用负责数据包的路由和转发实现端到端的传输处理逻辑地址如IP地址。
主要协议IPInternet Protocol、ICMPInternet Control Message Protocol、OSPFOpen Shortest Path First、BGPBorder Gateway Protocol。
4. 传输层Transport Layer
主要作用提供端到端的可靠数据传输服务进行流量控制和错误恢复。
主要协议TCPTransmission Control Protocol、UDPUser Datagram Protocol、SCTPStream Control Transmission Protocol。
5. 会话层Session Layer
主要作用建立、管理和终止会话通信连接进行会话控制和同步。
主要协议NetBIOS、RPCRemote Procedure Call、SSHSecure Shell。
6. 表示层Presentation Layer
主要作用处理数据格式转换、加密、压缩等确保数据在不同系统之间的正确解释。
主要协议SSL/TLSSecure Sockets Layer/Transport Layer Security、MIMEMultipurpose Internet Mail Extensions、ASCII、JPEG、MPEG。
7. 应用层Application Layer
主要作用提供网络服务和应用程序之间的接口直接与用户交互。
主要协议HTTPHypertext Transfer Protocol、FTPFile Transfer Protocol、SMTPSimple Mail Transfer Protocol、DNSDomain Name System、DHCPDynamic Host Configuration Protocol。85.TCP/IP四层网络通信结构
TCP/IPTransmission Control Protocol/Internet Protocol是互联网的核心协议套件它定义了数据如何在网络中传输和路由。TCP/IP模型是一个四层结构与OSI模型的七层结构有所不同。以下是TCP/IP四层模型的详细介绍1. 网络接口层Network Interface Layer
主要作用负责将数据帧发送到物理网络或从物理网络接收数据帧。这一层对应OSI模型的物理层和数据链路层。
主要协议EthernetIEEE 802.3、Wi-FiIEEE 802.11、PPPPoint-to-Point Protocol、ARPAddress Resolution Protocol。
2. 互联网层Internet Layer
主要作用负责数据包的路由和转发实现端到端的传输处理逻辑地址如IP地址。这一层对应OSI模型的网络层。
主要协议IPInternet Protocol包括IPv4和IPv6、ICMPInternet Control Message Protocol、IGMPInternet Group Management Protocol、OSPFOpen Shortest Path First、BGPBorder Gateway Protocol。
3. 传输层Transport Layer
主要作用提供端到端的可靠数据传输服务进行流量控制和错误恢复。这一层对应OSI模型的传输层。
主要协议TCPTransmission Control Protocol、UDPUser Datagram Protocol、SCTPStream Control Transmission Protocol。
4. 应用层Application Layer
主要作用提供网络服务和应用程序之间的接口直接与用户交互。这一层对应OSI模型的会话层、表示层和应用层。
主要协议HTTPHypertext Transfer Protocol、FTPFile Transfer Protocol、SMTPSimple Mail Transfer Protocol、DNSDomain Name System、DHCPDynamic Host Configuration Protocol、SNMPSimple Network Management Protocol、SSHSecure Shell、SSL/TLSSecure Sockets Layer/Transport Layer Security86.io模型有哪几种
I/O输入/输出模型是指计算机系统中用于处理输入和输出操作的机制。不同的I/O模型在处理数据传输和同步方式上有所不同。以下是几种常见的I/O模型1. 阻塞I/OBlocking I/O
原理当进程调用I/O操作时如果数据未准备好进程会被阻塞直到数据准备好并完成I/O操作后才继续执行。
优点简单易用适合简单的应用场景。
缺点效率低不适合高并发场景。
2. 非阻塞I/ONon-blocking I/O
原理当进程调用I/O操作时如果数据未准备好进程不会被阻塞而是立即返回一个错误码。进程需要不断轮询检查数据是否准备好。
优点避免了进程被长时间阻塞提高了并发处理能力。
缺点需要频繁轮询浪费CPU资源。
3. I/O多路复用I/O Multiplexing
原理使用select、poll、epoll等系统调用进程可以同时监听多个I/O事件。当某个I/O事件就绪时进程会被通知并进行处理。
优点高效处理多个I/O事件适合高并发场景。
缺点编程复杂度较高。
4. 信号驱动I/OSignal-driven I/O
原理进程注册一个信号处理函数当I/O事件就绪时内核发送一个信号通知进程。进程在信号处理函数中进行I/O操作。
优点避免了轮询提高了效率。
缺点信号处理函数的执行时间较短不适合复杂操作。
5. 异步I/OAsynchronous I/O
原理进程发起I/O操作后立即返回不等待I/O操作完成。I/O操作完成后内核通知进程。
优点真正实现了异步处理提高了并发性能。
缺点编程复杂度高操作系统支持有限。87.如何实现并发服务器并发服务器的实现方式以及有什么异同
并发服务器是指能够同时处理多个客户端请求的服务器。实现并发服务器的方式有多种主要包括多进程、多线程、I/O多路复用和异步I/O等。以下是这些实现方式的详细介绍及其异同点1. 多进程Multi-process
实现方式服务器主进程接受客户端连接并为每个连接创建一个子进程来处理请求。
优点进程之间相互独立稳定性高适合处理计算密集型任务。
缺点进程创建和销毁开销大资源消耗多不适合高并发场景。2. 多线程Multi-thread
实现方式服务器主线程接受客户端连接并为每个连接创建一个子线程来处理请求。
优点线程创建和销毁开销小资源消耗少适合处理I/O密集型任务。
缺点线程之间共享内存需要考虑同步和互斥问题容易引发竞态条件。3. I/O多路复用I/O Multiplexing
实现方式使用select、poll、epoll等系统调用服务器可以同时监听多个I/O事件。当某个I/O事件就绪时服务器进行处理。
优点单线程或单进程即可处理多个连接资源消耗少适合高并发场景。
缺点编程复杂度较高需要处理事件驱动的逻辑。4. 异步I/OAsynchronous I/O
实现方式服务器发起I/O操作后立即返回不等待I/O操作完成。I/O操作完成后内核通知服务器进行处理。
优点真正实现了异步处理提高了并发性能适合高并发场景。
缺点编程复杂度高操作系统支持有限。异同点资源消耗多进程消耗资源最多多线程次之I/O多路复用和异步I/O消耗资源最少。
编程复杂度多进程和多线程相对简单I/O多路复用和异步I/O编程复杂度较高。
并发处理能力I/O多路复用和异步I/O的并发处理能力最强多进程和多线程次之。
适用场景多进程适合计算密集型任务多线程适合I/O密集型任务I/O多路复用和异步I/O适合高并发场景。88.网络超时检测的本质和实现方式
网络超时检测的本质是在网络通信中设置一个合理的时间阈值如果在该时间内没有收到预期的响应或完成预期的操作则认为发生了超时事件。超时检测的目的是确保网络通信的可靠性和效率避免因长时间等待响应而导致的资源浪费和性能下降。实现方式
网络超时检测可以通过多种方式实现以下是几种常见的实现方式1. 定时器Timer
原理在发起网络请求时启动一个定时器如果在定时器到期前没有收到响应则认为发生了超时。
实现可以使用操作系统的定时器机制如alarm、setitimer或编程语言提供的定时器功能如setTimeout、Timer。
2. 超时参数Timeout Parameter
原理在网络协议或API调用中设置超时参数指定等待响应的最大时间。如果在该时间内没有收到响应则认为发生了超时。
实现例如在HTTP请求中设置timeout参数或在数据库连接中设置connectTimeout和readTimeout。
3. 心跳检测Heartbeat Detection
原理在长连接或持续通信中定期发送心跳包Heartbeat Packet如果在一定时间内没有收到对方的心跳响应则认为连接超时。
实现例如在WebSocket连接中定期发送PING帧或在TCP连接中定期发送心跳包。
4. 重传机制Retransmission Mechanism
原理在网络协议中设置重传机制如果在一定时间内没有收到确认ACK则重新发送数据包。通过重传次数和重传间隔来间接实现超时检测。
实现例如在TCP协议中如果发送的数据包在一定时间内没有收到ACK则会触发重传。89.udp本地通信需要注意哪些方面
UDPUser Datagram Protocol是一种无连接的、不可靠的传输层协议
适用于对传输速度要求高、对数据可靠性要求相对较低的应用场景。
在使用UDP进行本地通信时需要注意以下几个方面1. 端口选择
选择未被占用的端口确保选择的本地端口未被其他应用程序占用避免端口冲突。
使用知名端口对于特定应用可以使用知名的端口号如DNS使用53端口但需要注意权限问题知名端口通常需要管理员权限。
2. 数据包大小
避免IP分片UDP数据包的大小应小于网络的最大传输单元MTU避免IP分片。通常建议UDP数据包大小不超过1472字节以太网MTU为1500字节减去20字节的IP头和8字节的UDP头。
考虑应用需求根据应用需求合理设置数据包大小避免过大或过小的数据包影响传输效率。
3. 错误检测
校验和UDP头部包含16位的校验和字段用于检测数据包在传输过程中是否发生错误。虽然UDP校验和是可选的但建议启用以提高数据可靠性。
应用层校验在应用层进行额外的错误检测和纠正如使用CRC循环冗余校验等。
4. 流量控制和拥塞控制
应用层实现UDP不提供内置的流量控制和拥塞控制机制需要在应用层实现相应的控制策略避免网络拥塞和数据丢失。
5. 安全性
数据加密对于敏感数据建议在应用层进行加密确保数据在传输过程中的安全性。
访问控制限制UDP通信的源地址和端口避免未授权访问。
6. 超时重传
应用层实现UDP不提供超时重传机制需要在应用层实现超时检测和重传策略确保数据的可靠传输。90.怎么修改文件描述符的标志位
文件描述符的标志位File Descriptor Flags用于控制文件描述符的行为。在Unix和类Unix系统中可以使用fcntl系统调用来修改文件描述符的标志位。fcntl函数提供了丰富的控制功能包括设置文件描述符的标志位。修改文件描述符标志位的步骤
打开文件使用open系统调用打开文件获取文件描述符。
获取当前标志位使用fcntl函数获取文件描述符的当前标志位。
修改标志位根据需要修改标志位。
设置新的标志位使用fcntl函数设置新的标志位。常用的文件描述符标志位
O_APPEND追加模式每次写操作前将文件指针移动到文件末尾。
O_NONBLOCK非阻塞模式读写操作不会阻塞。
O_ASYNC异步I/O当文件描述符可读或可写时发送信号通知进程。
91.TCP和UDP的区别
TCPTransmission Control Protocol和UDPUser Datagram Protocol是互联网协议族中的两个重要传输层协议
它们在数据传输方式、可靠性、连接状态等方面有显著的区别。以下是TCP和UDP的主要区别1. 连接状态
TCP面向连接的协议传输数据前需要建立连接三次握手传输完成后需要释放连接四次挥手。
UDP无连接的协议传输数据前不需要建立连接每个数据包都是独立的。
2. 可靠性
TCP提供可靠的数据传输服务确保数据按顺序、无丢失、无重复地到达目的地。通过确认机制、重传机制、流量控制和拥塞控制等机制实现可靠性。
UDP提供不可靠的数据传输服务不保证数据包的顺序、不重传丢失的数据包、不进行流量控制和拥塞控制。
3. 传输效率
TCP由于需要建立连接、维护连接状态、进行复杂的错误检测和恢复机制传输效率相对较低。
UDP由于没有连接建立和维护的开销传输效率较高适合对实时性要求高的应用。
4. 数据包大小
TCP没有数据包大小的限制数据以字节流的形式传输。
UDP每个数据包数据报有大小限制通常不超过65507字节以太网MTU为1500字节减去20字节的IP头和8字节的UDP头。
5. 头部开销
TCP头部开销较大通常为20字节加上可选字段最多可达60字节。
UDP头部开销较小固定为8字节。
6. 适用场景
TCP适用于对数据可靠性要求高的应用如文件传输、电子邮件、网页浏览等。
UDP适用于对实时性要求高、对数据可靠性要求相对较低的应用如视频流、在线游戏、VoIPVoice over IP等。92.TCP的三次握手和四次挥手分别作用主要做什么
TCPTransmission Control Protocol是一种面向连接的、可靠的传输层协议。为了确保数据传输的可靠性和连接的建立与释放TCP使用了三次握手Three-way Handshake和四次挥手Four-way Handshake机制。三次握手Three-way Handshake
三次握手用于在客户端和服务器之间建立连接。其主要作用是确保双方都准备好进行数据传输并且同步初始序列号ISN。具体步骤
SYNSynchronize Sequence Number客户端向服务器发送一个SYN包请求建立连接并包含一个初始序列号ISN。
SYN-ACKSynchronize-Acknowledge服务器收到SYN包后向客户端发送一个SYN-ACK包确认收到客户端的请求并包含服务器自己的初始序列号ISN。
ACKAcknowledge客户端收到SYN-ACK包后向服务器发送一个ACK包确认收到服务器的响应并进入连接建立状态。主要作用
同步序列号双方通过交换初始序列号确保数据传输的顺序和可靠性。
确认双方准备就绪通过三次握手双方确认对方已经准备好进行数据传输。四次挥手Four-way Handshake
四次挥手用于在客户端和服务器之间释放连接。其主要作用是确保双方都完成数据传输并安全地关闭连接。具体步骤
FINFinish主动关闭方通常是客户端向被动关闭方通常是服务器发送一个FIN包请求关闭连接。
ACKAcknowledge被动关闭方收到FIN包后向主动关闭方发送一个ACK包确认收到关闭请求并进入半关闭状态被动关闭方仍然可以发送数据。
FINFinish被动关闭方完成数据传输后向主动关闭方发送一个FIN包请求关闭连接。
ACKAcknowledge主动关闭方收到FIN包后向被动关闭方发送一个ACK包确认收到关闭请求并进入TIME_WAIT状态。经过一段时间后连接完全关闭。主要作用
确保数据传输完成通过四次挥手双方确认对方已经完成数据传输。
安全关闭连接确保双方都同意关闭连接避免数据丢失或重复传输。三次握手
Client Server| ||---- SYN(ISN) ----|| ||--- SYN-ACK(ISN1) || ||---- ACK(ISN1) ---|| |四次挥手Client Server| ||---- FIN ---------|| ||--- ACK || || ||--- FIN || ||---- ACK ---------|| |
93.new、delete、malloc、free关系
new、delete、malloc和free是C和C语言中用于动态内存管理的函数和操作符。它们之间的关系和区别如下malloc 和 free
malloc是C语言中的一个标准库函数用于在堆上分配指定字节数的内存并返回指向该内存块的指针。malloc不会初始化内存返回的指针类型为void*需要显式转换为合适的类型。
free是C语言中的一个标准库函数用于释放由malloc、calloc或realloc分配的内存。释放后内存块可以被系统重新分配。new 和 delete
new是C中的一个操作符用于在堆上分配内存并调用对象的构造函数进行初始化。new返回指向分配内存的指针类型为对象类型。
delete是C中的一个操作符用于释放由new分配的内存并调用对象的析构函数进行清理。delete确保对象的析构函数被正确调用避免内存泄漏和资源泄漏。关系和区别内存分配和初始化
malloc只分配内存不进行初始化。
new不仅分配内存还调用对象的构造函数进行初始化内存释放和清理
free只释放内存不进行任何清理。
delete不仅释放内存还调用对象的析构函数进行清理。类型安全
malloc返回void*指针需要显式转换为合适的类型不进行类型检查。
new返回特定类型的指针进行类型检查确保类型安全。错误处理
malloc在内存分配失败时返回NULL。
new在内存分配失败时抛出std::bad_alloc异常。使用场景
malloc和free主要用于C语言和需要与C语言兼容的C代码。
new和delete主要用于C代码提供更高级的内存管理功能包括构造函数和析构函数的调用。94.delete与delete[]区别
在C中delete和delete[]是用于释放动态分配内存的操作符但它们有不同的用途和行为。以下是它们的区别delete用途用于释放由new操作符分配的单个对象的内存。行为调用单个对象的析构函数并释放该对象占用的内存。
delete[]用途用于释放由new[]操作符分配的数组内存。行为调用数组中每个对象的析构函数并释放整个数组占用的内存。区别析构函数调用delete只调用单个对象的析构函数。delete[]调用数组中每个对象的析构函数。
内存释放delete只释放单个对象占用的内存。delete[]释放整个数组占用的内存。95.C有哪些性质面向对象特点
C是一种多范式编程语言支持面向对象编程OOP、泛型编程和过程式编程。C的面向对象特点主要包括以下几个方面1. 封装Encapsulation
定义将数据属性和操作数据的方法行为绑定在一起形成一个类Class并通过访问控制符如public、private、protected隐藏内部实现细节只暴露必要的接口。
优点提高代码的可维护性和可重用性减少外部对内部数据的直接访问增强安全性。
2. 继承Inheritance
定义允许一个类派生类继承另一个类基类的属性和方法从而实现代码的复用和扩展。
优点减少代码冗余提高代码的可扩展性和可维护性。
类型单继承、多继承C支持但需谨慎使用、多层继承。
3. 多态Polymorphism
定义同一操作作用于不同的对象可以有不同的解释产生不同的执行结果。多态性分为编译时多态静态多态如函数重载和运算符重载和运行时多态动态多态如虚函数。
优点提高代码的灵活性和可扩展性使代码更易于维护和扩展。
实现通过虚函数Virtual Function和抽象类Abstract Class实现运行时多态。
4. 抽象Abstraction
定义将复杂的事物简单化隐藏不必要的细节只关注关键的属性和行为。抽象可以通过类和接口纯虚函数来实现。
优点提高代码的可读性和可维护性使设计更加清晰和模块化。
5. 构造函数和析构函数
构造函数用于初始化对象在对象创建时自动调用。
析构函数用于清理对象在对象销毁时自动调用。
6. 友元Friend
定义允许特定的函数或类访问另一个类的私有成员。
优点在某些情况下提供了一种灵活的访问控制机制。
7. 运算符重载Operator Overloading
定义允许用户定义的类型如类重新定义或重载运算符的行为。
优点使自定义类型的操作更加直观和符合习惯。96.子类析构时要调用父类的析构函数吗
在C中子类的析构函数在执行时会自动调用父类的析构函数。
这是C语言的特性确保在子类对象销毁时父类的资源也能被正确释放。析构函数的调用顺序
1.子类析构函数首先调用子类的析构函数清理子类特有的资源。
2.父类析构函数然后自动调用父类的析构函数清理父类的资源。97.多态虚函数纯虚函数
多态Polymorphism、虚函数Virtual Function和纯虚函数Pure Virtual Function是C中面向对象编程的三个重要概念它们共同支持运行时多态性使得代码更加灵活和可扩展。多态Polymorphism
定义多态是指同一操作作用于不同的对象可以有不同的解释产生不同的执行结果。多态性分为编译时多态静态多态和运行时多态动态多态。
静态多态通过函数重载Function Overloading和运算符重载Operator Overloading实现在编译时确定。
动态多态通过虚函数Virtual Function实现在运行时确定。虚函数Virtual Function
定义虚函数是在基类中使用virtual关键字声明的函数允许在派生类中重写Override。通过基类指针或引用调用虚函数时实际调用的是派生类中的重写版本从而实现运行时多态。
特点
虚函数在基类中声明可以在派生类中重写。
通过基类指针或引用调用虚函数时实际调用的是派生类中的版本。
虚函数在基类中必须有定义即使派生类不重写它。纯虚函数Pure Virtual Function
定义纯虚函数是在基类中声明的虚函数但没有实现通过在函数声明后加上 0来表示。包含纯虚函数的类称为抽象类Abstract Class不能直接实例化只能用作基类。
特点
纯虚函数在基类中没有实现必须在派生类中重写。
包含纯虚函数的类是抽象类不能直接实例化。
纯虚函数提供了一个接口规范强制派生类实现该函数。98.什么是“引用”申明和使用“引用”要注意哪些问题
引用Reference是C中的一种别名机制用于提供对现有变量的直接访问。
引用在声明时必须初始化且一旦初始化后不能重新绑定到其他变量。使用引用时需要注意以下几点
初始化引用必须在声明时初始化。
不能为空引用不能为空必须始终指向有效的对象或函数。
不能重新绑定引用一旦初始化后不能指向其他变量。
常量引用常量引用可以绑定到临时对象或常量但不能通过常量引用修改原始对象的值。
函数参数和返回值引用常用作函数参数和返回值以避免拷贝开销并提供更好的接口。
99.将“引用”作为函数参数有哪些特点
1. 避免拷贝开销
特点引用作为函数参数时不会创建参数的副本而是直接操作原始对象。这对于大型对象或复杂结构尤其重要因为拷贝这些对象可能会带来显著的性能开销。
2. 提供更好的接口
特点引用参数使得函数调用更加直观调用者可以清晰地看到参数可能会被修改。这增强了代码的可读性和可维护性因为调用者可以立即知道哪些参数可能会在函数内部被改变。
3. 支持修改原始对象
特点通过引用参数函数可以直接修改调用者传入的原始对象而不需要返回值。这使得函数能够以更自然的方式影响调用者的状态而不需要复杂的返回值处理。
4. 常量引用用于保护原始对象
特点使用常量引用const 可以避免修改原始对象同时避免拷贝开销。这对于只需要读取而不需要修改参数的函数特别有用因为它既保证了参数的安全性又提高了性能。
5. 支持多态
特点通过基类引用可以实现运行时多态调用派生类的重写方法。这使得函数能够处理不同类型的对象只要这些对象继承自同一个基类并且重写了相关的方法。100.在什么时候需要使用“常引用”
1. 避免拷贝开销
场景当函数需要传递大型对象或复杂结构时为了避免拷贝开销可以使用常引用。
原因常引用不会创建参数的副本直接操作原始对象从而提高性能。
2. 保护原始对象不被修改
场景当函数只需要读取参数的值而不需要修改它时使用常引用可以防止意外修改。
原因常引用确保函数内部不能修改参数增强了代码的安全性和可维护性。
3. 传递临时对象
场景当函数需要接受临时对象如字面量或表达式结果作为参数时常引用是唯一的选择。
原因临时对象不能绑定到非常量引用但可以绑定到常量引用。
4. 支持多态
场景当函数需要通过基类引用实现运行时多态时常引用可以确保基类对象不被修改。
原因常引用结合虚函数可以实现安全的运行时多态同时保护基类对象不被修改。