面试题4附加答案

来源:互联网 发布:问答系统源码 编辑:程序博客网 时间:2024/06/05 06:50

试卷四

一、填空选择题

1、请写出 float x 与“零值”比较的 if 语句   const float EPSINON = 0.00001;

                                   if ((x >= - EPSINON) && (x <= EPSINON)                                

解析:float是浮点数,不能用==,要用<和>配合一个接近0的数比较。

 

2、写出输出结果___________________________段错误________________________

char* s = “AAA”;

printf(“%s”, s);

s[0] = 'B';

printf(“%s”, s);

解析:因为printf是行缓冲,所以第一个没有回车符,所以没有进行输出AAA,段错误的原因,s只是一个指针,没有被分配空间,对没有分配的空间的操作;

 

3、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题):

       #define SEC (365*24*60*60)UL  

  解析:  一个常数的定义,但是由于这个常数是一个无符号长整型;所以最后加一个UL

 

4、下面程序的输出结果是多少____250_______//0xfa_____

#include <stdio.h>

 

int main()

{

unsigned char a = 0xA5;

unsigned char b = ~ a >> 4 + 1;

printf(“b = %d\n”, b);

return 0;

}

 

解析:具体的失误的原因,主要对于这些的操作的优先级的顺序不知道。这里面,应该,先加,然后然后移位,最后才是取反;

 

5、(多选)在多重处理系统中,处理死锁的办法有两种:一是防止其发生;二是发生后进行处理。下面的方法属于防止其发生的是哪一个?________bc_____

A、破坏互斥条件

B、破坏不可剥夺条件

C、破坏循环等待条件

D、杀死某个激活死锁的进程

解析:所谓死锁,是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面。很显然,如果没有外力的作用,那麽死锁涉及到的各个进程都将永远处于封锁状态。

 

产生死锁的4个必要条件是:

 

互斥条件:即某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有。如打印机。

 

不可抢占条件:进程所获得的资源在未使用完毕之前,资源申请者不能强行地从资源占有者手中夺取资源,而只能由该资源的占有者进程自行释放。

 

占有且申请条件:进程至少已经占有一个资源,但又申请新的资源;由于该资源已被另外进程占有,此时该进程阻塞;但是,它在等待新资源之时,仍继续占用已占有的资源。

 

循环等待条件:存在一个进程等待序列{P1,P2,…,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一源,……,而Pn等待P1所占有的的某一资源,形成一个进程循环等待环。

 

根据产生死锁的4个必要条件,只要使其中之一不能成立,死锁就不会出现。

 

为此,可采用下列3种预防措施:

 

采用资源静态分配策略,破坏“部分分配”条件;

允许进程剥夺使用其他进程占有的资源,从而破坏“不可剥夺”条件;

采用资源有序分配法,破坏“环路”条件。

 

但注意一点:互斥条件无法被破坏。本题中A是无法做到的,B和C正确,D选项属于死锁事后处理操作,与题意不符合。

 

 

二、简答题

1、系统调用与库函数的区别?

 

 

Linux下对文件操作有两种方式:系统调用(system call)和库函数调用(Library functions)。系统调用实际上就是指最底层的一个调用,在linux程序设计里面就是底层调用的意思。面向的是硬件。而库函数调用则面向的是应用开发的,相当于应用程序的api,采用这样的方式有很多种原因,第一:双缓冲技术的实现。第二,可移植性。第三,底层调用本身的一些性能方面的缺陷。第四:让api也可以有了级别和专门的工作面向。

 

 

 

 

 

 

 

 

函数库调用

系统调用

在所有的ANSI C编译器版本中,C库函数是相同的

各个操作系统的系统调用是不同的

它调用函数库中的一段程序(或函数)

它调用系统内核的服务

与用户程序相联系

是操作系统的一个入口点

在用户地址空间执行

在内核地址空间执行

它的运行时间属于用户时间

它的运行时间属于系统时间

属于过程调用,调用开销较小

需要在用户空间和内核上下文环境间切换,开销较大

C函数库libc中有大约300个函数

UNIX中大约有90个系统调用

典型的C函数库调用:system fprintf malloc

典型的系统调用:chdir fork write brk

 

 

 

2、sizeof与strlen的区别

 

1.sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。

2.sizeof是算符,strlen是函数。

3.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾。

4.数组做sizeof的参数不退化,传递给strlen就退化为指针了。

5.大部分编译程序 在编译的时候就把sizeof计算过了 是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因

6.strlen的结果要在运行的时候才能计算出来,时用来计算字符串的长度,不是类型占内存的大小。

7.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。

8.当适用了于一个结构类型时或变量, sizeof 返回实际的大小,当适用一静态地空间数组, sizeof 归还全部数组的尺寸。sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸

9.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,

 

3、关键字register的用法及注意事项?

 

答:  修饰经常被访问的变量,它所修饰的变量,请求编译器的尽可能的将变量保存在cpu的寄存器中。这样有助于减少访存的时间

  有助于程序的效率。

  它所修饰的变量不能用&地址,因为&这个是取的是内存空间的的地址,但是register 修饰的的变量保存在寄存器里面。

  还有register只能修饰cpu能够接受的类型,例如cpu是不能进行浮点类型的计算。

   register修饰的是局部变量不能修饰全局变量,因为只有这个进程知道这个变量的在哪里保存着,而其它的进程不知这个

   变量保存的地方。

 

 

 

 

 

 

 

 

4、用联合体判断大小端,大端返回0,小端返回1

  union w

 {

 int a;

 char b;

  } u;

 

int bigorlittle(void)

{

     u.a = 1;

     return (n.b == 1);

}

 

 

 

 

 

 

5、TCP是如何保证数据可靠传输

 

1)应用数据被分割成TCP认为的最合适发送的数据块;

2)当TCP发出一个报文段后,就启动一个定时器,用来等待目的端确认收到这个报文段;若没能及时收到这个确认,TCP发送端将重新发送这个报文段(超时重传);

3)TCP收到一个发自TCP连接的另一端的数据后就将发送一个确认,不过这个确认不是立即就发送,而是要推迟几分之一秒后才发送;

4)TCP将保持它的首部和数据的检验和;(这是一个端到端的检验和,为了检验数据在传输过程中发生的错误;若检测到段的检验和有差错,TCP将丢弃和不确认收到此报文段并希望发端可以进行超时重传)

5)由于TCP报文段是作为IP数据报来传输的,又因为IP数据报的到达可能会失序,所以TCP报文段的到达也可能会失序;因此,有必要的话TCP会对收到的数据进行重新排序后交给应用层;

6)因为TCP报文段是作为IP数据报来传输的,并且IP数据报可能会发生重复,所以TCP的接收端必须丢弃掉重复的数据;

7)TCP提供流量控制;(因为TCP连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这一限制可以防止较快主机致使较慢主机的缓冲区溢出)


三、程序题

1、编程实现strstr

char * my_strstr(const *str, char * dst)

{

      int i =0;

      char* temp1 =str;

      char *temp2 =dst;

      char * temp3;

   

      if(dst ==NULL)

      {

          return NULL;

      }

     while ( (*temp1) != ‘\0’)

     {

          temp3= temp1;

          temp2 = dest;

          while(1)

          {

if( (*temp3 ) != (*temp2))

{

    break;

}

if((*temp2) == ‘\0’)

{

   return temp1;

}

temp2++;

temp3++;

          }

     }

   

    return NULL:

}

 

 

 

 

 

 

 

 

 

2、合并两个递增排序链表

struct node

{

int num;

struct node *next;

};

typedef struct node Node;

typedef Node * Link;

 

Link Merge(Link head1, Link head2)

{

     Node * temp1 =head1;

     Node *temp2 =head2;

     Node *temp3 = NULL;

     if(temp1 == NULL)

     {

       return temp2;

     }

      if(temp2 == NULL)

      {

          return temp1;

      }

      if(temp1->num> temp2->num)

      {

            temp3 = temp1;

             temp1= temp2;

             tmp2 =temp3;

      }

     while(temp1 !=  NULL)

     {

         if((temp1->num)< (temp2->num))

         {s

     temp3 = temp1->next ;

              temp1= temp2;

              temp2 = temp2->next;

              temp1->next->next =temp3;

              temp2= temp2->next;

              if(temp2 == NULL )

              {

                   break;

              }

              

         }

         else

         {

        temp1 = temp1->next;

         }

     }

      return temp1;

}

0 0
原创粉丝点击