基础-笔试题6

1、tcp/udp是属于哪一层?tcp/udp有何优缺点?

tcp /udp属于运输层
TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
 与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。
 tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
 udp: 不提供稳定的服务,包头小,开销小

2、分析下方代码(数值溢出和强转)

char a = 100;   char b =  150;//10010110 //01101010 
unsigned char c ;
      c = (a < b)? a:b; 
则c的数值=___  , 

答:c=150 ; 
 被赋值为 150,这超出了 char 的正数范围,因为char通常只能存储-128到127之间的值(150 对应的二进制是 10010110,但存储在 char 中时,它会被解释为 -106 的二进制表示,即 10010110);所以a<b的判断为假,c=b;所以c=150(由于 c 是无符号的,所以 -106 会被转换为无符号整数对应的值。在8位无符号整数中,这将是 256 - 106 = 150

3、在C语言中memcpy和memmove是一样的吗?

 memmove()与memcpy()一样都是用来拷贝src所指向内存内容前n个字节到dest所指的地址上;
不同是,当src和dest所指的内存区域重叠时,memmove()仍然可以正确处理,不过执行效率上略慢些。

4、C语言程序代码优化方法

  1.   * 选择合适的算法和数据结构
  2.   * 使用尽量小的数据类型
  3.   * 使用自加、自减指令
  4.   * 减少运算的强度

   求余运算(a=a%8改为a=a&7)
   平方运算(a=pow(a,2.0)改为a=a*a)
   用移位实现乘除法运算
  * 延时函数的自加改为自减
  * switch语句中根据发生频率来进行case排序

5、找出一个字符串中一个最长的连续的数字,并标注出位置和个数。

 答:

void main()  
  {
  char input[100];  
  char output[100] = {0};
  int  count = 0, maxlen = 0, i = 0;
  char *in=input, *out=output,*temp=NULL,*final=NULL;
  
  printf("Please input string(length under 100):\n");
  scanf("%s", input);
  printf("Input string is %s\n", input);

  while(*in!='\0')
  {
    if(*in>='0'&&*in<='9')
    {
      count=0;
      temp=in;
      for(;(*in>='0')&&(*in<='9');in++)
     count++;
      if (maxlen<count)
      {
     maxlen=count;
     =temp;   
      } 
    } 
    in++;
  } 

  for(i=0; i<maxlen; i++)
  *(out++) = *(final++);
  *out='\0';

  printf("Maxlen is %d\n", maxlen);
  printf("Output is %s\n", output);
}

6、写出螺旋矩阵

                                    
                                              螺旋矩阵 
答:该代码段是一个C语言函数,用于创建一个顺时针螺旋矩阵。函数接受两个整数参数 m 和 n,分别表示矩阵的行数和列数。矩阵的大小是 m x n,元素值从1开始递增填充。算出螺旋矩阵的“半径” k =  small / 2,其中 small 是 m 和 n 中的较小值

 void Matrix(int m,int n)  //顺时针
 {
  int i,j,a=1;
  int s[100][100];
  int small = (m<n)?m:n;
  int k=small/2;
  for(i=0;i<k;i++)
  {
   for(j=i;j<n-i-1;j++)
    s[i][j]=a++;
   for(j=i;j<m-i-1;j++)
    s[j][n-i-1]=a++;
   for(j=n-i-1;j>i;j--)
    s[m-i-1][j]=a++;
   for(j=m-i-1;j>i;j--)
    s[j][i]=a++;
  }
  if(small & 1)
  {
   if(m<n)
    for(i=k;i<n-k;++i)
     s[k][i]=a++;
   else
    for(i=k;i<m-k;++i)
     s[i][k]=a++;
  }
  for(i=0;i<m;i++)
  {
   for(j=0;j<n;j++)
    printf("=",s[i][j]);
   printf("\n");
  }
 }

7、输出下方程序结果(内存偏移)

int *a = (int *)2; 
printf("%d",a+3);
答:14;
   int *a = (int *)2; 你实际上是在将整数 2 强制转换为指向整数的指针,并将这个指针赋值给变量 a。这意味着 a 现在指向内存地址 2;
         a+3,实际上是在将指针 a 向后移动3个 int 的大小,int类型地址加1 相当于加4个字节;a+3 就会是 2 + 3 * 4 = 14。

8、输出下方代码结果(读字节操作)

main() 
{
    char a,b,c,d;
    scanf("%c%c",&a,&b);
     c=getchar();    d=getchar();
     printf("%c%c%c%c\n",a,b,c,d);
 }当执行程序时,按下列方式输入数据(从第1列开始,<CR>代表回车,注意:回车也是一个字符)
12<CR>
34<CR>
则输出结果是
输出:
12
 3

该代码的功能是读取四个字符并打印它们。不过,由于 scanf 和 getchar 的特性,读取字符的方式可能会有一些微妙之处。
scanf("%c%c",&a,&b);标准输入读取两个字符,分别存储在变量 a 和 b;getchar() 函数会读取输入流中的下一个字符,包括空格、制表符和换行符;所以一概是12\n3

9、评价下方代码(指向常亮的指针和常指针)

int a[2] = {1, 2};  //a是指向常量的指针,指针可以变,指针指向的内容不可以变
 const int *p = a;//与int const *p = a;等价
 p++;                   //ok
 *p = 10;               //error   --指针指向的内容不可以变!
 int* const p2 = a;//与int const *p2 = a;不等价,
 p2++;                  //error
 *p2 = 10;             //ok
 const int* const p3 = a;//指向常量的常指针,都不可以改变
 p3++;//error
 *p3 = 10;//error

分析:
(1)const int *p = a; // 与 int const *p = a; 等价
这里声明了一个指向常量的指针 p,即 p 可以指向不同的地址,但是它所指向的内容是不可变的
(2)int* const p2 = a; // 与 const int* p2 = a; 不等价
声明了一个常指针 p2,它指向一个整型变量。这意味着 p2 一旦指向了某个地址,就不能再指向其他地址,但是它所指向的内容是可以修改的。
(3)const int* const p3 = a,这样声明的,那么它的指向和它所指向的内容都不能改变

 10、实现二分擦找算法

 int binary_search(int array[],int value,int size)
{
 int low=0,high=size-1,mid;
 
 while(low<=high)    //只要高低不碰头就继续二分查找
 {
  mid=(low+high)/2;
  if(value==array[mid])  //比较是不是与中间元素相等
   return mid;
  else if(value > array[mid]) //每查找一次,就判断一次所要查找变量所在范围,并继续二分
   low=mid;     //如果大小中间值,下限移到中间的后一个位,上限不变,往高方向二分
  else
   high=mid;        //上限移到中间的前一个位,往低方向二分
 }
 return -1;
}
/*双向循环链表插入函数*/
TYPE *insert_link(TYPE *head,TYPE *p_in)
{
 TYPE *p_mov = head,p_front = head;
 
 if(head == NULL)
 {
  head = p_in;
  p_in->next = head;
  p_perior = head;
 }
 else
 {
  while((p_in->[] > p_mov->[]) && (p_mov->next != head))
  {
   p_front = p_mov;
   p_mov = p_mov->next;
  }
  
  if(p_in->[] <= p_mov->[])
  {
   if(head == p_mov)
   {
    p_in->prior = head->prior;
    head->prior->next = p_in;
    p_in->next = p_mov;
    p_mov->prior = p_in;
    head = p_in;
   }
   else
   {
    pf->next = p_in;
    p_in->prior = p_front;
    p_in->next = p_mov;
    p_mov->prior = p_in;
   }
  }
  else
  {
   p_mov->next = p_in;
   p_in->prior = p_mov;
   p_in->next = head;
   head->prior = p_in;
  }
 }
 return head;
}
 
/*双向链表删除函数*/
TYPE *delete_link(TYPE *head,int num)
{
 TYPE *p_mov = head,p_front = head;
 
 if(head == NULL)
  printf("Not link\n");
 while((p_mov->num != num) && (p_mov->next != head))
 {
  p_front = p_mov;
  p_mov = p_mov->next;
 }
 if(p_mov->num == num)
 {
  if(p_mov == head)
  {
   if(p_mov->next == head && p_mov->prior == head)
   {
    free(pb);
    head =NULL;
    return head;
   }
   head->next->prior = head->prior;
   head->prior->next = head->next;
   head = head->next;
  }
  else
  {
   p_front->next = p_mov->next;
   p_mov->next->prior = p_front;
  }
  free(p_mov);
  printf("The node is delete\n");
 }
 else
 {
  printf("The node not been found\n");
 }
 return head;
}

11、简述中断活动的全过程:

 1、中断请求:中断事件一旦发生或者中断条件一旦构成,中断源提交“申请报告”,
   与请求CPU暂时放下目前的工作而转为中断源作为专项服务
 2、中断屏蔽:虽然中断源提交了“申请报告”,但是,是否得到CPU的响应,
   还要取决于“申请报告”是否能够通过2道或者3道“关卡”(中断屏蔽)送达CPU
  (相应的中断屏蔽位等于1,为关卡放行;反之相应的中断屏蔽位等于0,为关卡禁止通行);
 3、中断响应:如果一路放行,则CPU响应中断后,将被打断的工作断点记录下来
  (把断点地址保护到堆栈),挂起“不再受理其他申请报告牌”
  (清除全局中断标志位GIE=0),跳转到中断服务子程序
 4、保护现场:在处理新任务时可能破坏原有的工作现场,所以需要对工作现场和工作环境进行适当保护;
 5、调查中断源:检查“申请报告”是由哪个中断源提交的,以便作出有针对性的服务;
 6、中断处理:开始对查明的中断源进行有针对性的中断服务;
 7、清除标志:在处理完毕相应的任务之后,需要进行撤消登记(清除中断标志),以避免造成重复响应;
 8、恢复现场:恢复前面曾经被保护起来的工作现场,以便继续执行被中断的工作;
 9、中断返回:将被打断的工作断点找回来(从堆栈中恢复断点地址),
 并摘下“不再受理其他申请报告牌”(GIE=1),继续执行原先被打断的工作。   

12、linux进程间通讯的几种方式的特点和优缺点,和适用场合。分类:

 #管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。  
 #有名管道(named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 
 #信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。  它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。  
 #消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
 #信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。 
 #共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存,
   这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,
   它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,
   如信号量,配合使用,来实现进程间的同步和通信。 
 #套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,
   它可用于不同及其间的进程通信。

13、如何防止同时产生大量的线程?

方法是使用线程池,线程池具有可以同时提高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队等候 

14、评价下方代码(memset)

main() 

  char *p1=“name”; 
  char *p2; 
  p2=(char*)malloc(20); 
  memset (p2, 0, 20); 
  while(*p2++ = *p1++); 
  printf(“%s\n”,p2); 
 } 
 答案:输出为空串;
因为在whilie语句执行之前,memset 将p2的内容全置为\0, 因此第一次循环p2++已经指到了'\0'了;程序就结束了。

15、操作系统的内存分配一般有哪几种方式,各有什么优缺点?

 答:两者方式,定长和变长。
 变长:内存时比较灵活,但是易产生内存碎片。
 定长:灵活性差,但分配效率较高,不会产生内存碎片 

16、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?

 答:可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,
 前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错 

17、确定模块的功能和模块的接口是在软件设计的那个队段完成的? 

答:概要设计阶段 。 

18、评价下方代码(变量范围)

#define N 500
 unsigned char count;
 for(count=0;count < N;count++)
 {
  printf("---%d---\n",count);
 }
答:程序走入死循环,因为unsigned char 最大为255

19、评价结构体的内存大小

给定结构
struct A  
{       
    char t:4; //4位       
    char k:4; //4位       
    unsigned short i:8; //8位             
    unsigned long m;    // 偏移2字节保证4字节对齐
   };
答:共8字节  ,考查结构体的定义和自动对齐;

20、Ping操作使用的是什么一些,该协议的功能有哪些?

ICMP(ICMP协议对于网络安全具有极其重要的意义)功能主要有:

  1.  · 侦测远端主机是否存在。
  2.  · 建立及维护路由资料。
  3.  · 重导资料传送路径。
  4.  · 资料流量控制。

 单向、双向链表操作、写一个快速排序算法(原理:找一个基准值,分别将大于和小于基准值的数据放到基准值左右两边,即一次划分。由于处在两边的数据也是无序的,所以再用同样的划分方法对左右两边的序列进行再次划分,直到划分元素只剩1个时结束,)

21、单向链表逆序算法

LONDE *link_reverse(LNODE *head)
{
     LNODE *pb,*pt;
     if(head == NULL)
          return head;
     pb = head->next;
     head->next=NULL;
     while(pb != NULL)
     {
          pt = pb->next;
          pb->next = head;
          head = pb;
          pb = pt;
     }
     return head;
}

22、快速排序算法

void quick_sort(int num,int start_num,int end_num)
{
     if(start_num < end_num)
     {
           int i = start_num;
           int j = end_num;
          int temp = num[start_num];
      while(i < j)
      {
       while(i < j && num[j] < temp)
            j--;
       if(i < j)
       num[i++] = num[j];//把小于基准值放在左边
       while(i < j && num[i] >= temp)
            i++;
       if(i < j)
            num[j--] = num[i];//把大于基准值放在右边
      }
      num[i] = temp;
      quick_sort(num,start_num,i-1);
      quick_sort(num,i+1,end_num);
     }
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xiaoxilang

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

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

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

打赏作者

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

抵扣说明:

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

余额充值