c语言常见面试题 几个常见的C语言面试题分析
\u8425\u9500\u7b56\u5212\u5e38\u89c1\u9762\u8bd5\u9898\u6709\u54ea\u4e9b\uff1f\u8425\u9500\u7b56\u5212\u5e38\u89c1\u9762\u8bd5\u9898\u6709\u5f88\u591a\uff0c\u6bd4\u5982\uff1a
1\u3001\u4f60\u600e\u4e48\u6837\u5904\u7406\u4e0a\u4e0b\u7ea7\u4e4b\u95f4\u7684\u51b2\u7a81\u6216\u662f\u4e0e\u5ba2\u6237\u4e4b\u95f4\u7684\u51b2\u7a81?\u8bf7\u4e3e\u4e00\u4e2a\u5b9e\u4f8b\u8bf4\u660e\u3002
\u56de\u7b54\uff1a\u5728\u5904\u7406\u4e0a\u4e0b\u7ea7\u51b2\u7a81\u65f6\uff0c\u6211\u8ba4\u4e3a\u53cc\u65b9\u90fd\u5e94\u5c3d\u91cf\u505a\u5230\u6362\u4f4d\u601d\u8003\u3002\u5373\u4f7f\u4e8b\u60c5\u7d27\u6025\uff0c\u53cc\u65b9\u706b\u6c14\u4e0a\u5934\uff0c\u4e5f\u8981\u5c3d\u91cf\u51b7\u9759\u4e0b\u6765\uff0c\u5e76\u5c3d\u5feb\u5730\u601d\u8003\u77db\u76fe\u7684\u6838\u5fc3\u662f\u4ec0\u4e48\uff0c\u600e\u4e48\u89e3\u51b3\uff0c\u800c\u4e0d\u662f\u62c9\u5f00\u67b6\u52bf\u4e89\u5435\u2014\u2014\u81f3\u5c11\u53cc\u65b9\u4e2d\u6709\u4e00\u4eba\u8981\u505a\u5230\u3002
2\u3001\u4f60\u4f1a\u4e3a\u4ec0\u4e48\u800c\u79bb\u804c?\u4f60\u5bf9\u5f85\u5de5\u4f5c\u7684\u611f\u60f3\u6216\u662f\u611f\u53d7\u662f\u4ec0\u4e48?\u4ec0\u4e48\u8ba9\u4f60\u6700\u53d7\u632b\u6298?
\u56de\u7b54\uff1a\u6211\u4f1a\u56e0\u4e3a\uff0c\u516c\u53f8\u7684\u6587\u5316\uff0c\u53d1\u5c55\u65b9\u5411\uff0c\u5de5\u4f5c\u73af\u5883\u4ee5\u53ca\u6211\u7684\u5bb6\u5ead\u800c\u79bb\u804c\uff0c\u6211\u8ba4\u4e3a\u5de5\u4f5c\u5c31\u662f\u8981\u81ea\u5df1\u505a\u7740\u8212\u670d\u5bb6\u4eba\u670b\u53cb\u652f\u6301\uff0c\u6211\u6240\u505a\u7684\u5de5\u4f5c\u80fd\u591f\u7ed9\u516c\u53f8\u6216\u4ed6\u4eba\u5e26\u6765\u6548\u76ca\uff0c\u8fd9\u6837\u5de5\u4f5c\u624d\u6709\u610f\u4e49\u3002\u5728\u5de5\u4f5c\u4e2d\u6700\u8ba9\u6211\u53d7\u63aa\u7684\u662f\u6211\u7684\u52aa\u529b\u5f97\u4e0d\u5230\u8ba4\u53ef\u3002
3\u3001\u4f60\u8d1f\u8d23\u8fc7\u54ea\u4e9b\u8425\u9500\u63a8\u5e7f\u6d3b\u52a8\u7684\u9879\u76ee?\u91cd\u70b9\u9879\u76ee\u4e2d\u8d1f\u8d23\u54ea\u4e9b\u9636\u6bb5?\u81ea\u5df1\u5145\u5f53\u7684\u89d2\u8272?\u4e1a\u7ee9?
\u56de\u7b54\uff1a11\u5e74\u5230\u4eca\u5e74\u56db\u6708\u4efd\u5728\u4e00\u5bb6\u5c0f\u989d\u8d37\u6b3e\u516c\u53f8\u5de5\u4f5c;\u56e0\u4e3a\u662f\u5185\u52e4\u7684\u804c\u52a1\uff0c\u4e1a\u52a1\u81ea\u5df1\u4e5f\u90fd\u8054\u7cfb;\u672c\u8eab\u516c\u53f8\u4e1a\u52a1\u79cd\u7c7b\u5c11\u6240\u4ee5\u6210\u5355\u7387\u4e0d\u662f\u5f88\u9ad8\uff0c\u6211\u7684\u539f\u5219\u662f\u53ea\u6709\u820d\u624d\u6709\u5f97\uff0c\u6240\u4ee5\u4e00\u822c\u516c\u53f8\u4e0d\u505a\u7684\u4e1a\u52a1\u7ed9\u540c\u884c\u4ed6\u4eec\u624d\u4f1a\u7ed9\u6211;\u81ea\u5df1\u51fa\u94b1\u505a\u4e86\u6d77\u62a5\u5e16\u5b50\u4ea4\u901a\u8981\u9053\u7684\u62a5\u520a\u4ead\u7684\u6a71\u7a97\u91cc;\u672c\u8eab\u8fd9\u5c31\u4e0d\u662f\u7acb\u7aff\u89c1\u5f71\u7684\u4ea7\u54c1\uff0c\u5927\u6982\u4e00\u5e74\u5185\u901a\u8fc7\u5e7f\u544a\u8fd9\u4e2a\u65b9\u5f0f\u8d62\u5f97\u7684\u4e1a\u52a1\u5927\u6982\u6709\u516d-\u516b\u5355;\u6211\u5f88\u559c\u6b22\u6311\u6218\u521b\u65b0\uff0c\u5927\u5bb6\u90fd\u7528\u7684\u65b9\u5f0f\u4e0d\u662f\u6ca1\u7528\u6548\u679c\u53ea\u662f\u6ca1\u6709\u90a3\u4e48\u5bb9\u6613\u89c1\u6548;\u4e3a\u5176\u5954\u6ce2\u7684\u8fc7\u7a0b\u4ece\u5185\u5fc3\u91cc\u662f\u5341\u5206\u7684\u9ad8\u5174\uff0c\u6211\u81ea\u5df1\u60f3\u505a\u7684\u53bb\u505a\u4e86\u5e76\u6536\u5230\u4e86\u76f8\u5e94\u7684\u56de\u62a5\u6240\u6709\u5f88\u9ad8\u5174;\u5927\u5b66\u671f\u95f4\u4efb\u8fc7\u517c\u804c\u5728\u5b66\u6821\u8d85\u5e02\u91cc\u505a\u6536\u94f6\u5458\uff0c\u56e0\u4e3a\u53d1\u751f\u8fc7\u4e00\u6b21\u7cd5\u70b9\u8fc7\u671f\u7684\u95ee\u9898\uff0c\u5b66\u751f\u5e26\u4e86\u4e03\u516b\u4e2a\u540c\u5b66\u8fc7\u6765\u800c\u4e14\u7684\u6001\u5ea6\u4e0d\u662f\u5f88\u597d\u3002\u6211\u8bf4\u7ed9\u4ed6\u9000\u4e86\u518d\u6362\u4e00\u5757\uff0c\u4ed6\u4e0d\u662f\u5f88\u6ee1\u610f;\u4e0d\u4f46\u5411\u5176\u9053\u6b49\u6700\u540e\u7ed9\u4e86\u4ed6\u4e94\u5757\u7cd5\u70b9\u3002\u6211\u4eec\u7684\u5ba2\u6237\u5bf9\u8c61\u5c31\u662f\u5b66\u751f\uff0c\u4e0d\u80fd\u56e0\u6b64\u800c\u9020\u6210\u6d88\u6781\u7684\u5f71\u54cd;\u8ba9\u7ade\u4e89\u5bf9\u624b\u800c\u6709\u53ef\u4e58\u4e4b\u673a\u3002
4\u3001\u5047\u8bbe\u4f60\u662f\u9886\u5bfc\uff0c\u4f60\u5982\u4f55\u5224\u65ad\u4ed6\u662f\u5426\u5408\u9002\u8be5\u5c97\u4f4d?\u91cd\u8981\u8003\u6838\u6307\u6807\u6709\u54ea\u4e9b?
\u56de\u7b54\uff1a\u9996\u5148\u4ece3\u5927\u65b9\u9762\u8003\u8651\uff0c\u6001\u5ea6\uff0c\u4eba\u54c1\uff0c\u5b9e\u529b\u3002\u7b2c\u4e00\uff0c\u6001\u5ea6\uff0c\u5982\u679c\u4e00\u4e2a\u4eba\u62e5\u6709100\u7684\u624d\u534e\u4f46\u662f\u4ed6\u5e76\u4e0d\u559c\u6b22\u8fd9\u5de5\u4f5c\u53ea\u53d1\u632520%\uff0c\u4f46\u662f\u53e6\u5916\u4e00\u4e2a\u4eba\u53ea\u62e5\u670950\u7684\u624d\u534e\u4f46\u662f\u4ed6\u559c\u6b22\u8fd9\u5de5\u4f5c\u80fd\u53d1\u632540%\u3002\u6211\u5b81\u613f\u8981\u540e\u8005\u3002(\u5f53\u7136\u5982\u679c\u524d\u8005\u53ef\u4ee5\u57f9\u517b\u5174\u8da3\u6216\u8005\u901a\u8fc7\u5176\u4ed6\u65b9\u9762\u6fc0\u53d1\u4ed6\u7684\u5de5\u4f5c\u79ef\u6781\u6027\u90a3\u4e48\u9700\u8981\u989d\u5916\u8003\u8651)\u7b2c\u4e8c\uff0c\u4eba\u54c1\uff0c\u5982\u679c\u4e00\u4e2a\u4eba\u8bda\u4fe1\u503c\u5f97\u5546\u69b7\u90a3\u4e48\u8fd9\u4e2a\u4eba\u7684\u80fd\u529b\u8d8a\u5f3a\uff0c\u53cd\u800c\u5bf9\u516c\u53f8\u7684\u5371\u5bb3\u8d8a\u5927\u3002\u516c\u53f8\u9700\u8981\u4e2a\u4eba\u624d\u6211\u60f3\u9996\u5148\u8003\u8651\u7684\u662f\u5fe0\u8bda\uff0c\u53ef\u9760\uff0c\u800c\u5b9e\u529b\u662f\u653e\u5728\u7b2c\u4e8c\u4f4d\u7684\u3002\u7b2c\u4e09\uff0c\u5b9e\u529b\uff0c\u524d\u4e24\u8005\u8003\u8651\u8fc7\u540e\u90a3\u4e48\u5b9e\u529b\u5f53\u7136\u662f\u6700\u91cd\u8981\u7684\u4e86\uff0c\u65e0\u8bba\u54ea\u4e2a\u5730\u65b9\u90fd\u662f\u5b9e\u529b\u8005\u624d\u80fd\u751f\u5b58\u7684\u6cd5\u5219\u3002\u5b9e\u529b\u624d\u662f\u7efc\u5408\u6027\u4f53\u73b0\u81ea\u5df1\u624d\u80fd\u7684\u9014\u5f84\u3002\u65e0\u8bba\u54ea\u4e2a\u516c\u53f8\u90fd\u4e0d\u4f1a\u8981\u4e00\u4e2a\u6ca1\u7528\u7684\u4eba\u3002
\u90a3\u4e48\u73b0\u5728\u8003\u8651\u662f\u5426\u9002\u5408\u5c97\u4f4d\uff0c\u4ece\u4ee5\u4e0a3\u70b9\uff0c\u5982\u679c\u8fd9\u4e2a\u4eba\u559c\u6b22\u8fd9\u4e2a\u5c97\u4f4d\uff0c\u800c\u4e14\u4eba\u54c1\u503c\u5f97\u4fe1\u4efb\uff0c\u6700\u540e\u4ed6\u62e5\u6709\u505a\u597d\u8fd9\u4e2a\u5c97\u4f4d\u7684\u5b9e\u529b\u90a3\u4e48\u4ed6\u5c31\u662f\u5408\u9002\u7684\u3002
\u4e00\u6b21\u53bb\u4e00\u4e2a\u5c0f\u516c\u53f8\u9762\u8bd5\uff0c\u6ca1\u6709\u592a\u91cd\u89c6\uff0c\u5f53\u65f6\u7531\u4e8e\u5de5\u4f5c\u751a\u5fd9\uff0c\u4e5f\u6ca1\u4f5c\u51c6\u5907\u3002\u4ed6\u4eec\u7ed9\u6211\u7684\u8bd5\u5377\u6709\u5927\u91cf\u7684\u9898\uff0c\u89c4\u5b9a\u4e00\u4e2a\u5c0f\u65f6\u5fc5\u987b\u505a\u5b8c\uff0c\u4e00\u770b\u9898\u91cf\uff0c\u5413\u4e86\u4e00\u5927\u8df3\uff0c\u9898\u6709\u94fe\u8868\uff0c\u6709\u591a\u7ef4\u6570\u7ec4\uff0c\u6709\u5927\u91cf\u7684\u7a0b\u5e8f\u9605\u8bfb\uff0c\u5e78\u4e8f\u57fa\u672c\u529f\u8fd8\u7b97\u624e\u5b9e\uff0c\u672a\u8fb1\u4f7f\u547d\uff0c\u5dee\u5f3a\u5b8c\u6210\u3002\u7b49\u5230\u505a\u5230\u7f16\u7a0b\u9898\u65f6\uff0c\u624d\u53d1\u73b0\u81ea\u5df1\u592a\u957f\u65f6\u95f4\u6ca1\u6709\u5199\u8fc7\u7a0b\u5e8f\u4e86\uff0c\u8ba9\u4e00\u4e9b\u7410\u788e\u7684\u6539BUG\u5de5\u4f5c\u548c\u4ee3\u7801\u7ef4\u62a4\u6d6a\u8d39\u4e86\u592a\u591a\u7684\u7cbe\u529b\u3002\u4e00\u76f4\u505a\u4e0b\u53bb\uff0c\u5fc3\u91cc\u6697\u6697\u5403\u60ca\uff0c\u4e00\u4e2a\u5c0f\u65f6\uff0c\u8fd9\u4e2a\u9898\u91cf\u5982\u679c\u662f\u5728\u521a\u6bd5\u4e1a\u65f6\uff0c\u8fd8\u662f\u6709\u53ef\u80fd\u5b8c\u6210\u7684\uff0c\u5de5\u4f5c\u51e0\u5e74\u540e\uff0c\u538b\u529b\u6e10\u5c0f\uff0c\u5199\u7a0b\u5e8f\u57fa\u672c\u90fd\u662f\u62ff\u6765\u4e3b\u4e49\uff0c\u5bf9\u6807\u51c6\u5e93\u51fd\u6570\u7684\u539f\u7406\u628a\u63e1\u548c\u7f16\u7a0b\u80fd\u529b\u8d8a\u6765\u8d8a\u9000\u5316\u3002\u7531\u4e8e\u5f53\u65f6\u65f6\u95f4\u7d27\u8feb\uff0c\u6240\u5199\u7a0b\u5e8f\u4e5f\u4e0d\u591f\u5b8c\u5584\uff0c\u8fc7\u540e\u53c8\u601d\u8003\u4e86\u4e00\u4e0b\uff0c\u56de\u5230\u5bb6\u540e\u8d76\u7d27\u53c8\u5bf9\u8fd9\u4e9b\u95ee\u9898\u603b\u7ed3\u4e86\u4e00\u4e0b\u3002\u4e0b\u9762\u5bf9\u9762\u8bd5\u4e2d\u9047\u5230\u7684\u7f16\u7a0b\u95ee\u9898\u5206\u6790\u4e86\u4e00\u4e0b\u3002\u771f\u662f\u4eba\u5728\u793e\u4f1a\u5982\u6c5f\u6e56\u5440\uff0c\u5b66\u4e60\u662f\u4e00\u523b\u4e5f\u4e0d\u80fd\u653e\u677e\u7684\u4e8b\u3002\u7a0d\u4e00\u4e0d\u614e\uff0c\u665a\u8282\u4e0d\u4fdd\u4e0d\u8bf4\uff0c\u53cd\u800c\u4f1a\u9634\u6c9f\u91cc\u7ffb\u8239\u3002
1.\u83b7\u53d6\u8def\u5f84\u4e0b\u7684\u6587\u4ef6\u540d
char * FindFileName(char * s)
{
int len;
char *tmp=NULL;
ASSERT(s != NULL);
for (len=strlen(s); len>0;len--)
{
if((s[len]=='/') ||(s[len]=='//'))
{
tmp = &s[len+1];
break;
}
}
return tmp;
}
2.\u628a\u6574\u578b\u8f6c\u5316\u4e3a\u5b57\u7b26\u578b
char * i2a(int n, char *s)
{
int i, sign;
ASSERT(s != NULL);
if ((sign = n) < 0)
{
n = -n; //\u8f6c\u4e3a\u6b63\u6570\uff0c\u5229\u4e8e\u53d6\u4f4d
}
do
{
s[i++] = n % 10 + '0';
}
while ((n /= 10) > 0)
if (sign < 0)
{
s[i++] = '-';
}
s[i] = '/0';
reverse(s);
}
3.\u628a\u5b57\u7b26\u578b\u8f6c\u4e3a\u6574\u578b
int a2i(char * s)
{
int i, n, sign;
ASSERT(s != NULL);
for (i = 0; s[i] == ' '; i++)
{
NULL; //\u5982\u679c\u5b57\u4e32\u524d\u6709\u7a7a\u683c\uff0c\u8df3\u8fc7\u6240\u6709\u7a7a\u683c
}
sign = (s[i] == '-') ?: -1 : 1;
if (s[i] == '+' || s[i] == '-')
{
i++; //\u5224\u65ad\u662f\u6b63\u6574\u6570\u4e32\u8fd8\u662f\u8d1f\u6574\u6570\u4e32
}
for (n = 0; s[i] > = '0' && s[i] <= '9'; i++)
{
n = 10 * n + (s[i] - '0');
}
return sign*n;
}
4.\u8f93\u51fa\u5b57\u7b26\u4e32\u5012\u6587\uff0c\u4e0d\u80fd\u52a8\u6001\u5206\u914d\u5185\u5b58
char * reverse(char * s)
{
int c, i, j;
ASSERT(s != NULL);
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
return s;
}
5.\u67e5\u627e\u5b50\u4e32\u662f\u5426\u5b58\u5728
int strindex(char *str,char *searchstr)
{
int end, i, j;
ASSERT((str != NULL) && (searchstr != NULL));
//\u8ba1\u7b97\u7ed3\u675f\u4f4d\u7f6e
end = strlen(str) - strlen(searchstr);
if ( end > 0 )
{
for ( i = 0; i <= end; i++ )
{
for ( j = i; str[j] == searchstr[j-i]; j++ )
{
if ( searchstr[j-i+1] == '/0' ) /* \u5b50\u5b57\u7b26\u4e32\u5b57\u7ed3\u675f */
{
return i + 1; /* \u627e\u5230\u4e86\u5b50\u5b57\u7b26\u4e32 */
}
}
}
}
return -1;
}
预处理器(Preprocessor)
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. 预处理器标识#error的目的是什么?
如果你不知道答案,请看参考文献1。这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。
死循环(Infinite loops)
4. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
这个问题用几个解决方案。我首选的方案是:
while(1)
{
}
一些程序员更喜欢如下方案:
for(;;)
{
}
这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。如果他们的基本答案是:"我被教着这样做,但从没有想到过为什么。"这会给我留下一个坏印象。
第三个方案是用 goto
Loop:
...
goto Loop;
应试者如给出上面的方案,这说明或者他是一个汇编语言程序员(这也许是好事)或者他是一个想进入新领域的BASIC/FORTRAN程序员。
数据声明(Data declarations)
5. 用变量a给出下面的定义
a) 一个整型数(An integer)
b)一个指向整型数的指针( A pointer to an integer)
c)一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an intege)r
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
人们经常声称这里有几个问题是那种要翻一下书才能回答的问题,我同意这种说法。当我写这篇文章时,为了确定语法的正确性,我的确查了一下书。但是当我被面试的时候,我期望被问到这个问题(或者相近的问题)。因为在被面试的这段时间里,我确定我知道这个问题的答案。应试者如果不知道所有的答案(或至少大部分答案),那么也就没有为这次面试做准备,如果该面试者没有为这次面试做准备,那么他又能为什么出准备呢?
Static
6. 关键字static的作用是什么?
这个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用:
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
大多数应试者能正确回答第一部分,一部分能正确回答第二部分,同是很少的人能懂得第三部分。这是一个应试者的严重的缺点,因为他显然不懂得本地化数据和代码范围的好处和重要性。
Const
7.关键字const有什么含意?
我只要一听到被面试者说:"const意味着常数",我就知道我正在和一个业余者打交道。去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着"只读"就可以了。尽管这个答案不是完全的答案,但我接受它作为一个正确的答案。(如果你想知道更详细的答案,仔细读一下Saks的文章吧。)
如果应试者能正确回答这个问题,我将问他一个附加的问题:
下面的声明都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
/******/
前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
1) 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
2) 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3) 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
Volatile
8. 关键字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;
}
位操作(Bit manipulation)
9. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量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 (0x1 << 3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &= ~BIT3;
}
一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是可以接受的。我希望看到几个要点:说明常数、|=和&=~操作。
访问固定的内存位置(Accessing fixed memory locations)
10. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
A more obscure approach is:
一个较晦涩的方法是:
*(int * const)(0x67a9) = 0xaa55;
即使你的品味更接近第二种方案,但我建议你在面试时使用第一种方案。
中断(Interrupts)
11. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字 __interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf("\nArea = %f", area);
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了:
1)ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2) ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3) 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4) 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那么你的被雇用前景越来越光明了。
代码例子(Code examples)
12 . 下面的代码输出是什么,为什么?
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6) ? puts("> 6") : puts("<= 6");
}
这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答案是输出是 ">6"。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。
13. 评价下面的代码片断:
unsigned int zero = 0;
unsigned int compzero = 0xFFFF;
/*1's complement of zero */
对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:
unsigned int compzero = ~0;
这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限,然而PC机程序往往把硬件作为一个无法避免的烦恼。
到了这个阶段,应试者或者完全垂头丧气了或者信心满满志在必得。如果显然应试者不是很好,那么这个测试就在这里结束了。但如果显然应试者做得不错,那么我就扔出下面的追加问题,这些问题是比较难的,我想仅仅非常优秀的应试者能做得不错。提出这些问题,我希望更多看到应试者应付问题的方法,而不是答案。不管如何,你就当是这个娱乐吧...
动态内存分配(Dynamic memory allocation)
14. 尽管不像非嵌入式计算机那么常见,嵌入式系统还是有从堆(heap)中动态分配内存的过程的。那么嵌入式系统中,动态分配内存可能发生的问题是什么?
这里,我期望应试者能提到内存碎片,碎片收集的问题,变量的持行时间等等。这个主题已经在ESP杂志中被广泛地讨论过了(主要是 P.J. Plauger, 他的解释远远超过我这里能提到的任何解释),所有回过头看一下这些杂志吧!让应试者进入一种虚假的安全感觉后,我拿出这么一个小节目:
下面的代码片段的输出是什么,为什么?
char *ptr;
if ((ptr = (char *)malloc(0)) == NULL)
puts("Got a null pointer");
else
puts("Got a valid pointer");
这是一个有趣的问题。最近在我的一个同事不经意把0值传给了函数malloc,得到了一个合法的指针之后,我才想到这个问题。这就是上面的代码,该代码的输出是"Got a valid pointer"。我用这个来开始讨论这样的一问题,看看被面试者是否想到库例程这样做是正确。得到正确的答案固然重要,但解决问题的方法和你做决定的基本原理更重要些。
Typedef
15 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 两个指针。
晦涩的语法
16 . C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
int a = 5, b = 7, c;
c = a+++b;
这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成:
c = a++ + b;
因此, 这段代码持行后a = 6, b = 7, c = 12。
如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题。
网上找的
#include <stdio.h>
int cal(int h1,int length,int b[]);
int main(){
unsigned int n[]=;
int length=7;
printf("%d",cal(-2,length,n));
return 0;
}
int cal(int h1,int length,int b[]){
if (length-h1==1)
return b[h1];
if (length-h1==2)
return (b[h1]>b[h1+1]?b[h1]:b[h1+1]);
if (length-h1==3)
return (b[h1]+b[h1+2]>b[h1+1]?b[h1]+b[h1+2]:b[h1+1]);
if (h1>=0)
return b[h1]+(cal(h1+2,length,b)>cal(h1+3,length,b)?cal(h1+2,length,b):cal(h1+3,length,b));
else
return (cal(h1+2,length,b)>cal(h1+3,length,b)?cal(h1+2,length,b):cal(h1+3,length,b));
}
我目前参加过腾讯的两次面试,推荐看看这里:http://blog.csdn.net/wulei7528/article/details/7522684希望大家踊跃拍砖!
建立两个数组a,b,分别读取存放TEXE1.TXT
和TEXE2.TXT的姓名,然后对于a[0],遍历数组b中的所有元素,如果b中有相同的,则输出至TEXE3.TXT.
然后对a[1],a[2].....一次进行类似操作.
00
绛旓細1銆佸凡鐭ュ瓧姣峛鐨凙SCII鐮佺殑鍗佽繘鍒朵唬鐮佷负98锛屽垯鎵ц涓嬪垪璇彞杈撳嚭涓( C)ch=’b’;ch–;printf(%d,%c\n”,ch,ch);A)a,b B)杩愮畻涓嶅悎娉曪紝鏁呮湁璇硶閿 C)97,a D)鏍煎紡鎻忚堪鍜岃緭鍑洪」涓嶅尮閰嶏紝杈撳嚭鏃犲 2銆佽嫢鍙橀噺a宸茶鏄庝负float绫诲瀷锛屽垯鑳藉疄鐜板皢a涓殑鏁板间繚鐣欏皬鏁扮偣鍚庝袱浣嶏紝...
绛旓細C璇█缁忓吀闈㈣瘯棰8涓繀鏀跺綍 1銆佽缂栧啓涓涓狢鍑芥暟锛岃鍑芥暟缁欏嚭涓涓瓧鑺備腑琚疆1鐨勪綅鐨勪釜鏁般2銆佽缂栧啓涓涓狢 鍑芥暟锛岃鍑芥暟灏嗙粰瀹氱殑涓涓瓧绗︿覆杞崲鎴愭暣鏁般3銆佽缂栧啓涓涓狢鍑芥暟锛岃鍑芥暟鍦ㄧ粰瀹氱殑鍐呭瓨鍖哄煙鎼滅储缁欏畾鐨勫瓧绗︼紝骞惰繑鍥炶瀛楃鎵鍦ㄤ綅缃储寮曞笺4銆佸啓涓涓嚱鏁帮紝姹備竴涓瓧绗︿覆鐨勯暱搴︼紝鍦╩ain鍑芥暟涓...
绛旓細棣栧厛锛岃鎴戜滑鎻紑鎸囬拡鐨勭绉橀潰绾便傛寚閽堬紝杩C璇█涓殑寰涓栫晫锛屽畠灏卞儚涓涓寚鍚戝唴瀛樺湴鍧鐨勬寚璺墝銆傚0鏄庝竴涓寚閽堟槸杩欐牱鍋氱殑锛氭暟鎹被鍨 *鎸囬拡鍚;姣斿锛屼竴涓暣鍨嬫寚閽堬紝鍙渶涓琛屼唬鐮侊細int *p;鑰屽皢鎸囬拡涓庡彉閲忓叧鑱旇捣鏉ワ紝鍙渶璧嬩簣瀹冨疄闄呯殑鍐呭瓨鍦板潃锛屽锛歩nt x = 10; int *p = &x;杩欏氨鏄寚閽堢殑榄斿姏锛岃...
绛旓細浠ヤ笅鏄10閬C璇█闈㈣瘯棰锛屾兜鐩栨寚閽堛佽繘绋嬨佽繍绠椼佺粨鏋勪綋銆佸嚱鏁板拰鍐呭瓨锛屾娴嬩綘鐨凜璇█鐭ヨ瘑鎺屾彙绋嬪害锛1. gets()鍑芥暟浠g爜涓殑gets()鍑芥暟瀛樺湪瀹夊叏闅愭偅锛屽簲浣跨敤fgets()鏇夸唬锛岄伩鍏嶇紦鍐插尯婧㈠嚭闂銆2. strcpy()鍑芥暟瀵嗙爜淇濇姢鍔熻兘鍙氳繃strcpy()鍑芥暟鐨勬紡娲炵牬瑙c傜‘淇濇鏌ョ洰鏍囩紦瀛樺閲忥紝浣跨敤strncpy()浠ラ槻姝㈡孩鍑恒3....
绛旓細浠ヤ笅鏄竴浜涘叧浜庡祵鍏ュ紡寮鍙戜腑C璇█鐨甯歌闈㈣瘯棰锛1.浠涔堟槸宓屽叆寮忕郴缁燂紵宓屽叆寮忕郴缁熸槸涓绉嶄笓涓虹壒瀹氬簲鐢ㄩ鍩熻璁$殑璁$畻鏈虹郴缁燂紝閫氬父宓屽叆鍦ㄥ叾浠栬澶囦腑锛岀敤浜庢帶鍒惰璁惧鐨勭壒瀹氬姛鑳姐2.浠嬬粛涓涓婥璇█涓殑鎸囬拡銆傛寚閽堟槸涓涓彉閲忥紝鍏跺间负鍙︿竴涓彉閲忕殑鍦板潃銆傞氳繃鎸囬拡锛屽彲浠ョ洿鎺ヨ闂垨淇敼鍐呭瓨涓殑鏁版嵁銆3.浠涔堟槸瀹...
绛旓細C璇█6涓湁瓒g殑闈㈣瘯棰 1銆乬ets()鍑芥暟 闂: 璇锋壘鍑轰笅闈唬鐮侀噷鐨勯棶棰樸傜瓟:涓婇潰浠g爜閲岀殑闂鍦ㄤ簬鍑芥暟gets()鐨勪娇鐢紝杩欎釜鍑芥暟浠巗tdin鎺ユ敹涓涓瓧绗︿覆鑰屼笉妫鏌ュ畠鎵澶嶅埗鐨勭紦瀛樼殑瀹圭Н锛岃繖鍙兘浼氬鑷寸紦瀛樻孩鍑恒傝繖閲屾帹鑽愪娇鐢ㄦ爣鍑嗗嚱鏁癴gets()浠f浛銆2銆乵ain()鐨勮繑鍥炵被鍨 闂:涓嬮潰鐨勪唬鐮佽兘缂栬瘧閫氳繃鍚? 濡傛灉鑳斤紝瀹...
绛旓細濂界殑锛屾垜浼氭寜鐓ф偍鐨勮姹傚洖绛旇繖閬C璇█闈㈣瘯棰銆傞掑綊绠楁硶鏄疌璇█涓潪甯搁噸瑕佺殑涓绉嶇畻娉曟濇兂銆傚畠閫氳繃鍑芥暟鑷垜璋冪敤鐨勬柟寮忥紝瑙e喅浜嗕竴浜涢渶瑕佸垎瑙i棶棰樿妯★紝閫愭姹傝В鐨勯棶棰樸備緥濡傦紝璁$畻闃朵箻銆侀亶鍘嗙洰褰曠粨鏋勭瓑鍦烘櫙閮戒細鐢ㄥ埌閫掑綊绠楁硶銆傝В閲婏細閫掑綊绠楁硶鏄竴绉嶇紪绋嬫妧宸э紝瀹冨湪鍑芥暟鍐呴儴璋冪敤鑷韩鏉ュ疄鐜扮壒瀹氱殑鍔熻兘銆傝繖绉嶇畻娉曟濇兂...
绛旓細C璇█闈㈣瘯甯歌闂棰勫鐞嗗櫒(Preprocessor)1 . 鐢ㄩ澶勭悊鎸囦护#define 澹版槑涓涓父鏁,鐢ㄤ互琛ㄦ槑1骞翠腑鏈夊灏戠(蹇界暐闂板勾闂) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL鎴戝湪杩欐兂鐪嬪埌鍑犱欢浜嬫儏:1) #define 璇硶鐨勫熀鏈煡璇(渚嬪:涓嶈兘浠ュ垎鍙风粨鏉,鎷彿鐨勪娇鐢,绛夌瓑)2)鎳傚緱棰勫鐞嗗櫒灏嗕负浣犺绠楀父鏁拌〃杈惧紡鐨勫...
绛旓細缂栧啓涓涓C绋嬪簭锛岀敤鏉ユ眰鍑合鐨勮繎浼煎笺傞鐩垎鏋愶細姹傁鐨勬柟娉曞緢澶氾紝杩欓噷涓ょ鏈涓哄父鐢ㄧ殑姹傁鐨勬柟娉曘傛柟娉曪細鍒╃敤鈥滄澶氳竟褰㈤艰繎鈥濇硶姹傁銆傗滄澶氳竟褰㈤艰繎鈥 娉曟眰蟺鐨勬牳蹇冩濇兂鏄瀬闄愮殑鎬濇兂銆傚亣璁句竴涓洿寰刣涓1鐨勫渾锛屽彧瑕佹眰鍑鸿鍦嗙殑鍛ㄩ暱C锛屽氨鍙互閫氳繃蟺=C/d鐨勬柟娉曟眰鍑合鐨勫笺傛墍浠ュ叧閿槸姹傚嚭璇ュ渾鐨勫懆闀...
绛旓細涓嬮潰瀵闈㈣瘯涓亣鍒扮殑缂栫▼闂鍒嗘瀽浜嗕竴涓嬨傜湡鏄汉鍦ㄧぞ浼氬姹熸箹鍛锛屽涔犳槸涓鍒讳篃涓嶈兘鏀炬澗鐨勪簨銆傜◢涓涓嶆厧锛屾櫄鑺備笉淇濅笉璇达紝鍙嶈屼細闃存矡閲岀炕鑸广1.鑾峰彇璺緞涓嬬殑鏂囦欢鍚 char * FindFileName(char * s){ int len;char *tmp=NULL;ASSERT(s != NULL);for (len=strlen(s); len>0;len--){ if((s...