嵌入式软件开发——嵌入式软件工程师面试题

一、int a[10]={1,2,3,4,5,6,7,8,9,0};
   int *p=&a[1];
   则p[6]等于8
二、整数数组清零:bzero(),memset()。
三、siezof();测试变量所占地址的字节数
四、 main() 
 { 
  char *str[]={"ab","cd","ef","gh","ij","kl"}; 
  char *t; 
  t=(str+4)[-1]; 
  printf("%s",t); 
 }则显示"gh"
五、小端:低位字节数据存储在低地址
 大端:高位字节数据存储在低地址
 例如:int a=0x12345678;(a首地址为0x2000)
 0x2000  0x2001  0x2002  0x2003
  0x12    0x34    0x56    0x78      大端格式
六、异步IO和同步IO区别
 若是是同步IO,当一个IO操做执行时,应用程序必须等待,直到此IO执行完,相反,异步IO操做在后台运行,
 IO操做和应用程序能够同时运行,提升系统性能,提升IO流量; 在同步文件IO中,线程启动一个IO操做而后就当即进入等待状态,直到IO操做完成后才醒来继续执行,而异步文件IO中,
 线程发送一个IO请求到内核,而后继续处理其余事情,内核完成IO请求后,将会通知线程IO操做完成了。
七、用变量a定义
 一个整型数   int a;
 一个指向整型数的指针  int *a;
 一个指向指针的指针,它指向的指针式指向一个整型数  int **a;
 一个有10个整型数的数组   int a[10];
 一个有10指针的数组,该指针是指向一个整型数  int *a[10];
 一个指向有10个整型数数组的指针   int (*a)[10];
 一个指向函数的指针,该函数有一个整型数参数并返回一个整型数   int (*a)(int);
 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型数参数并返回一个整型  int (*a[10])(int);
八、int foo(void)
{
 int i;
 char c=0x80;
 i=c;
 if(i>0)
  return 1;
 return 2;
}返回值为2;由于i=c=-128;若是c=0x7f,则i=c=127。
九、a=b*2;a=b/4;a=b%8;a=b/8*8+b%4;a=b*15;效率最高的算法
 a=b*2 -> a=b<<1;
 a=b/4 -> a=b>>2;
 a=b%8 -> a=b&7;
 a=b/8*8+b%4 -> a=((b>>3)<<3)+(b&3)
 a=b*15 -> a=(b<<4)-b
十、c关键字node

 c的关键字共32个
 *数据类型关键字(12)
 char,short,int,long,float,double,unsigned,signed,union,enum,void,struct
 *控制语句关键字(12)
 if,else,switch,case,default,for,do,while,break,continue,goto,return
 *存储类关键字(5)
 auto,extern,register,static,const
 *其余关键字(3)
 sizeof,typedef,volatile
十一、int main(void)
 {
  unsigned int a = 6;
  int b = -20;
  char c;
  (a+b>6)?(c=1):(c=0);
 }则c=1,但a+b=-14;若是a为int类型则c=0。
 原来有符号数和无符号数进行比较运算时(==,<,>,<=,>=),有符号数隐式转换成了无符号数(即底层的补码不变,可是此数从有符号数变成了无符号数),
 好比上面 (a+b)>6这个比较运算,a+b=-14,-14的补码为1111111111110010。此数进行比较运算时,
 被当成了无符号数,它远远大于6,因此获得上述结果。
十二、给定一个整型变量a,写两段代码,第一个设置a的bit3,第二个清除a的bit,在以上两个操做中,
 要保持其它位不变。
 #define BIT3 (0x1<<3)
  static int a;
  void set_bit3(void)
  {
   a |= BIT3;
  }
  void clear_bit3(void)
  {
   a &= ~BIT3;
  }
1三、要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。
  int *ptr;
    ptr = (int *)0x67a9;
     *ptr = 0xaa66;(建议用这种)
  
    一个较晦涩的方法是:
    *(int * const)(0x67a9) = 0xaa66;
1四、中断是嵌入式系统中重要的组成部分,这致使了不少编译开发商提供一种扩展—让标准C支持中断。
 具表明性的是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
 __interrupt void compute_area (void) 
 { 
   double area = PI * radius * radius; 
   printf(" Area = %f", area); 
   return area; 
 } 
 ISR不可能有参数和返回值的!
 ISR尽可能不要使用浮点数处理程序,浮点数的处理程序通常来讲是不可重入的,并且是消耗大量CPU时间的!!
 printf函数通常也是不可重入的,UART属于低速设备,printf函数一样面临大量消耗CPU时间的问题!
1五、评价下面的代码片段:
  
  unsigned int zero = 0;
  unsigned int compzero = 0xFFFF;
  /*1's complement of zero */
  对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写以下:
  unsigned int compzero = ~0;
1六、main()
 {
  char *ptr;
   if ((ptr = (char *)malloc(0)) == NULL)
   puts("Got a null pointer");
   else
   puts("Got a valid pointer");
 }
 该代码的输出是“Got a valid pointer”。还能够*ptr='a';不出现段错误
1七、Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也能够用预处理器作相似的事。
    例如,思考一下下面的例子:
  #define dPS struct s *
  typedef struct s * tPS;
  
  以上两种状况的意图都是要定义dPS 和 tPS 做为一个指向结构s指针。哪一种方法更好呢?(若是有的话)为何?
  这是一个很是微妙的问题,任何人答对这个问题(正当的缘由)是应当被恭喜的。答案是:typedef更好。思考下面的例子:
  dPS p1,p2;
  tPS p3,p4;
  
  第一个扩展为
  struct s * p1, p2;
  
  上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。
1八、int a = 5, b = 7, c;
  c = a+++b;
 则c=12。
1九、int main()
 {
  int j=2;
  int i=1;
  if(i = 1) j=3;
  if(i = 2) j=5;
  printf("%d",j);
 } 
 输出为5;若是再加上if(i=3)j=6;则输出6。
20、宏定义是在预编译阶段被处理的。
2一、Norflash与Nandflash的区别
 (1)、NAND闪存的容量比较大
 (2)、因为NandFlash没有挂接在地址总线上,因此若是想用NandFlash做为系统的启动盘,就须要CPU具有特殊的功能,
 如s3c2410在被选择为NandFlash启动方式时会在上电时自动读取NandFlash的4k数据到地址0的SRAM中。
 (3)、NAND Flash通常地址线和数据线共用,对读写速度有必定影响。NOR Flash闪存数据线和地址线分开,
    因此相对而言读写速度快一些。
2二、反码:对原码除符号位外的其他各位逐位取反就是反码
 补码:负数的补码就是对反码加1
 正数的原码、反码、补码都同样
2三、pthread_t tid;
 pthread_create(&tid,NULL,pthread_func,NULL);//建立线程
 pthread_join(tid,NULL);//等待子线程结束,并回收资源
 pthread_detach(tid);//与当前进程分离
 pthread_exit(NULL);//退出调用线程
 pthread_cancel(tid);//取消线程
 pthread_mutex mutex=PTHREAD_MUTEX_INITIALIZER;
 pthread_mutex_init(&mutex,NULL);//初始化一个互斥锁
 pthread_mutex_lock(&mutex);//对互斥锁上锁
 pthread_mutex_unlock(&mutex);//对互斥锁解锁
 sem_t sem;
 sem_init(&sem,0,1);//建立信号量并初始化它的值
 sem_wait(&sem);//信号量的值减1
 sem_post(&sem);//信号量的值加1
2四、内存管理MMU的做用
  *内存分配和回收
  *内存保护
  *内存扩充
  *地址映射 
2五、ROM是只读存储器,掉电不丢失
 RAM是读写存储器,掉电丢失
2六、SRAM:CPU的缓存就是SRAM,静态的随机存取存储器,加电状况下,不须要刷新,数据不会丢失
 DRAM,动态随机存取存储器最为常见的系统内存,须要不断刷新,才能保存数据
 SDRAM:同步动态随机存储器,即数据的读取须要时钟来同步。
2七、signed char 的取值范围-128~127.
2八、编译和连接有什么不一样?(如外部符号的处理)
 编译生成的是目标文件(object  *.o);
 编译过程当中对于外部符号不作任何解释和处理。外部符号对应的就是“符号”linux

 连接生成的是可执行程序
 连接将会解释和处理外部符号。外部符号对应的是地址
2九、已知strcpy函数的函数原型是:
 char *strcpy(char *strDest, const char *strSrc)。其中,strDest是目的字符串,strSrc是源字符串。
 不调用C++/C的字符串库函数,请编写函数strcpy
 char *strcpy(char *strDest, const char *strSrc)
 {
  int i=0;
  if(!(strDest && strSrc))
   return;
  while(strDest[i++] = *strSrc++);
  return strDest;
 }
30、strcpy能把strSrc的内容复制到strDest,为何还要char *类型的返回值?
 为了实现链式表达式
 int len = strlen(strcpy(strDest, strSrc));
3一、写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个
 #define MIN(a, b) (a) <= (b) ? (a) : (b)
3二、关键字static的做用是什么
 static用来修饰一个局部的变量的时候,
  生命域是全局的
  做用域是局部的c++

 static用来修饰一个模块内的(某一个C的源程序文件)全局变量的时候
  生命域不变
  做用域减少,只在本模块内有效程序员

 static用来修饰一个函数的时候
  做用域减少,只在本模块内有效面试

3三、说明下面的声明的含义:
  A.
  const int a;     // a是一个常数
  int const a;     // a是一个常数
  B.
  const int *a;     // a是一个指向整型常数的指针
  int * const a;     // a是一个指向整型变量的常指针
  int const * a const;   // a是一个指向整型常数的常指针
 C.
 char *strcpy(char *strDest, const char *strSrc);
       // 参数在函数内部不会被修改
 const int strcmp(char *source, char *dest);
       // 函数的返回值不能被修改
 const int a = strcmp(xx, yy);
 if(strcmp(xx,yy) != 0)
3四、说明关键字volatile有什么含意,并给出例子。
 volatile表示被修饰的符号是易变的。告诉编译器不要随便优化个人代码!!
 *一个硬件寄存器
 *中断中用到的变量
 *线程之间共享变量
 volatile int a = 10;
 while((a & 0x01) == 0);
 #define P_UART_STATUS ((const volatile unsigned int *)0x88000000);
       // volatile表示硬件会修改这个寄存器的内容
       // const表示该寄存器只读,写无心义
3五、printf能够接受多个参数,为何,请写出printf的原型。
 int printf(const char *fmt, ...);
3六、什么是堆栈,简述为何须要堆栈?
 堆栈是计算机中最经常使用的一种数据结构,保存数据的一块连续内存;好比函数的调用是用堆栈实现的。
3七、请列举经常使用的串行通讯方式(两种以上),并简述串行通讯和并行通讯不一样之处、优缺点。
 异步通讯和同步通讯;并行速度快,串行口线间干扰小
3八、列举一下你熟悉7层OSI协议中的几层。说说你最熟悉的一层协议的功能。
    应用层,表示层,会话层,传输层,网络层,数据链路层,物理层。
3九、路由协议:网关-网关协议,外部网关协议,内部网关协议(RIP-一、RIP-IGRP、EIGRP、IS-IS和OSPF)
40、位转换
 位 8   7   6   5   4   3   2    1
 数 v8  v7  v6  v5  v4  v3  v2   v1算法

 转换后:
 位 8   7   6   5   4    3   2   1
 数 v1  v2  v3  v4  v5   v6  v7  v8
 unsigned char  bit_reverse(unsigned char  c)
 {
   unsigned char buf = 0;
   int bit = 8;
   while(bit)
   {
   bit--;
   buf |= ((c & 1) << bit);
   c >>=1;
   }
   return buf;
 }
4一、字符串倒序
 1)、inverted_order(char *p)
  {
   char *s1,*s2,tem;
   s1=p;
   s2=s1+strlen(p)-1;
   while(s1<s2)
   {
    tem=*s1;
    *s1=*s2;
    *s2=tem;
    s1++;
    s2--;
   }
  }
 2)、inverted_order(char *p)
  {
   int len = strlen(src);
   char *des = (char *)malloc(len + 1);
   char *s = &src[len -1];
   char *d = des;
   while(len-- != 0)
    *d++ = *s--;
   *d = 0;
   free(des);
  }
4二、引用和指针的区别
  (1). 指针是一个实体,而引用仅是个别名;
   (2). 引用使用时无需解引用(*),指针须要解引用;
   (3). 引用只能在定义时被初始化一次,以后不可变;指针可变;
   (4). 引用没有 const,指针有 const,const 的指针不可变;
   (5). 引用不能为空,指针能够为空;
   (6). “sizeof 引用”获得的是所指向的变量(对象)的大小,
    而“sizeof指针”获得的是指针自己(所指向的变量或对象的地址)的大小;
   (7). 指针和引用的自增(++)运算意义不同;
4三、队列和栈的区别
 队列是先进先出,只能在一端插入另外一端删除,能够从头或尾进行遍历(但不能同时遍历),
 栈是先进后出,只能在同一端插入和删除,只能从头部取数据
4四、四层模型?七层模型?TCP/IP协议包括?
 这7层是:物理层、数据链路层、网路层、传输层、话路层、表示层和应用层
 这4层分别为:应用层、传输层、网络层、链路层。 
 TCP/IP协议族包括(IP)、(ARP)、(RARP)、(ICMP)、(UDP)、(TCP)、(RIP)、Telnet、(SMTP)、DNS等协议。
4五、TCP通讯创建和结束的过程?端口的做用
 三次握手和四次挥手;端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程一般使用一个固定的端口。
    21端口:21端口主要用于FTP(File Transfer Protocol,文件传输协议)服务。    23端口:23端口主要用于Telnet(远程登陆)服务,是Internet上广泛采用的登陆和仿真程序。  
    25端口:25端口为SMTP(Simple Mail TransferProtocol,简单邮件传输协议)服务器所开放,
    主要用于发送邮件,现在绝大多数邮件服务器都使用该协议。  
    53端口:53端口为DNS(Domain Name Server,域名服务器)服务器所开放,
    主要用于域名解析,DNS服务在NT系统中使用的最为普遍。  
    6七、68端口:6七、68端口分别是为Bootp服务的Bootstrap Protocol Server
    (引导程序协议服务端)和Bootstrap Protocol Client(引导程序协议客户端)开放的端口。  
    69端口:TFTP是Cisco公司开发的一个简单文件传输协议,相似于FTP。  
    79端口:79端口是为Finger服务开放的,主要用于查询远程主机在线用户、操做系统类型以及是否缓冲区溢出等用户的详细信息。880端口:80端口是为HTTP(HyperText Transport Protocol,超文本传输协议)开放的,
    这是上网冲浪使用最多的协议,主要用于在WWW(World Wide Web,万维网)服务上传输信息的协议。  
    99端口:99端口是用于一个名为“Metagram Relay”(亚对策延时)的服务,
    该服务比较少见,通常是用不到的。  
    10九、110端口:109端口是为POP2(Post Office Protocol Version 2,邮局协议2)服务开放的,
    110端口是为POP3(邮件协议3)服务开放的,POP二、POP3都是主要用于接收邮件的。 
    111端口:111端口是SUN公司的RPC(Remote Procedure Call,远程过程调用)服务所开放的端口,
     主要用于分布式系统中不一样计算机的内部进程通讯,RPC在多种网络服务中都是很重要的组件。  
    113端口:113端口主要用于Windows的“Authentication Service”(验证服务)。  
    119端口:119端口是为“Network News Transfer Protocol”(网络新闻组传输协议,简称NNTP)开放的。  
    135端口:135端口主要用于使用RPC(Remote Procedure Call,远程过程调用)协议并提供DCOM(分布式组件对象模型)服务。  
    137端口:137端口主要用于“NetBIOS Name Service”(NetBIOS名称服务)。  
    139端口:139端口是为“NetBIOS Session Service”提供的,主要用于提供Windows文件和打印机共享以及Unix中的Samba服务。  
    143端口:143端口主要是用于“Internet Message Access Protocol”v2(Internet消息访问协议,简称IMAP)。  
    161端口:161端口是用于“Simple Network Management Protocol”(简单网络管理协议,简称SNMP)。  
    443端口:43端口即网页浏览端口,主要是用于HTTPS服务,是提供加密和经过安全端口传输的另外一种HTTP。  
    554端口:554端口默认状况下用于“Real Time Streaming Protocol”(实时流协议,简称RTSP)。  
    1024端口:1024端口通常不固定分配给某个服务,在英文中的解释是“Reserved”(保留)。  
    1080端口:1080端口是Socks代理服务使用的端口,你们平时上网使用的WWW服务使用的是HTTP协议的代理服务。  
    1755端口:1755端口默认状况下用于“Microsoft Media Server”(微软媒体服务器,简称MMS)。  
    4000端口:4000端口是用于你们常用的QQ聊天工具的,再细说就是为QQ客户端开放的端口,QQ服务端使用的端口是8000。  
    5554端口:在今年4月30日就报道出现了一种针对微软lsass服务的新蠕虫病毒——震荡波(Worm.Sasser),该病毒能够利用TCP 5554端口开启一个FTP服务,主要被用于病毒的传播。  
    5632端口:5632端口是被你们所熟悉的远程控制软件pcAnywhere所开启的端口。  
    8080端口:8080端口同80端口,是被用于WWW代理服务的,能够实现网页浏览。
4六、物理地址转换成IP地址的协议?反之?
 地址解析协议(ARP)的做用是将IP地址转换成物理地址;反地址解析协议(RARP)则负责将物理地址转换成IP地址。
4七、WLAN:无线局域网络:利用射频技术进行数据传输的系统。
   WLAN是指应用无线通讯技术将计算机设备互联起来,构成能够互相通讯和实现资源共享的网络体系。无线局域网本质的特色是再也不使用通讯电缆将计算机与网络链接起来,而是经过无线的方式链接,从而使网络的构建和终端的移动更加灵活。编程

4八、已知数组table,用宏求元素个数。
  COUNT(table)  (sizeof(table)/sizeof(table[0]));数组

4九、定义一个两个参数的标准宏MAX,老是输出最大值。
  #define  MAX(a,b)  ((a)>(b)?(a):(b))
50、什么是平衡二叉树?
 当且仅当两个子树的高度差不超过1时,这个树是平衡二叉树。
5一、全局变量和局部变量的区别。
  全局变量,储存在静态区.进入main函数以前就被建立.生命周期为整个源程序; 
 局部变量,在栈中分配.在函数被调用时才被建立.生命周期为函数内。
5二、数组与链表的区别。
  数组中的数据在内存中的按顺序存储的,而链表是随机存储的!
 要访问数组中的元素能够按下标索引来访问,速度比较快,若是对他进行插入操做的话, 就得移动不少元素,因此对数组进行插入操做效率很低!因为连表是随机存储的,
 链表在插入,删除操做上有很高的效率(相对数组),若是要访问链表中的某个元素的话,
 那就得从链表的头逐个遍历,直到找到所须要的元素为止,
 因此链表的随机访问的效率就比数组要低  
5三、死锁的四个条件及处理方法。
  (1)互斥条件:一个资源每次只能被一个进程使用。    
 (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已得到的资源保持不放。 
    (3)不剥夺条件:进程已得到的资源,在末使用完以前,不能强行剥夺。   
    (4)循环等待条件:若干进程之间造成一种头尾相接的循环等待资源关系。  
      解决死锁的方法分为死锁的预防,避免,检测与恢复三种 
5四、进程调度策略。
  先进先出算法,最短CPU运行期优先调度算法,轮转法,多级队列方法
5五、Linux驱动程序流程及功能。
  设备驱动程序的功能:
  对设备初始化和释放
  把数据从内核传送到硬件和从硬件读取数据
  读取应用程序传送给设备文件的数据和回送应用程序请求的数据
  检测和处理设备出现的错误
5六、时间换空间、空间换时间的例子。
  冒泡排序 --- 时间换空间
  快速排序,堆排序 --- 空间换时间  
5七、MAC层通讯协议有哪些?
  ISO2110,IEEE802,IEEE802.2  
5八、关键字static的做用是什么?
 *在函数体内,一个被声明为静态的变量在这一函数被调用过程当中维持其值不变(该变量存放在静态变量区)。
    *在模块内(但在函数体外),一个被声明为静态的变量能够被模块内所用函数访问,但不能被模块外其它函数访问。
     它是一个本地的全局变量。
    *在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。
  那就是,这个函数被限制在声明它的模块的本地范围内使用。
5九、参数的传递方式有几种?
 一、值传递
    二、指针传递
    严格来看,只有一种传递,值传递,指针传递也是按值传递的,复制的是地址。
60、局部变量可否和全局变量重名?    
   答:能,局部会屏蔽全局。要用全局变量,须要使用 ":: "  局部变量能够与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。
   对于有些编译器而言,在同一个函数内能够定义多个同名的局部变量,好比在两个循环体内都定义一个同名的局部变量,
   而那个局部变量的做用域就在那个循环体内。 
6一、如何引用一个已经定义过的全局变量?    
   答:extern 能够用引用头文件的方式,也能够用extern关键字,若是用引用头文件方式来引用某个在头文件中声明的全局变理,
   假定你将那个变量写错了,那么在编译期间会报错,若是你用extern方式引用时,假定你犯了一样的错误,
   那么在编译期间不会报错,而在链接期间报错。 
6二、全局变量可不能够定义在可被多个.C文件包含的头文件中?为何?    答:能够,在不一样的C文件中以static形式来声明同名全局变量。    能够在不一样的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时链接不会出错  
6三、语句for(   ;1   ;)有什么问题?它是什么意思?    答:和while(1)相同。缓存

6四、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?    全局变量(外部变量)的说明以前再加static   就构成了静态的全局变量。全局变量自己就是静态存储方式,   
    静态全局变量固然也是静态存储方式。   这二者在存储方式上并没有不一样。
    这二者的区别虽在于非静态全局变量的做用域是整个源程序,   当一个源程序由多个源文件组成时,
    非静态的全局变量在各个源文件中都是有效的。   而静态全局变量则限制了其做用域,  
  即只在定义该变量的源文件内有效。 从以上分析能够看出,把局部变量改变为静态变量后是改变了它的存储
 方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的做用域,   
 限制了它的使用范围。static函数与普通函数做用域不一样。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static)
 ,内部函数应该在当前源文件中说明和定义。对于可在当前源文件之外使用的函数,应该在一个头文件中说明,
 要使用这些函数的源文件要包含这个头文件 static全局变量与普通的全局变量有什么区别:
 static全局变量只初使化一次,防止在其余文件单元中被引用static局部变量和普通局部变量有什么区别:
 static局部变量只被初始化一次,下一次依据上一次结果值; static函数与普通函数有什么区别:
 static函数在内存中只有一份,普通函数在每一个被调用中维持一份拷贝
6五、程序的局部变量存在于(堆栈)中,全局变量存在于(静态区   )中,动态申请数据存在于(   堆)中。
6六、-1,2,7,28,,126请问28和126中间那个数是什么?为何?    
    答案应该是4^3-1=63 规律是n^3-1(当n为偶数0,2,4)n^3+1(当n为奇数1,3,5) 
6七、用两个栈实现一个队列的功能?要求给出算法和思路!    
    设2个栈为A,B, 一开始均为空. 
 入队: 将新元素push入栈A;    
 出队: (1)判断栈B是否为空;    
       (2)若是不为空,则将栈A中全部元素依次pop出并push到栈B;    
    (3)将栈B的栈顶元素pop出;
6八、.软件测试都有那些种类?  
  人工测试:我的复查、抽查和会审 
  机器测试:黑盒测试(针对系统功能的测试 )和白盒测试 (测试函数功能,各函数接口) 
6九、堆栈溢出通常是由什么缘由致使的?
      没有回收垃圾资源。
70、写出float x 与“零值”比较的if语句。
      if(x>0.000001&&x<-0.000001)
7一、P地址的编码分为哪俩部分?
     IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上以后才能区分哪些是网络位哪些
     是主机位
7二、写一个程序, 要求功能:求出用1,2,5这三个数不一样个数组合的和为100的组合个数。
   如:100个1是一个组合,5个1加19个5是一个组合。。。。 请用C++语言写。sass

 答案:最容易想到的算法是:
 设x是1的个数,y是2的个数,z是5的个数,number是组合数
 注意到0<=x<=100,0<=y<=50,0<=z=20,因此能够编程为:
 number=0;
 for (x=0; x<=100; x++)
  for (y=0; y<=50; y++)
   for (z=0; z<=20; z++)
    if ((x+2*y+5*z)==100)
     number++;
7三、内存对齐问题的缘由?
 平台缘由(移植缘由):不是全部的硬件平台都能访问任意地址上的任意数据;
 性能缘由:数据结构(尤为是栈)应该尽量地在天然边界上对齐,由于为了访问未对齐的内存,处理器须要作两次内存访问,
     而对齐的内存访问仅须要一次。
7四、比较一下进程和线程的区别?
 (1)、调度:线程是CPU调度和分派的基本单位
 (2)、拥有资源:
  *  进程是系统中程序执行和资源分配的基本单位
  *  线程本身通常不拥有资源(除了必不可少的程序计数器,一组寄存器和栈),但他能够去访问其所属进程的资源,
     如进程代码,数据段以及系统资源(已打开的文件,I/O设备等)。
 (3)系统开销:
  *  同一进程中的多个线程能够共享同一地址空间,所以它们之间的同步和通讯的实现也比较简单
  *  在进程切换的时候,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置;
     而线程切换只须要保存和设置少许寄存器的内容,并不涉及存储器管理方面的操做,从而能更有效地使用系统资源和
     提升系统吞吐量。
7五、main()
 {
   int a[5]={1,2,3,4,5};
    int *ptr=(int *)(&a+1);//&a至关于变成了行指针,加1则变成了下一行首地址
    printf("%d,%d",*(a+1),*(ptr-1));
 }
 *(a+1)就是a[1],*(ptr-1)就是a[4],执行结果是2,5
7六、 void getmemory(char *p)
   {
  p=(char *) malloc(100);
  strcpy(p,"hello world");
   }
   int main( )
   {
  char *str=NULL;
  getmemory(str);
  printf("%s/n",str);
  free(str);
  return 0;
    }
 程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操做很危险
7七、void GetMemory(char *p)
 {
  p = (char *)malloc(100);
 }
 void Test(void) 
 {
  char *str = NULL;
  GetMemory(str); 
  strcpy(str, "hello world");
  printf(str);
 }

 请问运行Test函数会有什么样的结果?
 答:程序崩溃。由于GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL。strcpy(str, "hello world");将使程序崩溃。

 void GetMemory2(char **p, int num)
 {
  *p = (char *)malloc(num);
 }
 void Test(void)
 {
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello"); 
 printf(str); 
 }
 请问运行Test函数会有什么样的结果?
 答:(1)可以输出hello
     (2)内存泄漏
7八、char *GetMemory(void)
 { 
  char p[] = "hello world";
  return p;
 }
 void Test(void)
 {
  char *str = NULL;
  str = GetMemory(); 
  printf(str);
 }
 请问运行Test函数会有什么样的结果?
 答:多是乱码。由于GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,
 但其原现的内容已经被清除,新内容不可知。
7九、void Test(void)
 {
   char *str = (char *) malloc(100);
  strcpy(str, “hello”);
  free(str);     
  if(str != NULL)
  {
    strcpy(str, “world”); 
    printf(str);
   }
 }
 请问运行Test函数会有什么样的结果?
 答:篡改动态内存区的内容,后果难以预料,很是危险。由于free(str);以后,str成为野指针,
 if(str != NULL)语句不起做用。
 野指针不是NULL指针,是指向被释放的或者访问受限内存指针。
 形成缘由:指针变量没有被初始化任何刚建立的指针不会自动成为NULL;
     指针被free或delete以后,没有置NULL;
     指针操做超越了变量的做用范围,好比要返回指向栈内存的指针或引用,由于栈内存在函数结束时会被释放。
80、unsigned char *p=(unsigned char *)0x0801000
    unsigned char *q=(unsigned char *)0x0810000
 p+5 =?    0x0801005
 q+5 =?    0x0810005
8一、进程间通讯方式:管道、命名管道、消息队列、共享内存、信号、信号量、套接字。
 (1)、 管道( pipe ):管道是一种半双工的通讯方式,数据只能单向流动,并且只能在具备亲缘关系的进程间使用。
       进程的亲缘关系一般是指父子进程关系。
 (2)、有名管道 (named pipe) :有名管道也是半双工的通讯方式,可是它容许无亲缘关系进程间的通讯。
 (3)、信号量( semophore ) :信号量是一个计数器,能够用来控制多个进程对共享资源的访问。
      它常做为一种锁机制,防止某进程正在访问共享资源时,其余进程也访问该资源。
      所以,主要做为进程间以及同一进程内不一样线程之间的同步手段。
 (4)、消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
      消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
 (5)、信号 ( sinal ) : 信号是一种比较复杂的通讯方式,用于通知接收进程某个事件已经发生。
 (6)、共享内存( shared memory ) :共享内存就是映射一段能被其余进程所访问的内存,
      这段共享内存由一个进程建立,但多个进程均可以访问。共享内存是最快的 IPC 方式,它是针对其余进程间通讯方式运行效率低而专门设计的。它每每与其余通讯机制,
      如信号两,配合使用,来实现进程间的同步和通讯。
 (7)、套接字( socket ) : 套接字也是一种进程间通讯机制,与其余通讯机制不一样的是,它可用于不一样及其间的进程通讯。 
8二、宏和函数的优缺点?
 (1)、函数调用时,先求出实参表达式的值,而后带入形参。而使用带参数的宏只是进行简单的字符替换。
 (2)、函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,
   不进行值的传递处理,也没有“返回值”的概念。
 (3)、对函数中的实参和形参都要定义类型,两者的类型要求一致,应进行类型转换;而宏不存在类型问题,宏名无类型,
   它的参数也是无类型,只是一个符号表明,展开时带入指定的字符便可。宏定义时,字符串能够是任何类型的数据。
 (4)、调用函数只可获得一个返回值,而宏定义能够设法获得几个结果。
 (5)、使用宏次数多时,宏展开后源程序长,由于每次展开一次都使程序增加,而函数调用不使源程序变长。
 (6)、宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)。
8三、C和c++的不一样
 c和c++的一些不一样点(从语言自己的角度):
 1)c++源于c,c++最重要的特性就是引入了面向对象机制,class关键字。
 2)c++中,变量能够再任何地方声明;c中,局部变量只能在函数开头声明。
 3)c++中,const型常量是编译时常量;c中,const常量只是只读的变量。
 4)c++有&引用;c没有
 5)c++的struct声明自动将结构类型名typedef;c中struct的名字只在结构标签名字空间中,不是做为一种类型出现
 6)c语言的main函数能够递归调用;c++中则不能够
 7)c中,void *能够隐式转换成其余指针类型;c++中要求现实转换,不然编译通不过
8四、6.大小端格式问题。
 方法一:
 void checkCpuMode(void)
 {
  int i = 0x12345678;
  char *cp = (char *)&i;
  if(*cp == 0x78)
   printf("little endian");
  else
   printf("big endian\n");
 }
 方法二:
 void checkCpuMode(void)
 {
  int a = 0x12345678;
  if((char)a == 0x12)
   printf("big endian\n");
  else 
   printf("little endian\n");
 }
 方法三:
 void checkCpuMode(void)
    {
  union 
  {
   short s;
   char c[sizeof(short)];
  }un;
  un.s=0x0102;
  if(un.[0]==1&&un.c[1]==2)
   printf("big endian\n");
  else
   printf("little endian\n");
 }
8五、由C/C++编译的程序占用的内存分为如下几个部分 
 一、栈区(stack): 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操做方式相似于数据结构中的栈。 
 二、堆区(heap): 通常由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
                 注意它与数据结构中的堆是两回事,分配方式却是相似于链表。 
 三、全局区(static): 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,
                    未初始化的全局变量和未初始化的静态变量在相邻的另外一块区域,程序结束后有系统释放 。 
 四、文字常量区: 常量字符串就是放在这里的, 程序结束后由系统释放。 
 五、程序代码区: 存放函数体的二进制代码。
8七、for(m=5;m--;m<0)
 {
  printf("m=%d\n",m);
 }输出:四、三、二、一、0
8八、5["abcdef"]可以编译经过,请问编译后的结果是什么?
 printf("%d\n",5["abcdef"]);输出'f'的ACSII值,若是是4["abcdef"]则输出'e'的ACSII的值。
8九、线程同步的方法:信号量、条件变量、互斥锁。
90、for(i=0;i<2,i<3,i<4;i++)
  printf("%d \n",i);     输出:0,1,2,3。

100、物理地址,虚拟地址,逻辑地址和总线地址的区别
     逻辑地址(Logical Address)是指由程序产生的与段相关的偏移地址部分。
 例如,你在进行C语言指针编程中,能够读取指针变量自己值(&amp;操做),实际上这个值就是逻辑地址,
 它是相对于你当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,
 逻辑地址才和物理地址相等(由于实模式没有分段或分页机制, Cpu不进行自动地址转换);
 逻辑也就是在Intel 保护模式下程序执行代码段限长内的偏移地址(假定代码段、数据段若是彻底同样)。
 应用程序员仅需与逻辑地址打交道,而分段和分页机制对您来讲是彻底透明的,仅由系统编程人员涉及。
 应用程序员虽然本身能够直接操做内存,那也只能在操做系统给你分配的内存段操做。
     线性地址(Linear Address)是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,
 或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。若是启用了分页机制,
 那么线性地址能够再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。
 Intel 80386的线性地址空间容量为4G(2的32次方即32根地址总线寻址)。
     物理地址(Physical Address) 是指出如今CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。
 若是启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。
 若是没有启用分页机制,那么线性地址就直接成为物理地址了。
  在x86下,外设的i/o地址是独立的,即有专门的指令访问外设i/o,i/o地址就是你所说的“总线地址”。
 而“物理地址”就是ram地址。在arm中,i/o和ram统一编址,但linux为了统一各个平台,仍然保留这个概念,其实就是物理地址。  
10一、编写内核程序中申请内存和编写应用程序时申请内存有什么区别
     应用程序使用C函数库中的内存分配函数malloc()申请内存内核会为进程使用的代码和数据空间维护一个当前位置的值brk,
 这个值保存在每一个进程的数据结构中。它指出了进程代码和数据(包括动态分配的数据空间)在进程地址空间中的末端位置。
 当malloc()函数为程序分配内存时,它会经过系统调用brk()把程序要求新增的空间长度通知内核,
 内核代码从而能够根据malloc()所提供的信息来更新brk的值,但此时并不为新申请的空间映射物理内存页面。
 只有当程序寻址到某个不存在对应物理页面的地址时,内核才会进行相关物理内存页面的映射操做。
     当用户使用内存释放函数free()动态释放已申请的内存块时,c库中的内存管理函数就会把所释放的内存块标记为空闲,
 以备程序再次申请内存时使用。在这个过程当中内核为该进程所分配的这个物理页面并不会被释放掉。
 只有当进程最终结束时内核才会全面收回已分配和映射到该进程地址空间范围内的全部物理内存页面。
10二、如何用C语言实现读写寄存器变量
 #define rBANKCON0  (*(volatile unsigned long *)0x48000004) 
 rBankCON0 = 0x12; 
10三、sscanf("123456 ", "%4s", buf);                     1234
 sscanf("123456 asdfga","%[^ ]", buf);               123456
    sscanf("123456aafsdfADDEFF", "%[1-9a-z]", buf);     123456aafsdf
    sscanf("123afsdfADJKLJ", "%[^A-Z]", buf);          123afsdf
10四、char* s="AAA";
 s[0]='B';
 printf("%s",s);
 有什么错?
 "AAA"是字符串常量。s是指针,指向这个字符串常量,因此声明s的时候就有问题。
 cosnt char* s="AAA";
 而后又由于是常量,因此对是s[0]的赋值操做是不合法的。 
10五、数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型:
  int do_dup(int a[],int N)                 int do_dup(int a[],int N)//a[0]为监视哨  
  {                                           {
   int i;                                       int temp; 
   int s;                                       while (a[0]!=a[a[0]])
   int num;                                     {
   for(i=0;i<N;i++)                                 temp=a[0];
    s+=a[i];                                     a[0]=a[temp];
   num=s-N*(N-1)/2;(num即为重复数)                  a[temp]=temp;         
  }                                                 }
              return a[0];
              }
10六、tcp/udp是属于哪一层?tcp/udp有何优缺点?
 tcp /udp属于运输层
 TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操做和多路复用技术等。
 与 TCP 不一样, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。因为 UDP 比较简单, UDP 头包含不多的字节,比 TCP 负载消耗少。
 tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性很差
 udp: 不提供稳定的服务,包头小,开销小
10七、 char a = 100;
   char b =  150;//10010110//01101010
   unsigned char c ;
      c = (a < b)? a:b;   --》 c=150;
10八、应用程序ping发出的是ICMP请求报文
10九、在C语言中memcpy和memmove是同样的吗?
 memmove()与memcpy()同样都是用来拷贝src所指向内存内容前n个字节到dest所指的地址上,不一样是,当src和dest所指的内存区域重叠时,
 memmove()仍然能够正确处理,不过执行效率上略慢些。
1十、C语言程序代码优化方法
  * 选择合适的算法和数据结构
  * 使用尽可能小的数据类型
  * 使用自加、自减指令
  * 减小运算的强度
   求余运算(a=a%8改成a=a&7)
   平方运算(a=pow(a,2.0)改成a=a*a)
   用移位实现乘除法运算
  * 延时函数的自加改成自减
  * switch语句中根据发生频率来进行case排序
 
1十一、找出一个字符串中一个最长的连续的数字,并标注出位置和个数。
 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);
}
1十二、写出螺旋矩阵
 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");
  }
 }
11三、int *a = (int *)2;
  printf("%d",a+3); 答案是2+3*4=14;int类型地址加1 至关于加4个字节
11四、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);
 } 输出:12
    3
11五、int a[2] = {1, 2};
 //指向常量的指针,指针能够变,指针指向的内容不能够变
 const int *p = a;//与int const *p = a;等价
 p++;//ok
 *p = 10;//error
 //常指针,指针不能够变,指针指向的内容能够变
 int* const p2 = a;
 p2++;//error
 *p2 = 10;//ok
 //指向常量的常指针,都不能够改变
 p3++;//error
 *p3 = 10;//error
11六、#error 预处理指令的做用是,编译程序时,只要遇到#error 就会生成一个编译错误提
  示消息,并中止编译
11七、中断活动的全过程大体为:
 一、中断请求:中断事件一旦发生或者中断条件一旦构成,中断源提交“申请报告”,
   与请求CPU暂时放下目前的工做而转为中断源做为专项服务
 二、中断屏蔽:虽然中断源提交了“申请报告”,可是,是否获得CPU的响应,
   还要取决于“申请报告”是否可以经过2道或者3道“关卡”(中断屏蔽)送达CPU
  (相应的中断屏蔽位等于1,为关卡放行;反之相应的中断屏蔽位等于0,为关卡禁止通行);
 三、中断响应:若是一路放行,则CPU响应中断后,将被打断的工做断点记录下来
  (把断点地址保护到堆栈),挂起“再也不受理其余申请报告牌”
  (清除全局中断标志位GIE=0),跳转到中断服务子程序
 四、保护现场:在处理新任务时可能破坏原有的工做现场,因此须要对工做现场和工做环境进行适当保护;
 五、调查中断源:检查“申请报告”是由哪一个中断源提交的,以便做出有针对性的服务;
 六、中断处理:开始对查明的中断源进行有针对性的中断服务;
 七、清除标志:在处理完毕相应的任务以后,须要进行撤消登记(清除中断标志),以免形成重复响应;
 八、恢复现场:恢复前面曾经被保护起来的工做现场,以便继续执行被中断的工做;
 九、中断返回:将被打断的工做断点找回来(从堆栈中恢复断点地址),
 并摘下“再也不受理其余申请报告牌”(GIE=1),继续执行原先被打断的工做。   
11八、linux进程间通信的几种方式的特色和优缺点,和适用场合。分类:
 #管道( pipe ):管道是一种半双工的通讯方式,数据只能单向流动,
    并且只能在具备亲缘关系的进程间使用。进程的亲缘关系一般是指父子进程关系。  
 #有名管道(named pipe) : 有名管道也是半双工的通讯方式,可是它容许无亲缘关系进程间的通讯。 
 #信号量( semophore ) : 信号量是一个计数器,能够用来控制多个进程对共享资源的访问。
   它常做为一种锁机制,防止某进程正在访问共享资源时,其余进程也访问该资源。所以,主要做
   为进程间以及同一进程内不一样线程之间的同步手段。  
 #消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识
   符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
 #信号 ( sinal ) : 信号是一种比较复杂的通讯方式,用于通知接收进程某个事件已经发生。 
 #共享内存( shared memory):共享内存就是映射一段能被其余进程所访问的内存,
   这段共享内存由一个进程建立,但多个进程均可以访问。共享内存是最快的IPC方式,
   它是针对其余进程间通讯方式运行效率低而专门设计的。它每每与其余通讯机制,
   如信号量,配合使用,来实现进程间的同步和通讯。 
 #套接字( socket ) : 套解口也是一种进程间通讯机制,与其余通讯机制不一样的是,
   它可用于不一样及其间的进程通讯。
11九、关键字volatile有什么含意?并给出三个不一样的例子。
 一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设
 这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都当心地从新读取这个变量的值,
 而不是使用保存在寄存器里的备份。
 下面是volatile变量的几个例子:
 1). 并行设备的硬件寄存器(如:状态寄存器)
 2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
 3). 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员常常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。
 假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,
 看一下这家伙是否是直正懂得volatile彻底的重要性。
 1). 一个参数既能够是const还能够是volatile吗?解释为何。
 2). 一个指针能够是volatile 吗?解释为何。
 3). 下面的函数有什么错误:
 int square(volatile int *ptr) {
    return *ptr * *ptr;
  }
 下面是答案:
 1). 是的。一个例子是只读的状态寄存器。它是volatile由于它可能被意想不到地改变。
     它是const由于程序不该该试图去修改它。
 2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
 3). 这段代码的有个恶做剧。这段代码的目的是用来返指针*ptr指向值的平方,可是,
    因为*ptr指向一个volatile型参数,编译器将产生相似下面的代码:
 int square(volatile int *ptr) {
   int a,b;
   a = *ptr;
   b = *ptr;
   return a * b;
  }
  因为*ptr的值可能被意想不到地该变,所以a和b多是不一样的。
  结果,这段代码可能返不是你所指望的平方值!正确的代码以下:
 long square(volatile int *ptr) {
   int a;
   a = *ptr;
   return a * a;
  }
  Volatile 关键字告诉编译器不要持有变量的临时性拷贝。通常用在多线程程序中,
  以免在其中一个线程操做该变量时,将其拷贝入寄存器。
 请看如下情形: A线程将变量复制入寄存器,而后进入循环,反复检测寄存器的值是否知足
 必定条件(它期待B线程改变变量的值。在此种状况下,当B线程改变了变量的值时,
 已改变的值对其在寄存器的值没有影响。因此A线程进入死循环。
  volatile 就是在此种状况下使用。  
120、如何防止同时产生大量的线程,方法是使用线程池,线程池具备能够同时提升调度效率和
  限制资源使用的好处,线程池中的线程达到最大数时,其余线程就会排队等候 
12一、main() 
 { 
  char *p1=“name”; 
  char *p2; 
  p2=(char*)malloc(20); 
  memset (p2, 0, 20); 
  while(*p2++ = *p1++); 
  printf(“%s\n”,p2); 
 } 
 答案:Answer:empty string. 因p2++已经指到了'\0'了;
12二、操做系统的内存分配通常有哪几种方式,各有什么优缺点?
 定长和变长。
 变长:内存时比较灵活,可是易产生内存碎片。
 定长:灵活性差,但分配效率较高,不会产生内存碎片 
12三、全局变量可不能够定义在可被多个.C文件包含的头文件中?为何?
 答:能够,在不一样的C文件中以static形式来声明同名全局变量。能够在不一样的C文件中声明同名的全局变量,
 前提是其中只能有一个C文件中对此变量赋初值,此时链接不会出错 
12四、肯定模块的功能和模块的接口是在软件设计的那个队段完成的?概要设计阶段 
12五、#define N 500
 unsigned char count;
 for(count=0;count < N;count++)
 {
  printf("---%d---\n",count);
 }死循环,由于unsigned char 最大为255
12六、给定结构struct A 
   {       
    char t:4; 4位       
    char k:4; 4位       
    unsigned short i:8; 8位             
    unsigned long m; // 偏移2字节保证4字节对齐
   }; // 共8字节 
12七、ICMP(ICMP协议对于网络安全具备极其重要的意义)功能主要有:
 · 侦测远端主机是否存在。
 · 创建及维护路由资料。
 · 重导资料传送路径。
 · 资料流量控制。
 
 
 单向、双向链表操做、写一个快速排序算法(原理:找一个基准值,分别将大于和小于基准值的数据放到基准值左右两边,即一次划分。因为处在两边的数据也是无序的,因此再用一样的划分方法对左右两边的序列进行再次划分,直到划分元素只剩1个时结束,)
/******************************************************************/
一、单向链表逆序
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;
}
二、快速排序
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);
 }
}
三、//二分擦找
 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; }