嵌入式linux工程师面试题目C语言基础部分Word文档下载推荐.docx
- 文档编号:16170059
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:13
- 大小:27.06KB
嵌入式linux工程师面试题目C语言基础部分Word文档下载推荐.docx
《嵌入式linux工程师面试题目C语言基础部分Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《嵌入式linux工程师面试题目C语言基础部分Word文档下载推荐.docx(13页珍藏版)》请在冰豆网上搜索。
chararray[5]={'
1'
'
2'
3'
4'
5'
};
或者chararray[5]={"
12345"
或者chararray[2][10]={"
China"
"
Beijing"
也许更符合“初始化”的意思。
最简单的方法是:
chararray[5];
意思是分配给数组array一个5个字节的空间。
但是我们要知道在C中数组其实就是一个名字,其实质含义就是指针,比如chararray[];
是到底分配的多少空间?
所以我们要将其分成为两种不同的形式给出答案:
一种是栈的形式:
一种是堆的形式:
char*array;
array=(char*)malloc(5);
//C++:
array=newchar[5];
堆和栈的含义其实我也没弄太透彻,改天明白了再发一篇。
我们要明白的是,第一种形式空间分配的大小可能会受操作系统的限制,比如windows会限制在2M;
第二种形式成空间分配很灵活,想分配多少分配多少,只要RAM够大。
首先明确一个概念,就是指向数组的指针,和存放指针的数组。
指向数组的指针:
char(*array)[5];
含义是一个指向存放5个字符的数组的指针。
存放指针的数组:
char*array[5];
含义是一个数组中存放了5个指向字符型数据的指针。
按照题意,我理解为初始化一个存放指针的数组,char*array[2]={"
};
其含义是初始化了一个有两个指向字符型数据的指针的数组,这两个指针分别指向字符串"
和"
既然只是定义而不是初始化,那就很简单且没有争议了:
int*array[10];
前面说过了,数组和指针其实是数据存在形态的两种表现形式,如果说对于数组s[],我们知道*s=s[0],那么s[10]的另一种表达方式就是:
*(s+10)。
这个问题实在变态,就像问你#error的作用是什么一样。
不可否认,gcc是linux下一个亮点,是一个备受无数程序员推崇的编译器,其优点省略1000字,有兴趣可以自己查,我翻了翻书,书上曰:
支持C,C++,Java,Obj-C,Ada,Fortran,Pascal,Modula-3等语言,这个“等”比较要命,不过我认为已经很全了,如果认为还是不全,干脆把ASM也加上算了,不过那已经不算是编译了。
如果结合上面的问题,答题的人估计会认为自己撞鬼了,这个问题实在是……搜索了一下,应该是limits.h。
其实不同的取整函数可能有不同的结果,不过这个数没有太大的争议,答案是-1。
具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。
这个问题说实话不是很理解题干的意思,据我理解,有两种情况,一种是预处理阶段,用#define定义;
还有就是使用const修饰词,不过const修饰的是一个变量,其含义是“只读”,称之为常量并不准确,但是确实可以用操作变量的方法当常量用。
所以还是第一种比较靠谱。
这个问题也问的挺含糊的,怎么说呢,最简单最直接的方法是为变量添加extern修饰词,当然,这个变量必须是全局变量。
还有一种就是利用函数调用来进行变量的间接引用,比如这个C文件中的一个函数引用另外一个C中的函数,将变量通过实参的形式传递过去。
不过题目既然说是引用,那么还是用第一个答案好了。
其实准备工作很多啊,比如你需要一台计算机之类的。
玩笑话,我们首先要知道malloc的用途,简单的说就是动态的分配一段空间,返回这段空间的头指针。
实际的准备工作可以这么分:
需要这段空间的指针是否存在,若不存在,则定义一个指针用来被赋值,还要清楚要返回一个什么类型的指针,分配的空间是否合理;
如果指针已经存在,那么在重新将新的空间头地址赋值给这个指针之前,要先判断指针是否为NULL,如果不是要free一下,否则原来的空间就会被浪费,或者出错,free之后就按照前一种情形考虑就可以了。
这个函数我也才知道的,汗一个。
据我的初步理解,这个函数的作用是重新分配空间大小,返回的头指针不变,只是改变空间大小。
既然是改变,就有变大、变小和为什么改变的问题。
变大,要注意不能大到内存溢出;
变小,那变小的那部分空间会被征用,原有数据不再存在;
为什么改变,如果是想重新挪作他用,还是先free了吧。
这个问题我不知道能不能回答全面,因为实在是用的很少。
这个函数的作用是分割字符串,但是要分割的字符串不能是常量,这是要注意的。
比如先定义一个字符串:
chararray[]="
part1,part2"
;
,strtok的原形是char*strtok(char*string,char*delim);
,我们将"
作为分隔符,先用pt=strtok(array,"
);
,得到的结果print出来就是"
part1"
,那后面的呢,要写成pt=strtok(NULL,"
,注意,要用NULL,如果被分割的字符串会被分成N段,那从第二次开始就一直要用NULL。
总结起来,需要注意的是:
被分割的字符串和分隔符都要使用变量;
除第一次使用指向字符串的指针外,之后的都要使用NULL;
注意使用这个函数的时候千万别把指针跟丢了,不然就全乱了。
这是一个键盘输入函数,将输入字符串的头地址返回。
说到要注意的问题,我还是先查了一下网上的一些情况,需要注意的就是gets以输入回车结束,这个地球人都知道,但是很多人不知道的是,当你输入完一个字符串后,这个字符串可能依然存在于这个标准输入流之中,当再次使用gets的时候,也许会把上次输入的东西读出来,所以应该在使用之后用fflush(stdin);
处理一下,将输入流清空。
最后也还是要注意溢出的问题。
关于这个答案我比较含糊,不知道有没有高人高见?
我无语……闻所未闻啊……还是搜索了一下,有一篇文章,地址是:
http:
//202.117.80.9/jp2005/20/kcwz/wlkc/wlkc/03/3_5_2.htm,是关于词法分析器的。
其中提到了两点策略:
(1)按最长匹配原则确定被选的词型;
(2)如果一个字符串能为若干个词型匹配,则排列在最前面的词型被选中。
不知道是不是题干的要求,还是其他什么。
我乃一介草民,望达人指点迷津!
这个东西(称之为东西一点都不过分)其实并没有语法错误,按照C对运算符等级的划分,++的优先级大于+,那么这句话会被编译器看做:
(a++)+(++b),这回明白了吧。
有什么问题,语法上没有问题,有的是道德上的问题!
作为一个优秀的程序员,我们要力求语句的合法性和可读性,如果写这句的人是在一个team里,那么他基本会被打的半死……最后讨论一下结果:
假设a之前的值是3,b是4,那么运行完这个变态语句后,a的值是4,b是5,语句的结果是8。
不知道这个题有什么陷阱,写到现在神经已经大了,一般来说先要把TURE和FALSE给定义了,使用#define就可以:
#defineTURE1
#defineFALSE0
如果有一个变量需要定义成bool型的,举个例子:
boola=TURE;
就可以了。
首先,这个题干抽了10题回答的一个大嘴巴。
关于常量的概念看来我要好好看看书了……我说过了,const修饰词可以将一个变量修饰为“只读”,这个就能称为常量么?
姑且认为可以。
回到题目中,const是只读的意思,它限定一个变量不允许被改变,谁都不能改!
既然是修饰变量,那么变量的类型就可以丰富多彩,int啊,char啊,只要C认识的都可以;
但是#define就不可以了,在预处理阶段缺乏类型检测机制,有可能会出错。
还有就是变量可以extern,但是#define就不可以。
貌似const还可以节省RAM,这个我倒是没有考证过。
至于const的用法和作用,有很多,我会总结后发上来。
终于最后一题了,容易么……如果这个测试是一个关于嵌入式的,那么这道题非常重要!
!
从词面上讲,volatile的意思是易变的,也就是说,在程序运行过程中,有一些变量可能会被莫名其妙的改变,而优化器为了节约时间,有时候不会重读这个变量的真实值,而是去读在寄存器的备份,这样的话,这个变量的真实值反而被优化器给“优化”掉了,用时髦的词说就是被“和谐”了。
如果使用了这个修饰词,就是通知编译器别犯懒,老老实实去重新读一遍!
可能我说的太“通俗”了,那么我引用一下“大师”的标准解释:
volatile的本意是“易变的”。
由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。
当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。
而且读取的数据立刻被保存。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
下面是volatile变量的几个例子:
1).并行设备的硬件寄存器(如:
状态寄存器)
2).一个中断服务子程序中会访问到的非自动变量(Non-automaticvariables)
3).多线程应用中被几个任务共享的变量
嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。
不懂得volatile内容将会带来灾难。
C语言测试是招聘嵌入式系统程序员过程中必须而且有效的方法。
这些年,我既参加也组织了许多这种测试,在这过程中我意识到这些测试能为面试者和被面试者提供许多有用信息,此外,撇开面试的压力不谈,这种测试也是相当有趣的。
从被面试者的角度来讲,你能了解许多关于出题者或监考者的情况。
这个测试只是出题者为显示其对ANSI标准细节的知识而不是技术技巧而设计吗?
这是个愚蠢的问题吗?
如要你答出某个字符的ASCII值。
这些问题着重考察你的系统调用和内存分配策略方面的能力吗?
这标志着出题者也许花时间在微机上而不是在嵌入式系统上。
如果上述任何问题的答案是"
是"
的话,那么我知道我得认真考虑我是否应该去做这份工作。
从面试者的角度来讲,一个测试也许能从多方面揭示应试者的素质:
最基本的,你能了解应试者C语言的水平。
不管怎么样,看一下这人如何回答他不会的问题也是满有趣。
应试者是以好的直觉做出明智的选择,还是只是瞎蒙呢?
当应试者在某个问题上卡住时是找借口呢,还是表现出对问题的真正的好奇心,把这看成学习的机会呢?
我发现这些信息与他们的测试成绩一样有用。
有了这些想法,我决定出一些真正针对嵌入式系统的考题,希望这些令人头痛的考题能给正在找工作的人一点帮助。
这些问题都是我这些年实际碰到的。
其中有些题很难,但它们应该都能给你一点启迪。
这个测试适于不同水平的应试者,大多数初级水平的应试者的成绩会很差,经验丰富的程序员应该有很好的成绩。
为了让你能自己决定某些问题的偏好,每个问题没有分配分数,如果选择这些考题为你所用,请自行按你的意思分配分数。
预处理器(Preprocessor)
1.用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#defineSECONDS_PER_YEAR(60*60*24*365)UL
我在这想看到几件事情:
1)#define语法的基本知识(例如:
不能以分号结束,括号的使用,等等)
2)懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
3)意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
4)如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。
记住,第一印象很重要。
2.写一个"
标准"
宏MIN,这个宏输入两个参数并返回较小的一个。
#defineMIN(A,B)((A)<
=(B)?
(A):
(B))
这个测试是为下面的目的而设的:
1)标识#define在宏中应用的基本知识。
这是很重要的。
因为在嵌入(inline)操作符变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。
2)三重条件操作符的知识。
这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。
3)懂得在宏中小心地把参数用括号括起来
4)我也用这个问题开始讨论宏的副作用,例如:
当你写下面的代码时会发生什么事?
least=MIN(*p++,b);
3.预处理器标识#error的目的是什么?
如果你不知道答案,请看参考文献1。
这问题对区分一个正常的伙计和一个书呆子是很有用的。
只有书呆子才会读C语言课本的附录去找出象这种问题的答案。
当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。
死循环(Infiniteloops)
4.嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
这个问题用几个解决方案。
我首选的方案是:
while
(1)
{
}
一些程序员更喜欢如下方案:
for(;
)
这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。
如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。
如果他们的基本答案是:
"
我被教着这样做,但从没有想到过为什么。
这会给我留下一个坏印象。
第三个方案是用goto
Loop:
...
gotoLoop;
应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。
数据声明(Datadeclarations)
5.用变量a给出下面的定义
a)一个整型数(Aninteger)
b)一个指向整型数的指针(Apointertoaninteger)
c)一个指向指针的的指针,它指向的指针是指向一个整型数(Apointertoapointertoanintege)r
d)一个有10个整型数的数组(Anarrayof10integers)
e)一个有10个指针的数组,该指针是指向一个整型数的。
(Anarrayof10pointerstointegers)
f)一个指向有10个整型数数组的指针(Apointertoanarrayof10integers)
g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数(Apointertoafunctionthattakesanintegerasanargumentandreturnsaninteger)
h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数(Anarrayoftenpointerstofunctionsthattakeanintegerargumentandreturnaninteger)
答案是:
a)inta;
//Aninteger
b)int*a;
//Apointertoaninteger
c)int**a;
//Apointertoapointertoaninteger
d)inta[10];
//Anarrayof10integers
e)int*a[10];
//Anarrayof10pointerstointegers
f)int(*a)[10];
//Apointertoanarrayof10integers
g)int(*a)(int);
//Apointertoafunctionathattakesanintegerargumentandreturnsaninteger
h)int(*a[10])(int);
//Anarrayof10pointerstofunctionsthattakeanintegerargumentandreturnaninteger
人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这种说法。
当我写这篇文章时,为了确定语法的正确性,我的确查了一下书。
但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。
因为在被面试的这段时间里,我确定我知道这个问题的答案。
应试者如果不知道所有的答案(或至少大部分答案),那么也就没有为这次面试做准备,如果该面试者没有为这次面试做准备,那么他又能为什么出准备呢?
Static
6.关键字static的作用是什么?
这个简单的问题很少有人能回答完全。
在C语言中,关键字static有三个明显的作用:
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。
它是一个本地的全局变量。
3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。
那就是,这个函数被限制在声明它的模块的本地范围内使用。
大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。
这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。
Const
7.关键字const有什么含意?
我只要一听到被面试者说:
const意味着常数"
,我就知道我正在和一个业余者打交道。
去年DanSaks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:
EmbeddedSystemsProgramming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着"
只读"
尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。
(如果你想知道更详细的答案,仔细读一下Saks的文章吧。
如果应试者能正确回答这个问题,我将问他一个附加的问题:
下面的声明都是什么意思?
constinta;
intconsta;
constint*a;
int*consta;
intconst*aconst;
/******/
前两个的作用是一样,a是一个常整型数。
第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。
第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。
顺带提一句,也许你可能会问,即使不用关键字const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?
我也如下的几下理由:
1)关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。
如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。
(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。
2)通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3)合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。
简而言之,这样可以减少bug的出现。
Volatile
8.关键字volatile有什么含意?
并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。
1)并行设备的硬件寄存器(如:
2)一个中断服务子程序中会访问到的非自动变量(Non-automaticvariables)
3)多线程应用中被几个任务共享的变量
回答不出这个问题的人是不会被雇佣的。
我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。
搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道,所有这些都要求用到volatil
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式 linux 工程师 面试 题目 语言 基础 部分