嵌入式面试知识点——海康2020年笔试

在这里插入图片描述
答案:B
这句话是不对的,堆分配的内存速度比栈慢,而且容易产生内存碎片。
栈分配的内存速度比堆快,因为栈由操作系统自动分配和释放,有专门的寄存器和指令来操作,而堆由程序员手动申请和释放,需要调用库函数或运算符,实现机制较为复杂。
堆分配的内存容易产生内存碎片,因为堆是不连续的内存区域,当频繁地申请和释放不同小的内存时,就会导致空闲内存分散成许多小块,无法满足大块内存的需求。 栈分配的内存不会产生内存碎片,因为栈是连续的内存区域,栈顶指针只能向一个方向移动,所以不会出现空闲内存碎片。

在这里插入图片描述
答案:A
为避免死锁,尽量用信号量替代互斥锁使用。这个问题的答案并不是一定的,因为信号量和互斥锁各有优缺点,适用于不同的场景。死锁的产生是由于多个线程同时请求一组资源,而每个线程都持有其中一部分资源,并等待其他线程释放资源,从而形成一个循环等待的状态。

要避免死锁,一般有以下几种方法:
破坏互斥条件:即允许多个线程同时访问共享资源,但这可能会导致数据不一致或者竞态条件的问题。
破坏占有且等待条件:即要求线程在申请资源时必须一次性申请所有需要的资源,而不是分阶段申请,但这可能会导致资源的浪费或者饥饿现象。
破坏不可抢占条件:即允许操作系统或者其他线程强制收回已经分配给某个线程的资源,但这可能会导致数据丢失或者不完整。
破坏环路等待条件:即规定所有线程申请资源的顺序必须一致,或者对所有资源进行编号,并要求线程按照编号的升序申请资源,但这可能会增加编程的复杂度和开销。
信号量和互斥锁都可以用来实现线程间的同步和互斥,但它们有以下区别34:

信号量是一个非负整数,表示可用的资源数量,可以被多个线程同时获取和释放;互斥锁是一个布尔值,表示资源是否被占用,只能被一个线程获取和释放。

信号量可以实现多个同类资源的多线程互斥和同步;互斥锁只能实现一个资源的互斥访问。
信号量可以由一个线程释放,另一个线程获取;互斥锁必须由同一个线程获取和释放。
因此,并不是说信号量就比互斥锁更好,而是要根据具体的需求和场景来选择合适的工具。如果只需要保证一个资源的互斥访问,那么使用互斥锁可能更简单和高效;如果需要实现多个同类资源的多线程互斥和同步,或者需要实现生产者消费者模式等复杂的逻辑,那么使用信号量可能更灵活和强大。

在这里插入图片描述
答案:C
顺序结构的顺序存取:把逻辑上连续的文件信息依次存放在连续编号的物理块中,只要知道文件的起始地址和长度,就能很快地进行存取。这种方式的优点是访问速度快,缺点是文件长度增加困难。
链接结构的顺序存取:把逻辑上连续的文件分散存放在若干不连续的物理块中,每个物理块设有一个指针,指向其后续的物理块。这种方式的优点是文件动态扩展容易,缺点是只能顺序存取,效率低
索引结构的顺序存取:为每个文件建立一个索引表,记录文件各个逻辑块在物理块中的位置。这种方式的优点是既适合顺序存取,也适合随机存取,缺点是需要占用一定的索引空间。
hash结构的顺序存取:为每个文件建立一个hash表,根据记录的关键字计算出其在物理块中的位置。这种方式的优点是随机存取效率高,缺点是不适合顺序存取,因为记录在物理块中可能是无序或者分散的。
因此,可以看出,只有链接结构是只能顺序存取的文件物理结构。其他三种结构都可以支持随机存取。

在这里插入图片描述
答案:A

因为有新进程进入就绪状态并不一定会导致操作系统立即选择新进程运行,而是要看当前运行的进程是否需要被剥夺或者阻塞。而其他三个选项都是引起操作系统选择新进程的直接原因,因为它们都会使当前运行的进程放弃或者失去处理机。

在这里插入图片描述
答案:B
因为SCHED_OTHER是Linux系统中默认的分时调度策略,它是基于动态优先级来分配CPU时间片给每个进程的。而其他三个选项都是实时调度策略,它们是基于静态优先级来分配CPU资源给每个进程的。实时调度策略的优先级高于分时调度策略,它们适用于对响应时间和实时性有严格要求的场景。

在这里插入图片描述

答案:B
因为在一个函数内复合语句中定义的变量,其作用域只限于该复合语句,也就是说,只有在该复合语句内部才能访问该变量,而不是在整个函数范围内都有。其他三个选项都是正确的,因为:

在不同的函数中可以使用相同名字的变量,这些变量属于不同的作用域,互不干扰。
在一个函数内定义的变量只在本函数范围内有效,这些变量属于局部变量,其生存期和作用域都与函数绑定。
函数中的形式参数是在栈中保存,这些参数属于动态存储方式,每次函数调用时都会分配和释放相应的空间。

在这里插入图片描述
答案:D
因为选项D中,cpi是一个指向int类型的常量指针,它不能指向一个const int类型的变量ic,这样会造成类型不匹配的错误。

在这里插入图片描述
答案:C
#运算符用于将宏参数转换为字符串字面量,即在参数两边加上双引号。
##运算符用于将两个宏参数或者一个宏参数和一个标识符连接成一个新的标识符。

str(inter) 展开是“inter”
name_y(1) 展示是name_1
adjoin(hik) 展开是 -> name_y ->name_hik

因此,最终的结果是:
“inter”, name_ 1, name_ hik

在这里插入图片描述
答案:C
因为当malloc(0)返回一个具体的内存值时,ptr占用的内存栈空间虽然不能被使用,但可以被释放。

选项A中,malloc(0)可能返回一个具体的内存值,这取决于具体的实现方式。
选项B中,当返回具体内存值时,ptr占用一定的内存空间,这是因为malloc函数会在堆上分配一块大小为0的内存,并返回其地址。
选项D中,malloc(0)可能返回NULL,这也取决于具体的实现方式 。

在这里插入图片描述
答案:1,1,9

在这里插入图片描述
答案:A
选项B中的IP地址是一个广播地址,它属于C类地址,其网络号为192.168.1,主机号为255。广播地址用于向同一网络中的所有主机发送信息,不能分配给单个主机。

选项C中的IP地址是一个网络地址,它属于C类地址,其网络号为220.224.25,主机号为0。网络地址用于标识一个网络的范围,不能分配给单个主机。

选项D中的IP地址是一个回环地址,它属于A类地址,其网络号为127,主机号为0.0.1。回环地址用于测试本地主机的网络连接和软件功能,不能分配给其他主机。

在这里插入图片描述
答案:B

在这里插入图片描述
答案:C
因为对于一个没有设置任何套接字选项的阻塞套接字,调用recv函数时,它会一直等待对方发送数据,直到收到数据或者发生错误为止。
如果对方在发送数据前突然断电,那么这就相当于对方主动关闭了连接,但是没有发送任何关闭通知给本地主机。这种情况下,本地主机无法立即知道对方已经断开,只能通过TCP的超时和重传机制来检测到连接的异常。这个过程可能需要很长一段时间,取决于具体的网络环境和TCP参数 。当TCP最终判断连接已经失效时,它会向应用层返回一个错误码,通常是WSAECONNRESET或者WSAETIMEDOUT 。这时recv函数就会返回-1,并且可以通过WSAGetLastError函数来获取具体的错误原因。

选项A中,recv永远不会返回是不可能的,因为TCP总有一个超时时间,无论多长,它总会在超时后放弃重传并报告错误。

选项B中,recv立刻返回0是不正确的,因为recv函数只有在收到对方发送的正常关闭通知时才会返回0 。如果对方突然断电,那么本地主机就无法收到这样的通知。

选项D中,recv立刻返回-1也是不正确的,因为recv函数只有在发生本地错误或者已经知道对方异常关闭时才会立刻返回-1 。如果对方突然断电,那么本地主机需要一定的时间才能检测到这种情况。

.答案:A、B、D

int main(int argc, char *argv[])
int main()

其中,argc表示命令行参数的个数,argv表示命令行参数的字符串数组,它们都是main函数的参数。另外,还有一种特定于Microsoft的扩展形式:
int main(int argc, char *argv[], char *envp[])
其中,envp表示环境变量的字符串数组,它也是main函数的参数。

而选项C中的main不是main函数的参数,而是main函数本身。

在这里插入图片描述
答案:A、B、D

选项A中,函数中变长数组的长度值一旦确定,其值在函数生命周期结束前都不会改变,这是正确的。因为变长数组不是动态数组,它不能在运行时改变大小,它只能在声明时使用变量或表达式来指定长度。

选项B中,避免数组长度值过大引起栈溢出,这是正确的。因为变长数组是在栈上分配内存的,如果数组长度过大,可能会超出栈的容量,导致程序崩溃或者数据损坏。所以在使用变长数组时,要注意控制数组长度的合理范围。

选项C中,变长数组可以在任何函数中使用,这是错误的。因为变长数组只能在局部作用域中使用,也就是说只能在函数内部定义和使用。如果要在全局作用域中使用变长数组,就必须使用动态内存分配的方法,比如malloc或calloc函数。

选项D中,变长数组在使用时先判断一个初步的长度范围,这是正确的。因为变长数组在声明时需要确定长度,所以在使用之前要有一个大致的估计,以便合理地分配内存空间。如果长度不确定或者可能发生较大变化,就不适合使用变长数组。

在这里插入图片描述
答案:A、B、C
选项A中,确定性是指算法中每一条指令都有确切的含义,不会产生二义性或者不确定性。算法对于特定的输入,其输出是唯一确定的。

选项B中,可行性是指算法中的每一步都是可行的,也就是说都能够在有限的时间内完成,并且能够用已经实现的基本操作来实现。

选项C中,有穷性是指算法必须在执行有限步之后结束,不会出现无限循环或者无法终止的情况。

选项D中,鲁棒性是指算法能够应对各种异常或者错误的情况,保证程序的稳定性和安全性。但这并不是算法本身必须具备的特性,而是算法设计和实现时应该考虑到的因素。

算法的五大特征:有穷性、确定性、可行性、输入、输出

在这里插入图片描述
答案:A、B、D
程序的三种基本控制结构是:
顺序结构:程序按照语句的出现顺序依次执行,没有任何跳转或分支。
选择结构:程序根据某个条件的真假,选择执行不同的语句或语句块。常见的选择结构有if语句和switch语句。
循环结构:程序重复执行某个语句或语句块,直到满足某个终止条件。常见的循环结构有for语句、while语句和do-while语句

在这里插入图片描述
答案:A、B、D
应用层协议是位于TCP/IP模型最高层的协议,它为应用程序提供网络接口,直接向用户提供服务。应用层协议有很多种,例如:

DNS(域名系统):把网络节点的易于记忆的名字转化为网络地址。
HTTP(超文本传输协议):支持Web浏览器和Web服务器之间的文本、图像、音频、视频等数据的传输。
SMTP(简单邮件传输协议):支持文本邮件的Internet传输。
FTP(文件传输协议):支持文件在不同主机之间的传输。
Telnet(远程登录协议):支持用户从一台主机登录到另一台主机,并执行命令。

因此,A、B和D都是应用层协议,而C不是。C是TCP(传输控制协议),它是位于传输层的协议,它为应用层提供可靠的面向连接的通信服务。

在这里插入图片描述
校验和:通过计算TCP首部、数据和伪首部的检验和,接收端可以检测出数据是否有差错或异常,如果有则丢弃数据并请求重传。

序列号和确认应答:TCP为每个字节的数据都分配一个序列号,发送端在发送数据后,会等待接收端的确认应答(ACK)报文,其中包含下一个期望接收的序列号。如果发送端没有收到ACK报文或收到重复的ACK报文,就会认为数据丢失或乱序,从而重发数据。

超时重传:TCP设置了一个超时时间,在发送数据后,如果超过这个时间还没有收到ACK报文,就会认为数据丢失,并重新发送数据。这个超时时间是动态计算的,根据网络的往返时间(RTT)和抖动(方差)来调整。

连接管理:TCP在传输数据之前,会先建立一个连接,通过三次握手来同步双方的序列号和窗口大小,并交换一些选项。在传输数据结束后,会通过四次挥手来断开连接,并释放资源。

流量控制:TCP通过滑动窗口机制来控制发送端的发送速度,使之不超过接收端的处理能力。接收端会在ACK报文中反馈自己的窗口大小,即缓冲区的剩余空间。发送端会根据窗口大小来调整发送的数据量。

拥塞控制:TCP通过慢启动、拥塞避免、快速重传和快速恢复等算法来控制网络的拥塞程度,避免因为过多的数据导致网络负载过大和丢包率增高。TCP维护了一个拥塞窗口,用来限制在网络中未被确认的数据量。拥塞窗口会根据网络状况动态变化。

在这里插入图片描述答案:
局部变量:static关键词可以修饰函数内部的局部变量,使其具有静态存储类别,即在程序运行期间一直存在,而不是每次进入和退出函数时被创建和销毁。这样的局部变量只能在定义它的函数内部访问,但它的值会保留到下一次调用该函数。static修饰的局部变量可以实现函数内部的状态保存,也可以避免全局变量的命名冲突。
全局变量:static关键词可以修饰文件外部的全局变量,使其具有内部链接属性,即只能在定义它的文件内部访问,而不能被其他文件引用。这样的全局变量可以实现文件内部的数据封装,也可以避免不同文件之间的全局变量的命名冲突。
函数:static关键词可以修饰文件外部的函数,使其具有内部链接属性,即只能在定义它的文件内部调用,而不能被其他文件调用。这样的函数可以实现文件内部的功能封装,也可以避免不同文件之间的函数名的命名冲突。

在这里插入图片描述
单链表节点Link的定义:单链表是一种线性表的链式存储结构,每个节点包含一个数据域和一个指针域,指针域指向下一个节点。在C语言中,可以用结构体来定义单链表节点的类型:

typedef struct Link {
    int elem; //数据域,存放数据元素
    struct Link *next; //指针域,指向下一个节点
} Link; //Link为节点名,每个节点都是一个Link结构体

单链表节点的插入:单链表节点的插入操作是在指定位置插入一个新的节点,使得新节点成为该位置的元素,原来的元素及其后续元素后移一位。插入操作需要找到插入位置的前一个节点,并修改其指针域。例如,定义一个函数link *insertElem(link *p, int elem, int add),表示在单链表p中第add个位置插入元素elem,并返回插入后的链表头指针。函数的实现如下:

link *insertElem(link *p, int elem, int add) {
    link *temp = p; //创建临时节点temp,用于遍历链表
    //首先找到要插入位置的前一个节点
    for (int i = 1; i < add; i++) {
        if (temp == NULL) {
            printf("插入位置无效\n");
            return p;
        }
        temp = temp->next;
    }
    //创建插入节点c
    link *c = (link *)malloc(sizeof(link)); //为插入节点分配空间
    c->elem = elem; //设置插入节点的数据域
    //向链表中插入节点
    c->next = temp->next; //将插入节点的指针域指向原来的第add个节点
    temp->next = c; //将前一个节点的指针域指向插入节点
    return p; //返回链表头指针
}

单链表节点的查询:单链表节点的查询操作是在单链表中查找是否存在某个元素,并返回其位置。查询操作需要遍历链表,并比较每个节点的数据域。例如,定义一个函数int findElem(link *p, int elem),表示在单链表p中查找元素elem,并返回其位置(从1开始),如果不存在则返回-1。函数的实现如下:

link *insertElem(link *p, int elem, int add) {
    link *temp = p; //创建临时节点temp,用于遍历链表
    //首先找到要插入位置的前一个节点
    for (int i = 1; i < add; i++) {
        if (temp == NULL) {
            printf("插入位置无效\n");
            return p;
        }
        temp = temp->next;
    }
    //创建插入节点c
    link *c = (link *)malloc(sizeof(link)); //为插入节点分配空间
    c->elem = elem; //设置插入节点的数据域
    //向链表中插入节点
    c->next = temp->next; //将插入节点的指针域指向原来的第add个节点
    temp->next = c; //将前一个节点的指针域指向插入节点
    return p; //返回链表头指针
}

单链表节点的删除:单链表节点的删除操作是在单链表中删除指定位置的元素,并释放其空间。删除操作需要找到删除位置的前一个节点,并修改其指针域。例如,定义一个函数link *delElem(link *p, int add),表示在单链表p中删除第add个位置的元素,并返回删除后的链表头指针。函数的实现如下:

link *delElem(link *p, int add) {
    link *temp = p; //创建临时节点temp,用于遍历链表
    //首先找到要删除位置的前一个节点
    for (int i = 1; i < add; i++) {
        temp = temp->next;
    }
    link *del = temp->next; //单独设置一个指针指向要删除的节点,以防丢失
    temp->next = temp->next->next; //将前一个节点的指针域指向删除节点的下一个节点,即跳过删除节点
    free(del); //手动释放删除节点的空间,防止内存泄漏
    return p; //返回链表头指针
}
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Asita_c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值