杭州天丽笔试题

1.volatile关键字的作用,举三个应用实例。

一般说来,volatile用在如下的几个地方:

1、中断服务程序中修改的供其它程序检测的变量需要加volatile

2、多任务环境下各任务间共享的标志应该加volatile

3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;

2.定义一个返回值和参数都是函数指针的函数

typedef void (*p)(void)

p func(p p1);

或是:void (*) (void)  func( void (*) (void))

void (*func(void (*p) (void))(void);

3.内存中的大小端模式?

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。

4.排序算法有哪几种?用C实现冒泡排序

void sort(int arr[],int size){

//1.外层循环控制比较的轮数

//2.内层循环控制每轮比较的下标范围

int i=0,j=0;

for(i=0;i<size-1;i++){

for(j=0;j<size-i-1;j++){

    if(arr[j]>arr[j+1]){

      int temp=arr[j];

      arr[j]=arr[j+1];

      arr[j+1]=temp;

}

}

}

}

常用的排序算法

2.1冒泡排序

相邻位置之间元素的比较

1)算法流程

a.比较相邻位置的元素,如果左边的比右边的大,则交换两个元素的位置

b.针对每一对相邻位置的元素都重复上一步,从第一对到最后一对比较完毕

经过这一步,最后的元素就是这组数中的最大值

c.针对所有的元素重复以上步骤,每次对越来越少的元素进行比较,直到没有

可以交换的元素为止

2)算法评价

平均时间复杂度o(n^2),稳定,对样本的有序性比较敏感

2.2插入排序

1)算法的流程

a.从第一个元素起,假定这个元素已经有序

b.从第二个元素起,与已经有序的元素从后向前进行比较

c.如果左边的元素大于取出的元素,则将左边的元素赋值到下一个位置上

继续与有序的元素进行比较

d.如果左边的元素小于取出的元素,则将取出的元素插入到左边元素之后

e.重复以上步骤,直到处理完所有的元素

2)算法评价

平均时间复杂度o(n^2),稳定,对样本的有序性比较敏感,但是赋值的次数

比冒泡排序少,所以略优于冒泡排序

2.3选择排序算法

1)算法的流程

a.从第一数起依次取出所有元素,假定取出的元素是最小值,记录下标

b.使用假定的最小元素和后续元素依次进行比较,如果后续元素中有比

假定最小元素还小的元素,则重新记录下标,后续元素成为了假定的最小数

c.直到假定的最小元素和后续所有元素比较完毕,交互最新的最小元素和

开始假定的最小元素

d.重复上述过程,直到所有元素排序完毕

2)算法评价

平均时间复杂度o(n^2),不稳定,对样本的有序性不敏感,比较的次数的比较多

交换的次数比较少,一般情况下略优于冒泡排序

2.4快速排序

1)算法的流程

a.选择一个中间元素作为基准值,单独存储起来

b.依次分别使用左边元素和右边元素和基准值比较,将比基准值小的元素放在左边

将比基准值大或者相等的元素放在右边,

c.重复以上过程,直到两边元素的下标重合为止,将基准值放到重合的位置上,此时

比基准值小的元素已经到了基准值左边,比基准值大的元素已经在基准值的右边

d.用递归的方式对基准值左边和右边的元素分别进行分组排序

2)算法评价

平均时间复杂度o(NlogN)不稳定,如果每次分配都能做到均匀划分,这种情况的排序速度最快

5.ISR中断服务子程序的错误:

    ISR不能有返回值;

    ISR不能传递参数;

    ISR应该是短而高效的,在ISR中做浮点运算是不明智的;

    ISR中不应该有重入和性能上的问题,因此不应该使用printf()函数。

__interrupt double compute_area (double radius) 

{

    double area = PI * radius * radius;

    printf(" Area = %f", area);

    return area;

}

1)  ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。

2)  ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。

3)  在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额外的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。

此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。

4) 与第三点一脉相承,printf经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。

6.while(1) ,for(; ;),goto死循环用哪个?为什么

一般for(;;)性能更优

for(;;)  

{}  

这两个;; 空语句,编译器一般会优掉的,直接进入死循环

while(1)  

{}  

每循环一次都要判断常量1是不是等于零,在这里whilefor多做了这点事

不过从汇编的角度来说,都是一样的代码。

goto语句通常不用,主要因为它将使程序层次不清,且不易读,但在多层嵌套退出时,用goto语句则比较合理。

7.抢占式内核和非抢占式内核?

内核抢占(可抢占式内核):

即当进程位于内核空间时,有一个更高优先级的任务出现时,如果当前内核允许抢占,则可以将当前任务挂起,执行优先级更高的进程。

非抢占式内核:

高优先级的进程不能中止正在内核中运行的低优先级的进程而抢占CPU运行。进程一旦处于核心态(例如用户进程执行系统调用),则除非进程自愿放弃CPU,否则该进程将一直运行下去,直至完成或退出内核。

抢占式内核的意义:

首先,这是将Linux应用于实时系统所必需的。实时系统对响应时间有严格的限定,当一个实时进程被实时设备的硬件中断唤醒后,它应在限定的时间内被调度执行。而Linux不能满足这一要求,因为Linux的内核是不可抢占的,不能确定系统在内核中的停留时间。事实上当内核执行长的系统调用时,实时进程要等到内核中运行的进程退出内核才能被调度,由此产生的响应延迟,在如今的硬件条件下,会长达100ms级。这对于那些要求高实时响应的系统是不能接受的。而可抢占的内核不仅对Linux的实时应用至关重要,而且能解决Linux对多媒体(video, audio)等要求低延迟的应用支持不够好的缺陷。

原文地址:https://www.cnblogs.com/guozhijiang/p/4821757.html