面试模拟题答案1C讲诉.docx
《面试模拟题答案1C讲诉.docx》由会员分享,可在线阅读,更多相关《面试模拟题答案1C讲诉.docx(21页珍藏版)》请在冰豆网上搜索。
面试模拟题答案1C讲诉
面试模拟题1(C)
面试题1:
用find写出查找/opt/kernel目录下(包括子目录)文件名为Kconfig的命令。
cd/opt/kernel/;find-nameKconfig或find/opt/kernel-nameKconfig
面试题2:
用Vi编译器底行命令模式实现字符串替换,把当前文件中的“xiaodai”全部替换成“banzhang”。
:
%s/xiaodai/banzhang/g
面试题3:
变量的声明和定义有什么区别?
为变量分配地址和存储空间的称为定义,不分配地址的称为声明。
一个变量可以在多个地方声明,但是只在一个地方定义。
加入extern修饰的是变量的声明,说明此变量将在文件以外或在文件后面部分定义。
说明:
很多时候一个变量,只是声明不分配内存空间,直到具体使用时才初始化,分配内存空间,如外部变量。
面试题4:
sizeof是库函数吗?
sizeof和strlen的区别?
sizeof是一个操作符,strlen是库函数。
qsizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为‘\0‘的字符串作参数。
q
编译器在编译时就计算出了sizeof的结果。
而strlen函数必须在运行时才能计算出来。
并且sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度。
q数组做sizeof的参数不退化,传递给strlen就退化为指针了。
注意:
有些是操作符看起来像是函数,而有些函数名看起来又像操作符,这类容易混淆的名称一定要加以区分,否则遇到数组名这类特殊数据类型作参数时就很容易出错。
最容易混淆为函数的操作符就是sizeof。
面试题5:
链表和数组有什么区别
数组和链表有以下几点不同:
(1)存储形式:
数组是一块连续的空间,声明时就要确定长度。
链表是一块可不连续的动态空间,长度可变,每个结点要保存相邻结点指针。
(2)数据查找:
数组的线性查找速度快,查找操作直接使用偏移地址。
链表需要按顺序检索结点,效率低。
(3)数据插入或删除:
链表可以快速插入和删除结点,而数组则可能需要大量数据移动。
(4)越界问题:
链表不存在越界问题,数组有越界问题。
说明:
在选择数组或链表数据结构时,一定要根据实际需要进行选择。
数组便于查询,链表便于插入删除。
数组节省空间但是长度固定,链表虽然变长但是占了更多的存储空间。
面试题6:
简述队列和栈的异同
队列和栈都是线性存储结构,但是两者的插入和删除数据的操作不同,队列是“先进先出”,栈是“后进先出”。
注意:
区别栈区和堆区。
堆区的存取是“顺序随意”,而栈区是“后进先出”。
栈由编译器自动分配释放,存放函数的参数值,局部变量的值等。
其操作方式类似于数据结构中的栈。
堆一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
分配方式类似于链表。
它与本题中的堆和栈是两回事。
堆栈只是一种数据结构,而堆区和栈区是程序的不同内存存储区域。
面试题7:
有以下语句:
chara=3,b=6,c;c=a^b<<2;则c的二进制值是_0x00011011____。
面试题8:
如何打印出当前源文件的文件名以及源文件的当前行号?
答案:
cout<<__FILE__;
cout<<__LINE__;
__FILE__和__LINE__是系统预定义宏,这种宏并不是在某个文件中定义的,而是由编译器定义的。
面试题9:
假设某个函数的原型为:
voidfoo(intx,inty);该函数分别被C编译器和C++编译器编译后在符号库中的名字是什么?
答:
该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangledname”)。
_foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
面试题10:
在QT程序中可以调用被C编译器编译后的函数吗?
如果可以怎么实现?
答:
可以,通过加“extern"C"”连接申明,被extern"C"修饰的变量和函数是按照C语言方式编译和连接的
面试题11:
.h头文件中的ifndef/define/endif的作用?
#include与#include"file.h"的区别?
答:
1.防止该头文件被重复引用。
2.前者是从StandardLibrary的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。
面试题12:
结构与联合有和区别?
答:
1.结构和联合都是由多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。
2.对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的。
面试题13:
全局变量和局部变量可否同名,他们是否有区别?
如果有,是什么区别?
答:
可以同名,从生命周期来说全局变量存活于整个程序运行周期,而局部变量只存在所在函数的运行周期,当函数返回后,局部变量也消失,全局变量储存在静态数据库,局部变量在堆栈。
面试题14:
static有什么用途?
static全局变量与普通的全局变量有什么区别?
static局部变量和普通局部变量有什么区别?
static函数与普通函数有什么区别?
答:
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。
它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。
那就是,这个函数被限制在声明它的模块的本地范围内使用。
全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。
全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。
这两者在存储方式上并无不同。
这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。
而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。
由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。
把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
static函数与普通函数作用域不同。
仅在本文件。
只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。
对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用;static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
面试题15:
什么是预编译,何时需要预编译?
预编译又称为预处理,是做些代码文本的替换工作。
处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段,主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
c编译系统在对程序进行通常的编译之前,先进行预处理。
c提供的预处理功能主要有以下三种:
1)宏定义2)文件包含3)条件编译
1、总是使用不经常改动的大型代码体。
2、程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。
在这种情况下,可以将所有包含文件预编译为一个预编译头。
面试题16:
有数组定义inta[2][2]={{1},{2,3}};则a[0][1]的值为多少?
。
a[0][1]的值为0
面试题17:
请计算sizeof的值
char str[] = “Hello” ;
char *p = str ;
int n = 10;
请计算
sizeof (str ) =___6__
sizeof ( p ) =__4___
sizeof ( n ) =___4__
void Func ( char str[100])
{
请计算sizeof( str ) =4
}
void *p = malloc( 100 ); 请计算sizeof ( p ) =4
char *str[]={“Hello”,”HI”, “\x0”};
请计算:
sizeof(str) =12
sizeof(str[0]) =4
面试题18:
头文件中有如下宏定义,
#defineDECLARE_TASKLET(name,func,data)\
structtasklet_structname={NULL,0,ATOMIC_INIT(0),func,data}
.c源文件中有如下语句,staticDECLARE_TASKLET(btn_tasklet,
btn_tasklet_func,
(unsignedlong)&mydata);
请写出预编译后,该语句展开的结果.
staticstructtasklet_structbtn_tasklet={NULL,0,ATOMIC_INIT(0),btn_tasklet_func,(unsignedlong)&mydata};
面试题19:
写一个程序,以递归方式反序输出一个字符串。
如给定字符串“abc”输出“cba”。
#include
voidreverse(char*p)
{
if(*p==‘\0′)
return;
reverse(p+1);
printf(“%c”,*p);
}
intmain()
{
reverse(“abc”);
printf(“\n”);
return0;
}
面试题20:
对于一个字节(8bit)的无符号整形变量,求二进制表示中“1”的个数,要求算法执行效率尽可能地高。
先看看我自己的答案(方法一):
unsignedcharCount(unsignedcharbyt)
{
unsignedcharnum=0;
while(byt)
{
num+=(byt&0×01);
byt>>=1;
}
returnnum;
}
不管有多少个1都要循环8次,执行效率不高,但是执行该函数的时间每次都是确定的。
方法二:
直接的方法就是除以2向右移位,逐个统计,但是用到取模和相除,这个很耗资源。
intCount(BYTEv)
{
intnum=0;
while(v)
{
if(v%2==1)
{
num++;
}
v=v/2;
}
returnnum;
}
求余、除法很耗资源,写程序时应慎用。
方法三:
使用位操作,但是只会去统计1的个数,循环的次数是BYTE中1的个数,无需遍历。
intCount(BYTEv)
{
intnum=0;
while(v)
{
v&=(v-1);//v=v&(v-1)这个操作可以直接消除掉v中的最右边的1。
num++;
}
returnnum;
}
循环次数与Byte中1的个数有关,但是函数执行时间不确定,不过效率比前面的要提高了很多,是不是以为这就是最佳答案了吧,告诉你:
NO。
方法四:
查表法,这个的效率应该是最高的了——空间换时间。
将0~255各个数中所含的1列出来,查表!
!
intcountTable[256]=
{
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
};
intCount(BYTEv)
{
returncountTable[v];
}
这个程序要求效率尽可能的高,显然最后一种的时间复杂度最低了O
(1).执行时间也是确定的。
空间换时间在某些情况下是个好的选择,比如需要频繁使用这个算法的时候,但也不是尽然,还是得视情况而定。
面试题21:
参数传递有哪些形式?
寄存器和堆栈传递各有什么优缺点?
【考点】编译优化、调用性能、接口设计。
答案:
每种体系结构及对应的编译器对参数传递都有自己的规定。
参数传递并非总是通过堆栈进行的,参数入栈出栈是需要耗费时间的,编译器总是尽量优化利用寄存器来传递参数,因为寄存器的访问效率要高,但当参数过多时,将放弃优化从而用栈传递参数。
因此为了提高调用性能,应尽量减少参数个数,太多时可以将所有参数重新定义为一个结构体,利用结构体指针来传递参数。
在函数接口设计时应考虑硬件平台和编译器的特性,以灵活定义参数形式
面试题22:
Define宏语句和inline函数有什么区别?
【考点】时空效率及宏的副作用。
答:
嵌入式系统平台通常存储资源有限,但同时又对实时性有一定的要求,二者如何权衡需要考虑。
Define宏语句相对于函数调用能提高运行时间性能,但消耗了空间,并且不标准的宏语句定义在不标准的编码中更容易出现副作用,因此inline函数则是define语句的完美替代品。
小资金干大事正是嵌入式的终极目标!
面试题23:
chara[5][4],a的地址为0,问printf(“%d”,a[4]+3)值
答案:
15
面试题24:
编写一个宏,实现判断数组a元素的个数。
#define CNT( a ) sizeof(a)/sizeof(*a)
面试题25:
.#defineDOUBLE(x)x+x,i=5*DOUBLE(5);i是多少?
答案:
i为30。
面试题26:
i++一下代码的输出结果是?
inti=1;
intj=2;
intk=i+++j;
cout</*3i+++j是首先结合为i++(大多数的c编译系统都是尽可能多的将多个字符结合成为一个运算符,所以i+++j等价于(i++)+j),然后再+j;但是i++是事后计算,也就是先计算i+j然后再i++,所以k的值是1+2=3;然后i自增到2*/
面试题27:
下面代码输出是什么?
为什么
voidfoo(void)
{
unsignedinta=6;
intb=-20;
(a+b>6)puts(">6"):
puts("<=6");
}
这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。
不管如何,这无符号整型问题的答案是输出是“>6”。
原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。
因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。
这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。
面试题28:
关于动态申请内存的问题
voidGetMemory(char*p)
{
p=(char*)malloc(100);
}
voidTest(void)
{
char*str=NULL;
GetMemory(str);
strcpy(str,"helloworld");
printf(str);
}
请问运行Test函数会有什么样的结果?
传入GetMemory(char*p)函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完char*str=NULL;GetMemory(str);后的str仍然为NULL;
面试题29:
请问运行Test函数会有什么样的结果?
char*GetMemory(void)
{
charp[]="helloworld";
returnp;
}
voidTest(void)
{
char*str=NULL;
str=GetMemory();
printf(str);
}
可能是乱码。
charp[]="helloworld";returnp;p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。
这是许多程序员常犯的错误,其根源在于不理解变量的生存期。
面试题30:
请问运行Test函数会有什么样的结果?
voidGetMemory2(char**p,intnum)
{
*p=(char*)malloc(num);
}
voidTest(void)
{
char*str=NULL;
GetMemory(&str,100);
strcpy(str,"hello");
printf(str);
}
能够输出hello,Test函数中也未对malloc的内存进行释放。
GetMemory避免了以上问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句*p=(char*)malloc(num);后未判断内存是否申请成功,应加上:
if(*p==NULL)
{
...//进行申请内存失败处理
}
面试题31:
请问运行Test函数会有什么样的结果?
voidTest(void)
{
char*str=(char*)malloc(100);
strcpy(str,“hello”);
free(str);
if(str!
=NULL)
{
strcpy(str,“world”);
printf(str);
}
}
运行成功,输出可能是乱码,char*str=(char*)malloc(100);后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:
str=NULL;
面试题32:
用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#defineSECONDS_PER_YEAR(60*60*24*365)UL
我在这想看到几件事情:
1).#define语法的基本知识(例如:
不能以分号结束,括号的使用,等等)
2).懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
3).意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
4).如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。
记住,第一印象很重要
面试题33:
C语言中结构化程序设计的三种基本控制结构
顺序结构
选择结构
循环结构
面试题34:
请说出const与#define相比,有何优点?
Const作用:
定义常量、修饰函数参数、修饰函数返回值三个作用。
被Const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
1)const常量有数据类型,而宏常量没有数据类型。
编译器可以对前者进行类型安全检查。
而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
2)有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
面试题35:
简述数组与指针的区别?
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。
指针可以随时指向任意类型的内存块。
(1)修改内容上的差别
chara[]=“hello”;
a[0]=‘X’;
char*p=“world”;//注意p指向常量字符串
p[0]=‘X’;//编译器不能发现该错误,运行时错误
(2)用运算符sizeof可以计算出数组的容量(字节数)。
sizeof(p),p为指针得到的是一个指针变量的字节数,而不是p所指的内存容量。
C++/C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。
注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。
chara[]="helloworld";
char*p=a;
cout<cout<计算数组和指针的内存容量
voidFunc(chara[100])
{
cout<}
面试题36:
main函数执行完毕后,是否可能会再执行一段代码,给出说明?
答案:
可以,可以用_onexit注册一个函数,它会在main之后执行int
fn1(void),fn2(void),fn3(void),fn4(void);
voidmain(void)
{
Stringstr("zhanglin");
_onexit(fn1);
_onexit(fn2);
_onexit(fn3);
_onexit(fn4);
printf("Thisisexecutedfirst.n");
}
intfn1()
{