单片机面试笔试大全.docx_第1页
单片机面试笔试大全.docx_第2页
单片机面试笔试大全.docx_第3页
单片机面试笔试大全.docx_第4页
单片机面试笔试大全.docx_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

单片机笔试面试白皮书目录第一部笔试面试流程2一、准备简历2二、简历投递2三、笔试准备3四、面试准备3五、面试练习4第二部C笔试面试题5第一大块:基本语法5第二大块:变量7第三大块:函数18第四大块:指针 & 内存21第五大块:链表26第六大块:算法30第三部LSD笔试面试题37第四部C+/驱动笔试面试题37第五部JAVA笔试面试题40第六部android笔试面试题41第七部项目面试题42第一部 笔试面试流程一、 准备简历在51、智联、中华英才网站个做一份简历。简历内容重点:所学课程(C语言、linux系统程序设计、JAVA、android)所做项目:项目描述一定要完整,清晰。项目是关键点。 并且,如果面试的是android,那么把android项目放在前面。 【一句话摆平】你和应届生的本质区别,就在于你有项目经验。工作背景:如果有技术相关背景,写清楚,只要技术相关都可以加分的。交流背景:以前做过和交流沟通相关的事情如果是应届生,那么做过的学生会工作,组着过活动等;如果工作过,那么做过的工作,把闪光点说出来;最起码,工作沟通、稳定性等方面是可以展示出来的。面试官很关心这个。简历书写注意事项:简历书写语言简洁,多用条例性语言。(第一、第二、第三、.)简历不能出现经历空白,如中间半年没有任何经历。简历不能和其他学员的简历出现相同的内容,尤其是项目描述。否则,两个人都有可能失去面试机会。简历版面简单,字体不要超过3种。不需要相片,不需要花哨的格式。 招聘网站介绍:51效果最好,重点关注51招聘网站。注意关键字:在简历重要多出现重要关键字: C语言、数据结构、linux系统开发(linux系统移植、驱动、arm、C+)、JAVA、android二、 简历投递每天早晨(一定要早晨,早晨的效果是最好的,否则可能效果减半)把3个网站的简历都“刷新”一下。每天早晨投递简历,主要搜索,嵌入式开发、C开发、linux开发、JAVA开发、android开发、软件开发。每天投递十几个公司。一家公司,如果没给面试通知,多次投递。重点关注的51网站,要在这个网站上注册2-3个账号,使用同样的简历,每天可以更换账号投递。并不是你投递的每个人的简历公司人事都会看到,如果收到的简历很多,那么人事可能每天只能看到排在收件箱最前面的简历。所以你的投递必须要人事能最先看到。简历投递的重点注意:第一、最好投递时间是早晨。早晨效果往往是其他时间段的两倍。第二、51上要注册两、三个账号。使用同样的简历,轮流投递。第三、第一轮投递使用海投的方式,即搜索“嵌入式开发”、“linux开发”、“C开发”等关键字,然后全选投递(海投)。第四、以后每天坚持投递,投递职位数目在十多个。三、 笔试准备笔试的主要内容应该是C语言和android,其次算法,JAVA。所以C语言必须扎实。很多公司的笔试题目就是为了笔试而笔试,可能开发中千年难用。但是你做不出来,就能体现出公司的出题水平。我们可以鄙视这些公司,但我们还是要认真准备笔试的。1、“嵌入式经典笔试整理收录”这份题目必须看.这里面的题目一道都不能落下全部弄懂。这里面都是基础.包括概念在内.练习题目不但要看懂,而且要在纸上动手写出来。一定要在纸上写出来,因为不笔试的时候不是上机,要一次写出来,难度还是大些。2、“高质量C+-C编程指南.doc”看这份资料。这份看完基本C语言就没有太多问题。3、看其他面试笔试资料。资料要多看。注意:很多笔试题目一定要自己在纸上写出来。笔试讲求的就是“纸上谈兵”!在纸上写程序要比你在电脑上写难很多。切记不可以骄傲。四、 面试准备看嵌入式经典面试题目收录 常见面试题目。必须每道题目都能流畅完整打出来。准备自我介绍:1、教育背景:学校专业毕业时间。2、工作背景:之前从事什么工作。一定要说明为什么转到这个行业了,为什么离开上一家公司了。对之前工作中的自己不要否定:因为你自己都否定自己了,谁还会肯定你?3、培训背景:所学课程:课程名称(不要把课程名称都忘掉了,名字都忘了,别人怎么相信你学好这个课程)所做项目:在培训期间动手完成了那些项目。项目描述要清晰,一般套路:1、项目名称(这个也不能忘)2、项目简介 3、项目分成几个模块 4、项目所使用的技术。项目描述是整个面试的一个重点。4、技术问答:对面试官所提出的技术问题,进行解答。解答问题要简洁明了,要用肯定语气,一定要给面试官信心。回到问题要简介明了,不要有语气词。如果有不会回答的问题,不用着急。可以肯定的告诉面试官不知道。很多问题答不上来是正常的。所以不要紧张。都答上来还不一定要你呢(面试中面试官一定要出一些拟答不上来的问题,这样才能确定你的能力范围,另外也能让你认识到自己的不足,这样你开价的时候也会自觉地悠着点)。也可以绕过去,但不能太多问题都去绕。面试官提问喜欢沿着一个问题不停的追问,直到你不会为止。所以准备的时候注意一定要全面深入。另外不会也不用紧张,影响后面的面试。5、人事面试:常见问题:你对加班的看法?你对你上一家公司的经理的看法?你觉得你最忌最大的优点和缺点个是什么?你为什么离开上一家公司?你3年或者5年的职业发展规划?你觉得你自己值这么多钱(你开的薪资)吗?闲聊:注意闲聊的时候不要忘形,要给别人一种稳定,喜欢技术,对公司所属行业感兴趣,自己个人爱好健康,不要提消极(爱玩游戏,懒,之类的事情)6、谈薪资:谈薪资,开始要想要自己期望的薪资是多少。不要模糊的。告诉比人我期望薪资多少。不过不要太高,如果太高的话,别人即使想要你也可以去,但别人会认为你不踏实,而不敢要你。所以你所说的期望薪资可以比你的最低薪资多出500.最多不能多出1000.注意一般面试时间要超过20分钟。如果面试官面试时间超过20分钟,那么说明他对你的情趣比较大了。30分钟以上说明你已经有6成以上的把握了。一般情况如果面试的人当时没有对你表示出意向,让你回去等通知,基本没戏了。五、 面试练习把面试的自我介绍写下来,让后多读几遍。最好是对着镜子读。不要不好意思,流畅与否,那就是每月500或者1000的差呀。面试准备是非常重要的。因为经常面试的东西主要就那些。另外,面试过程中必须对自己有信心。那怕装也得装出来。正常情况下,如果两个人技术差不多,那么面试官一般都会挑选有信心的。有信心的人在日后的项目中会更有韧性,能担当的更多。即使技术现在不是很好,但有信心的话,可以在以后的工作中很快就弥补上来了。每个人对自己的信心,要有这样的觉悟,即使我现在技术不是很好,但我将来一定会好好学,好好做,一定能给我所在的公司带来价值,公司选择我那是正确,不选我那是公司最大的损失。反过来,如果对自己没有信心,那凭什么让面试官对你有信心呢?即使你技术过了,他还可能认为,是不是死记硬背的。即使你值5k他会觉得,给你3.5k你都会来。面试不但是技术的战争,更是心理的战争。最后一句:信心十足,但不高调。祝大家马到成功!第二部 C笔试面试题第一大块:基本语法1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL我在这想看到几件事情:1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。4). 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。2. 写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个#define MIN(A,B) (A) = (B) (A) : (B)这个测试是为下面的目的而设的:1). 标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符变为标准C的一部分,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。2). 三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。3). 懂得在宏中小心地把参数用括号括起来4). 我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?least = MIN(*p+, b);其实宏在编程中的副作用主要表现在编译器的处理计算上,如果考虑不周全很容易出现重复计算的问题。所以写程序要用宏的简洁,又要注意其中的陷阱,以防出现莫名其妙的错误3. 用宏定义写出swap(x,y)#define swap(x, y) x = x + y; y = x - y; x = x - y;4. 请定义一个宏,比较两个数a、b的大小,不能使用大于、小于、if语句#define Max(a,b) ( a/b)?a:b5. 预处理器标识#error的目的是什么?如果你不知道答案,直接baidu。6. 字节对齐/# pragma pack(4)struct stchar c; int i; short s; ;sizeof(struct st);7. 死循环(Infinite loops)8. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?这个问题用几个解决方案。我首选的方案是:while(1) 一些程序员更喜欢如下方案:for(;) 这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为什么。”这会给我留下一个坏印象。第三个方案是用 gotoLoop:.goto Loop;应试者如给出上面的方案,最好解释汇编语言程或BASIC/FORTRAN语言可以这么做。但如果是C 编程中出现goto ,那么会留下恶劣的印象。9. Typedef 在C语言中频繁用以声明一个已经存在的数据类型的同义字。也可以用预处理器做类似的事。例如,思考一下下面的例子:#define dPS struct s *typedef struct s * tPS;dPS mm, qq; /struct s * mm, qq;tPS nn, pp; / struct s * mm, *qq;以上两种情况的意图都是要定义dPS 和 tPS 作为一个指向结构s指针。哪种方法更好呢?(如果有的话)为什么?这是一个非常微妙的问题,任何人答对这个问题(正当的原因)是应当被恭喜的。答案是:typedef更好。思考下面的例子:dPS p1,p2;tPS p3,p4;第一个扩展为struct s * p1, p2;上面的代码定义p1为一个指向结构的指,p2为一个实际的结构,这也许不是你想要的。第二个例子正确地定义了p3 和p4 两个指针。10. C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?int a = 5, b = 7, c;c = a+b;这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:c = a+ + b;因此, 这段代码持行后a = 6, b = 7, c = 12。11. 头文件中的 ifndef/define/endif 干什么用?12. 一个死循环int main()unsigned char i;for(i= 0;i256;i+)printf(“i= %dn”,i);return 0;程序运行结果13. 如何输出源文件的标题和目前执行行的行数int line = _LINE_;char *file = _FILE_;coutfile name is (file),line is 第二大块:变量14. 变量的存储空间 C程序一直由下列部分组成:(1)正文段CPU执行的机器指令部分;一个程序只有一个副本;只读,防止程序由于意外事故而修改自身指令;(2)初始化数据段(数据段)在程序中所有赋了初值的全局变量,存放在这里。(3)非初始化数据段(bss段)在程序中没有初始化的全局变量;内核将此段初始化为0。(4)栈增长方向:自顶向下增长;自动变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。(5)堆动态存储分配。|-| 高地址|-| 栈 |-| | | |/ | /| | | |-| 堆 |-| 未初始化 |-| 初始化 |-| 正文段 | 低地址问题:局部变量存放区域?初始化全局变量存放区域?未初始化的全局变量存放区域?静态局部变量存放区域?动态分配内存是在那个区域?15. 堆和栈的区别【一句话摆平】堆是手动,但容易导致内存碎片;栈是自动,但空间有限。一般认为在c中分为这几个存储区(1)、栈 - 有编译器自动分配释放(2)、堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收(3)、全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束释放(4)、另外还有一个专门放常量的地方。 - 程序结束释放在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。另外,函数中的adgfdf这样的字符串存放在常量区。比如:int a = 0; 全局初始化区char *p1; 全局未初始化区main()int b; 栈char s = abc;栈char *p2; 栈char *p3 = 123456; 1234560在常量区,p3在栈上。static int c =0; 全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20);分配得来得10和20字节的区域就在堆区。strcpy(p1, 123456); 1234560放在常量区,编译器可能会将它与p3所指向的123456优化成一块。还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。栈的空间大小有限定,vc的缺省是2M。栈不够用的情况一般是程序中分配了大量数组和递归函数层次太深。有一点必须知道,当一个函数调用完返回后它会释放该函数中所有的栈空间。栈是由编译器自动管理的,不用你操心。堆是动态分配内存的,并且你可以分配使用很大的内存。但是用不好会产生内存泄漏。并且频繁地malloc和free会产生内存碎片(有点类似磁盘碎片),因为c分配动态内存时是寻找匹配的内存的。而用栈则不会产生碎片。在栈上存取数据比通过指针在堆上存取数据快些。一般大家说的堆栈和栈是一样的,就是栈(stack),而说堆时才是堆heap.栈是先入后出的,一般是由高地址向低地址生长。堆(heap)和栈(stack)是C/C+/JAVA编程不可避免会碰到的两个基本概念。首先,这两个概念都可以在讲数据结构的书中找到,他们都是基本的数据结构,虽然栈更为简单一些。在具体的C/C+/JAVA编程框架中,这两个概念并不是并行的。对底层机器代码的研究可以揭示,栈是机器系统提供的数据结构,而堆则是C/C+/JAVA函数库提供的。具体地说,现代计算机(串行执行机制),都直接在代码底层支持栈的数据结构。这体现在,有专门的寄存器指向栈所在的地址,有专门的机器指令完成数据入栈出栈的操作。这种机制的特点是效率高,支持的数据有限,一般是整数,指针,浮点数等系统直接支持的数据类型,并不直接支持其他的数据结构。因为栈的这种特点,对栈的使用在程序中是非常频繁的。对子程序的调用就是直接利用栈完成的。机器的call指令里隐含了把返回地址推入栈,然后跳转至子程序地址的操作,而子程序中的ret指令则隐含从堆栈中弹出返回地址并跳转之的操作。C/C+/JAVA中的自动变量是直接利用栈的例子,这也就是为什么当函数返回时,该函数的自动变量自动失效的原因(因为 颜换指戳说饔们暗 状态)。和栈不同,堆的数据结构并不是由系统(无论是机器系统还是操作系统)支持的,而是由函数库提供的。基本的malloc/realloc/free函数维护了一套内部的堆数据结构。当程序使用这些函数去获得新的内存空间时,这套函数首先试图从内部堆中寻找可用的内存空间,如果没有可以使用的内存空间,则试图利用系统调用来动态增加程序数据段的内存大小,新分配得到的空间首先被组织进内部堆中去,然后再以适当的形式返回给调用者。当程序释放分配的内存空间时,这片内存空间被返回内部堆结构中,可能会被适当的处理(比如和其他空闲空间合并成更大的空闲空间),以更适合下一次内存分配申请。这套复杂的分配机制实际上相当于一个内存分配的缓冲池(Cache),使用这套机制有如下若干原因:1. 系统调用可能不支持任意大小的内存分配。有些系统的系统调用只支持固定大小及其倍数的内存请求(按页分配);这样的话对于大量的小内存分类来说会造成浪费。2. 系统调用申请内存可能是代价昂贵的。系统调用可能涉及用户态和核心态的转换。3. 没有管理的内存分配在大量复杂内存的分配释放操作下很容易造成内存碎片。堆和栈的对比从以上知识可知,栈是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活;而栈是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低。栈是系统数据结构,对于进程/线程是唯一的;堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloc函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的!堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存/释放内存匹配是良好程序的基本要素。所以计算机中的堆和栈经常时放一块讲的node 一般不是必要就不要动态创建,最讨厌是,C+中,把new出来的东西当局部变量用,用完了马上delete 的做法;最恶劣的是,JAVA中不断地new,然后等着GC来回收。理由1.栈分配比堆快,只需要一条指令就呢给配所有的局部变量2.栈不会出现内存碎片3.栈对象好管理当然,某些情况下也要那么写,比如1.对象很大2.对象需要在某个特定的时刻构造或析够3.类只允许对象动态创建,比如VCL的大多数类当然,必须用堆对象时也不能躲避对于类的申明(还没有定义)来说,可以有限的方式使用它。如我们可以声明指向该类类型的指针或引用。允许指针和引用是因为它们都有固定的大小,而与它们指向的对象的大小无关。只有到完全定义了该类才能对这些指针和引用解引用。 只有对类定义了,才能声明该类类型对象。在程序中还没有看到类定义之前,数据成员只能是该类类型的指针或引用。 当一个类的类头被看到时,它就被视为已经声明了,所以一个类可以有指向自身类型的指针或引用作为数据成员。只有一个类的类体已经完整时,它才被视为已经被定义。 所以可以有如下形式: class LinkScreen Screen window; LinkScreen *next; LinkScreen *prev; 16. 关键字static的作用是什么?这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:1). 在函数内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。2). 在模块内(但在函数外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。17. 静态变量(1)、静态全局变量在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。静态全局变量有以下特点:该变量在全局数据区分配内存;未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的;静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序代码区全局数据区堆区栈区一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静 态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:静态全局变量不能被其它文件所用;其它文件中可以定义相同名字的变量,不会发生冲突;(2)、静态局部变量【一句话解决】静态局部变量具有记忆性在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。example:void foo()static int a;a+;couta 6) ?puts( 6) : puts(6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。/u/20090216/20/bfa12d10-4800-4998-987d-31ac21dbc4fd.html位操作(Bit manipulation)21. 位操作嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。对这个问题有三种基本的反应1). 不知道如何下手。该被面者从没做过任何嵌入式系统的工作。2). 用bit fields。Bit fields是被扔到C语言死角的东西,它保证你的代码在不同编译器之间是不可移植的,同时也保证了的你的代码是不可重用的。我最近不幸看到 Infineon为其较复杂的通信芯片写的驱动程序,它用到了bit fields因此完全对我无用,因为我的编译器用其它的方式来实现bit fields的。从道德讲:永远不要让一个非嵌入式的家伙粘实际硬件的边。3). 用 #defines 和 bit masks 操作。这是一个有极高可移植性的方法,是应该被用到的方法。最佳的解决方案如下:#define BIT3 (0x13)/0000 1000static int a;void set_bit3(void) a |= BIT3;void clear_bit3(void) a &= BIT3;/1001 1011 &= 1111 0111 /a= 1001 0011一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是可以接受的。我希望看到几个要点:说明常数、|=和&=操作。访问固定的内存位置(Accessing fixed memory locations)22. 评价下面的代码片断:unsigned int zero = 0;unsigned int compzero = 0xFFFF;/*1s complement of zero */对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:unsigned int compzero = 0;这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。到了这个阶段,应试者或者完全垂头丧气了或者信心满满志在必得。如果显然应试者不是很好,那么这个测试就在这里结束了。但如果显然应试者做得不错,那么我就扔出下面的追加问题,这些问题是比较难的,我想仅仅非常优秀的应试者能做得不错。提出这些问题,我希望更多看到应试者应付问题的方法,而不是答案。不管如何,你就当是这个娱乐吧#include#includeint main(void) union A char a; char y:3; char z:3; char x:2; a; a.a = 0x67; printf(a.a =%0x a.x=%0x t a.y=%0xt a.z=%0xn,a.a, a.x, a.y, a.z ); return 0;结果a.a =67 a.x=ffffffff a.y=ffffffff a.z=ffffffffa.a =64 a.x=0 a.y=fffffffc a.z=fffffffca.a =65 a.x=1 a.y=fffffffd a.z=fffffffd如果单从位域来理解这个还是简单,问题的关键是理解其在计算机内的存取规则。对a.a=64, 单从取位(二进制)上可知a.x=00, a.y=101, a.z=101.目前通用计算机x86大都是32位机,我的机器也是32位,在存取上默认是存取32位。对每个数而言第一位是符号位,补码存储。那么可以理解a.x的补码就是00000000, a.y的补码就是11111100, a.z的补码就是11111100.这样看比较自然,但如果输出结果是10进制,就会觉得难以理解。当然关键还是对数据的存取规则和编码的熟悉。a.a=0x64的10进制结果是a.x=0, a.y=-4 ,a.z=-4补充一点,union内的变量顺序对结果不影响(每次只可能有一种解释是合理的,这个跟struct显然不同)2、关于位域在结构体的应用主要要注意内存对齐规则的理解和空域的理解使用位域的主要目的是压缩存储,其大致规则为:1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止; 2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍; 3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C+采取压缩方式; 4) 如果位域字段之间穿插着非位域字段,则不进行压缩; 5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。#include int main()union struct unsigned short s1:3; unsigned short s2:3; unsigned short s3:3; x; char c;v;v.c=100;printf(%dn,sizeof(v);printf(s1=%dn,v.x.s1);printf(s2=%dn,v.x.s2);printf(s3=%dn,v.x.s3);return 0;fc6-linux下gcc-4.1.12s1=4s2=4s3=5000000000110010001100100windows xp2下vc6.02s1=4s2=4s3=1可见s3的结果并不一样vc6.0的结果如果只是按位取,就很好理解,这样跟之前的union的存取规则又不一样了而对于gcc-4.1.1,s3=5还没想出该结果的原因。同时考虑struct unsigned short s1:3;unsigned short s2:3;unsigned short s3:3; unsigned short s4:7; x;第三大块:函数23. 通过函数修改变量的值具体面试题示例:如下,通过修改change函数的定义和调用,让第4行执行完,a的值编程13,p指向b。void change()/第5行,可以改 void main() int a = 10;/第1行,不许改 int b = 11; /第2行,不许改 int *p = &a; /第3行,不许改 change();/第4行,可以改【面试考察点】规则:如果通过函数修改一个变量的值,则需要传给这个函数变量的地址。这里的陷阱是,既要改变变量的值,还要改变指针的值。80%的学员错在:没有成功修改指针的值。其实这很好理解,指针不也是一种变量吗?void change(int *pp, int *p_b)/第5行,可以改 *pp = 13; *p = p_b;void main() int a = 10;/第1行,不许改 int b = 11; /第2行,不许改 int *p = &a; /第3行,不许改 change(&p, &b);/第4行,可以改【一句话摆平】通过函数改变变量的值,则需要传递变量的地址(即一级指针); 改变指针的值,则需要传递指针的地址(即二级指针);改变二级指针的值,则需要传递二级指针的地址(即三级指针);以此类推。这个题目是区分应届生和有编程经验人的标志。24. 库函数实现这里有三道题,我只重点分析第一道,其它两题的代码仅供参考 (1)已知strcpy的函数原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串,strSrc 是源字符串。不调用C+/C 的字符串库函数,请编写函数 strcpy。【点评】此问题或类似问题被问到的频率极高;首先要全部背上,一个字不能错(默写几遍);其次要彻底理解。答案:【注意点1】有的公司不提供函数声明,这里面试官考察两点:其一,是否有const,这涉及到参数的安全性,是否会有可能被函数修改(原则上,不允许被函数修改的入参,都需要用const限定!);其二,入参命名是否规范,首先从名字能看出谁是目的谁是源头,其次是从名字能看出是指针。char *strcpy(char *p_dst, const char *p_src) 【注意点2】这是函数step1:变量定义和赋值。 这个代码块的原则是:变量定义放在函数开始,且要初始化。在本函数中,先记录下指针,用来返回用char *p_temp = p_dst;【注意点3】这是函数step2:入参有效性检查,没有这一步的人直接被判死刑。 这个代码块的原则是:所有有可能的风险全部检测一遍,能发现多少就多少 在本函数中,本代码块须判断是否为空和地址是否重叠。判断为空时NULL放在等于号的前面,这是良好的工程习惯,常量在前。if (NULL = p_dst | NULL = p_src)return NULL ; if (p_dst = p_src) return p_dst; 【注意点4】这是函数step3:业务功能代码块。这是函数的功能主体。 这个代码块的原则是:用简洁易懂的语言来实现业务功能,且无漏洞 在本函数中,本代码块考察核心是:p_dst最后是否以0结尾。尽管代码写的没有突出这一点,但应聘时需要记住:所有字符串操作,都不要忘记结尾的0!很多学员面试卡在这个地方而不自知!while( (*p_dst + = * p_src +) != 0);【注意点5】这是函数step4

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论