超长!16个C语⾔经典问题分析与解答(收藏)
1. ⽤预处理指令#define 声明⼀个常数,⽤以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
我在这想看到⼏件事情:
#define 语法的基本知识(例如:不能以分号结束,括号的使⽤,等等)
懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算⼀年中有多少秒⽽不是计算出实际的值,是更清晰⽽没有代价的。
意识到这个表达式将使⼀个16位机的整型数溢出-因此要⽤到长整型符号L,告诉编译器这个常数是的长整型数。
如果你在你的表达式中⽤到UL(表⽰⽆符号长整型),那么你有了⼀个好的起点。记住,第⼀印象很重要。
2. 写⼀个“标准”宏MIN,这个宏输⼊两个参数并返回较⼩的⼀个。
#define MIN(A,B) ((A) <= (B) (A) : (B))
这个测试是为下⾯的⽬的⽽设的:
标识#define在宏中应⽤的基本知识。这是很重要的,因为直到嵌⼊(inline)操作符变为标准C的⼀部分,宏是⽅便产⽣嵌⼊代码的唯⼀⽅法,对于嵌⼊式系统来说,为了能达到要求的性能,嵌⼊代码经常是必须的⽅法。
三重条件操作符的知识。这个操作符存在C语⾔中的原因是它使得编译器能产⽣⽐if-then-else更优化的代码,了解这个⽤法是很重要的。
懂得在宏中⼩⼼地把参数⽤括号括起来
我也⽤这个问题开始讨论宏的副作⽤,例如:当你写下⾯的代码时会发⽣什么事?least = MIN(*p++, b);
3. 预处理器标识#error的⽬的是什么?
如果你不知道答案,请看参考⽂献
这问题对区分⼀个正常的伙计和⼀个书呆⼦是很有⽤的。只有书呆⼦才会读C语⾔课本的附录去出象这种问题的答案。当然如果你不是在⼀个书呆⼦,那么应试者最好希望⾃⼰不要知道答案。
4. 嵌⼊式系统中经常要⽤到⽆限循环,你怎么样⽤C编写死循环呢?
这个问题⽤⼏个解决⽅案。我⾸选的⽅案是:
⼀些程序员更喜欢如下⽅案:
这个实现⽅式让我为难,因为这个语法没有确切表达到底怎么回事。如果⼀个应试者给出这个作为⽅案,我将⽤这个作为⼀个机会去探究他们这样做的基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为什么。”这会给我留下⼀个坏印象。
第三个⽅案是⽤ goto
应试者如给出上⾯的⽅案,这说明或者他是⼀个汇编语⾔程序员(这也许是好事)或者他是⼀个想进⼊新领域的BASIC/FORTRAN程序员。
5. ⽤变量a给出下⾯的定义
a) ⼀个整型数(An integer)
b) ⼀个指向整型数的指针(A pointer to an integer)
c) ⼀个指向指针的的指针,它指向的指针是指向⼀个整型数(A pointer to a pointer to an integer)
d) ⼀个有10个整型数的数组(An array of 10 integers)
e) ⼀个有10个指针的数组,该指针是指向⼀个整型数的(An array of 10 pointers to integers)
f) ⼀个指向有10个整型数数组的指针(A pointer to an array of 10 integers)
g) ⼀个指向函数的指针,该函数有⼀个整型参数并返回⼀个整型数(A pointer to a function that takes an integer as an argument and returns an integer)
h) ⼀个有10个指针的数组,该指针指向⼀个函数,该函数有⼀个整型参数并返回⼀个整型数( An array of ten pointers to functions that take an integer argument and return an integer )
答案是:
a) int a; // An integer
b)int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
⼈们经常声称这⾥有⼏个问题是那种要翻⼀下书才能回答的问题,我同意这种说法。当我写这篇⽂章时,为了确定语法的正确性,我的确查了⼀下书。
但是当我被⾯试的时候,我期望被问到这个问题(或者相近的问题)。因为在被⾯试的这段时间⾥,我确定我知道这个问题的答案。应试者如果不知道所有的答案(或⾄少⼤部分答案),那么也就没有为这次⾯试做准备,如果该⾯试者没有为这次⾯试做准备,那么他⼜能为什么出准备呢?
c语言如何去学6. 关键字static的作⽤是什么?
这个简单的问题很少有⼈能回答完全。在C语⾔中,关键字static有三个明显的作⽤:
在函数体,⼀个被声明为静态的变量在这⼀函数被调⽤过程中维持其值不变。
在模块内(但在函数体外),⼀个被声明为静态的变量可以被模块内所⽤函数访问,但不能被模块外其它函数访问。它是⼀个本地的全局变量。
在模块内,⼀个被声明为静态的函数只可被这⼀模块内的其它函数调⽤。那就是,这个函数被限制在声明它的模块的本地范围内使⽤。
⼤多数应试者能正确回答第⼀部分,⼀部分能正确回答第⼆部分,同是很少的⼈能懂得第三部分。这是⼀个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。
7.关键字const是什么含意?
我只要⼀听到被⾯试者说:“const意味着常数”,我就知道我正在和⼀个业余者打交道。去年Dan Saks已经在他的⽂章⾥完全概括了const的所有⽤法,因此ESP(译者:Embedded Systems Programming)的每⼀位读者应该⾮常熟悉const能做什么和不能做什么.如果你从没有读到那篇⽂章,只要能说出con
st意味着“只读”就可以了。尽管这个答案不是完全的答案,但我接受它作为⼀个正确的答案。(如果你想知道更详细的答案,仔细读⼀下Saks的⽂章吧。)如果应试者能正确回答这个问题,我将问他⼀个附加的问题:下⾯的声明都是什么意思?
前两个的作⽤是⼀样,a是⼀个常整型数。第三个意味着a是⼀个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是⼀个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后⼀个意味着a是⼀个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。
如果应试者能正确回答这些问题,那么他就给我留下了⼀个好印象。顺带提⼀句,也许你可能会问,即使不⽤关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的⼏下理由:
关键字const的作⽤是为给读你代码的⼈传达⾮常有⽤的信息,实际上,声明⼀个参数为常量是为了告
诉了⽤户这个参数的应⽤⽬的。
如果你曾花很多时间清理其它⼈留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得⽤const的程序员很少会留下的垃圾让别⼈来清理的。)
通过给优化器⼀些附加的信息,使⽤关键字const也许能产⽣更紧凑的代码。
合理地使⽤关键字const可以使编译器很⾃然地保护那些不希望被改变的参数,防⽌其被⽆意的代码修改。简⽽⾔之,这样可以减少bug的出现。
有个好的记忆办法,如:const char *a通过顺时针旋转,可以看出const离a最近,即const修饰常量a.
如果const关键字不涉及到指针,我们很好理解,下⾯是涉及到指针的情况:
如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的⼀步。不知道,也没关系,我们
可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是⽤来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本⾝,即指针本⾝是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置⽆关),这种情况下不允许对内容进⾏更改操作,如不能*a = 3 ;[3]为指针本⾝是常量,⽽指针所指向的内容不是常量,这种情况下不能对指针本⾝进⾏更改操作,如a++是错误的;[4]为指针本⾝和指向的内容均为常量。
8. 关键字volatile有什么含意并给出三个不同的例⼦。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论