首页 > 技术文章 > C/C++程序员面试易错题

wystan 2015-06-14 11:53 原文

 

c部分:::::::::::::::::::::::::::::::::::

27、 关键字volatile有什么含意? 并给出三个不同的例
子。
【参考答案】一个定义为volatile的变量是说这变量可
能会被意想不到地改变,这样,编译器就不会去假设
这个变量的值了。精确地说就是,优化器在用到这个
变量时必须每次都小心地重新读取这个变量的值,而
不是使用保存在寄存器里的备份。下面是volatile变量
的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量
(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量

31const 有什么用途?(请至少说明两种)
【标准答案】: (1)可以定义 const 常量
(2)const 可以修饰函数的参数、返回值,甚至函数
的定义体。被 const 修饰的东西都受到强制保


32、 static有什么用途?(请至少说明两种)
【标准答案】
1.限制变量的作用域(static全局变量);
2.设置变量的存储域(static局部变量)。

34、如何引用一个已经定义过的全局变量?
【标准答案】可以用引用头文件的方式,也可以用
extern关键字,如果用引用头文件方式来引用某个在
头文件中声明的全局变理,假定你将那个变量写错了
,那么在编译期间会报错,如果你用extern方式引用
时,假定你犯了同样的错误,那么在编译期间不会报
错,而在连接期间报错。

35、全局变量可不可以定义在可被多个.C文件包含的
头文件中?为什么?
【标准答案】可以,在不同的C文件中以static形式来声
明同名全局变量。可以在不同的C文件中声明同名的全
局变量,前提是其中只能有一个C文件中对此变量赋初
值,此时连接不会出错。

37、 Heap与stack的差别。
【标准答案】Heap是堆,stack是栈。
Stack的空间由操作系统自动分配/释放,Heap上的空
间手动分配/释放。
Stack空间有限,Heap是很大的自由存储区
C中的malloc函数分配的内存空间即在堆上,C++中对
应的是new操作符。
程序在编译期对变量和函数分配内存都在栈上进行,且
程序运行过程中函数调用时参数的传递也在栈上进行。

1).全局全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。

2).static函数(也叫内部函数)

只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数) static在c里面可以用来修饰变量,也可以用来修饰函数。 先看用来修饰变量的时候。变量在c里面可分为存在全局数据区、栈和堆里。其实我们平时所说的堆栈是栈而不包含对,不要弄混。

程序的局部变量存在于栈(stack)中,全局
变量存在于静态数据区 中,动态申请数据存在于堆(
heap)中。

49、什么是预编译,何时需要预编译:
【标准答案】1、总是使用不经常改动的大型代码体
。
2、程序由多个模块组成,所有模块都使用一组标准
的包含文件和相同的编译选项。在这种情况下,可以
将所有包含文件预编译为一个预编译头。

72、 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提
供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字
__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服
务子程序(ISR),请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
}
【参考答案】这个函数有太多的错误了,以至让人不知从何说起了:
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第
一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编
译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做
浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明
智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。如果你丢掉
了第三和第四点,我不会太为难你的。不用说,如果你能得到后两点,那
么你的被雇用前景越来越光明了。

83、请编写一个 C 函数,该函数在给定的内存区域搜
索给定的字符,并返回该字符所在位置索引值。
【参考答案】
int search(char *cpSource, int n, char ch) //起始地址,搜索长度,目标字符
{
int i;
for(i=0; i<n && *(cpSource+i) != ch; ++i);
return i;
}

91、写一个内存拷贝函数,不用任何库函数.就是前些时
候本版讨论的那个问题。
【参考答案】
void* memcpy(void* pvTo, const void* pvFrom, size_t size)
{
assert((pvTo != NULL) && (pvFrom != NULL));
byte* pbTo = pvTo;
byte* pbFrom = pbFrom;
while (size-- > 0)
{
*pbTo++ = *pbFrom++;
}
return pvTo;
}

93、取一个整数a从右端开始的4~7位。
【参考答案】
main()
{
unsigned a,b,c,d;
scanf("%o",&a);
b=a>>4;
c=~(~0<<4);
d=b&c;
printf("%o\n%o\n",a,d);
}


c++ 部分:::::::::::::::::::::::;

11、引用与指针有什么区别?
【参考答案】
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的
对象。
3) 不存在指向空值的引用,但是存在指向空值的指针
。

14、函数assert的用法?
【参考答案】断言assert是仅在debug版本起作用的宏
,用于检查“不应该“发生的情况。程序员可以把assert
看成一个在任何系统状态下都可以安全使用的无害测
试手段。

17、有了 malloc/free 为什么还要 new/delete ?
【参考答案】malloc 与 free 是 C++/C 语言的标准库
函数,new/delete 是 C++的运算符。它们都可用于申
请动态内存和释放内存。 对于非内部数据类型的对象
而言,光用 maloc/free 无法满足动态对象的要求。对
象在创建的同时要自动执行构造函数,对象在消亡之
前要自动执行析构函数。由于malloc/free 是库函数而
不是运算符,不在编译器控制权限之内,不能够把执
行构造函数和析构函数的任务强加于 malloc/free。 因
此 C++语言需要一个能完成动态内存分配和初始化工
作的运算符 new,以及一个能完成清理与释放内存工
作的运算符 delete。注意 new/delete 不是库函数。

19、C++是不是类型安全的?
【参考答案】不是。两个不同类型的指针之间可以强制
转换(用reinterpret cast)。

21、用C++写个程序,如何判断一个操作系统是16位
还是32位的?
【标准答案】定义一个指针p,打印出sizeof(p),如果节
后是4,则表示该操作系统是32位,打印结果是2,表
示是16位。

22、 .用C++写个程序,如何判断一个操作系统是16位
还是32位的?不能用sizeof()函数。
【参考答案】
int a = ~0;
if( a>65536 )
{
cout<<"32 bit"<<endl;
}
else
{
cout<<"16 bit"<<endl;
}

24、多态类中的虚函数表是Compile-Time,还是Run-
Time时建立的?
【标准答案】虚拟函数表是在编译期就建立了,各个虚
拟函数这时被组织成了一个虚拟函数的入口地址的数
组.而对象的隐藏成员--虚拟函数表指针是在运行期--也
就是构造函数被调用时进行初始化的,这是实现多态的
关键。

25、错误的转义字符是 ()
A.'\091'
B.'\\'
C.'\0'
D.'\'‘
【标准答案】A

28、内存的分配方式有几种?
【参考答案】一、从静态存储区域分配。内存在程序
编译的时候就已经分配好,这块内存在程序的整个运
行期间都存在。例如全局变量。二、在栈上创建。在
执行函数时,函数内局部变量的存储单元都可以在栈
上创建,函数执行结束时这些存储单元自动被释放。
栈内存分配运算内置于处理器的指令集中,效率很高
,但是分配的内存容量有限。
三、从堆上分配,亦称动态内存分配。程序在运行的
时候用malloc或new申请任意多少的内存,程序员自己
负责在何时用free或delete释放内存。动态内存的生存
期由我们决定,使用非常灵活,但问题也最多。

29float a,b,c ,问等式 (a+b)+c==(b+a)+c 和
(a+b)+c==(a+c)+b能否成立?
【参考答案】两者都不行。在比较float或double时,不
能简单地比较。由于计算误差,相等的概率很低。应
判断两数之差是否落在区间(-e,e)内。这个e应比浮点
数的精度大一个数量级。

32、In C++, what does "explicit" mean? what does
"protected" mean?
【标准答案】c++中的explicit关键字用来修饰类的构造
函数,表明该构造函数是显式的,在某些情况下,我
们要求类的使用者必须显示调用类的构造函数时就需
要使用explicit,反之默认类型转换可能会造成无法预期
的问题。protected控制的是一个函数对一个类的成员
(包括成员变量及成员方法)的访问权限。protected
成员只有该类的成员函数及其派生类的成员函数可以
访问。

32、In C++, what does "explicit" mean? what does
"protected" mean?
【标准答案】c++中的explicit关键字用来修饰类的构造
函数,表明该构造函数是显式的,在某些情况下,我
们要求类的使用者必须显示调用类的构造函数时就需
要使用explicit,反之默认类型转换可能会造成无法预期
的问题。protected控制的是一个函数对一个类的成员
(包括成员变量及成员方法)的访问权限。protected
成员只有该类的成员函数及其派生类的成员函数可以
访问。

33、重复多次fclose一个打开过一次的FILE *fp指针会
有什么结果,并请解释。
【参考答案】考察点:导致文件描述符结构中指针指向
的内存被重复释放,进而导致一些不可预期的异常。

34、为什么数组名作为参数,会改变数组的内容,而
其它类型如int却不会改变变量的值?
【参考答案】当数组名作为参数时,传递的实际上是地
址。而其他类型如int作为参数时,由于函数参数值实
质上是实参的一份拷贝,被调函数内部对形参的改变
并不影响实参的值。

40、重载(overload)、重写(override,有的书也叫做“
覆盖”)、重定义(redefinition)的区别?
【标准答案】
名称
名字空间
区别
重载 同一名字空间 是指允许存在多个同名函数,而这些函数的参
数表不同。
重定义/隐
藏 不同名字空间 用于继承,派生类与基类的函数同名,屏蔽基
类的函数
重写/覆盖 不同名字空间 用于继承,子类重新定义复类虚函数的方法

41、多态的作用?
【参考答案】主要是两个:1. 隐藏实现细节,使得代
码能够模块化;扩展代码模块,实现代码重用;2. 接
口重用:为了类在继承和派生的时候,保证使用家族
中任一类的实例的某一属性时的正确调用。

44、 C++里面是不是所有的动作都是main()引起的?
如果不是,请举例。
【参考答案】比如全局变量的初始化,就不是由main函
数引起的。

47、“newin c++ is a:
A. library function like malloc in c
B. key word
C. operator
D. none of the above
【参考答案】C。malloc是库函数,不在编译器控制范
围之内;new是运算符,在编译器控制范围之内。
调用malloc时,从堆中申请内存;调用new时,从堆中
申请内存并为内存调用构造函数。

48、对于C++中类(class) 与结构(struct)的描述正确的为:
A,类中的成员默认是private的,当是可以声明public,private
和protected,结构中定义的成员默认的都是public;
B,结构中不允许定义成员函数,当是类中可以定义成员函数;
C,结构实例使用malloc() 动态创建,类对象使用new 操作符动
态分配内存;
D,结构和类对象都必须使用new 创建;
E,结构中不可以定义虚函数,当是类中可以定义虚函数.
F,结构不可以存在继承关系,当是类可以存在继承关系.
【标准答案】A,D

50、C++程序下列说法正确的有:
A,对调用的虚函数和模板类都进行迟后编译.
B,基类与子类中函数如果要构成虚函数,除了要求在基
类中用virtual 声名,而且必须名字相同且参数类型相同
返回类型相同。
C,重载的类成员函数都必须要:或者返回类型不同,或者
参数数目不同,或者参数序列的类型不同.
D,静态成员函数和内联函数不能是虚函数,友员函数和
构造函数也不能是虚函数,但是析构函数可以是虚函数.
【标准答案】A

51、在C++中有没有纯虚构造函数?
【标准答案】构造函数不能是虚的。只能有虚的析构
函数。

60、所有的运算符都能重载吗?
【参考答案】不能被重载的运算符
在 C++运算符集合中,有一些运算符是不允许被重载
的。这种限制是出于安全方面的考虑,可防止错误和
混乱。 (1)不能改变 C++内部数据类型(如 int,float
等)的运算符。 (2)不能重载‘.’,因为‘.’在类中对任
何成员都有意义,已经成为标准用法。 (3)不能重
载目前 C++运算符集合中没有的符号,如#,@,$等。
原因有两点,一是难以理解,二是难以确定优先级。
(4)对已经存在的运算符进行重载时,不能改变优先级
规则,否则将引起混乱。

61、基类的析构函数不是虚函数,会带来什么问题?
【参考答案】派生类的析构函数用不上,会造成资源
的泄漏。

76、以下三条输出语句分别输出什么?
char str1[]
= "abc";
char str2[]
= "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char* str5 = "abc";
const char* str6 = "abc";
cout << boolalpha << ( str1==str2 ) << endl; // 输出什么?
cout << boolalpha << ( str3==str4 ) << endl; // 输出什么?
cout << boolalpha << ( str5==str6 ) << endl; // 输出什么?
【参考答案】分别输出false,false,true。str1和str2都是字符数组,每个都有其自己
的存储区,它们的值则是各存储区首地址,不等;str3和str4同上,只是按const语
义,它们所指向的数据区不能修改。str5和str6并非数组而是字符指针,并不分配
存储区,其后的“abc”以常量形式存于静态数据区,而它们自己仅是指向该区首地址
的指针,相等。

77、以下代码有什么问题?
cout << (true?1:"1") << endl;
【参考答案】三元表达式“?:”问号后面的两个操作数必
须为同一类型。

79、以下代码中的输出语句输出0吗,为什么?
struct CLS
{
int m_i;
CLS( int i ) : m_i(i) {}
CLS()
{
CLS(0);
}
};
CLS obj;
cout << obj.m_i << endl;
【标准答案】不能。在默认构造函数内部再调用带参的构造函数属用户
行为而非编译器行为,亦即仅执行函数调用,而不会执行其后的初始化
表达式。只有在生成对象时,初始化表达式才会随相应的构造函数一起
调用。

82、在排序方法中,关键码比较次数与记录地初始排
列无关的是()
A. Shell排序
B. 归并排序
C. 直接插入排序
D. 选择排序
【标准答案】D

83、代码
void func()
{
static int val;
...
} 中,变量val的内存地址位于:
A. 已初始化数据段 B.未初始化数据段
C.堆
D.栈
【标准答案】A

85、写出判断ABCD四个表达式的是否正确, 若正确,
写出经过表达式中 a的值。
int a = 4;
(A)a += (a++); (B) a += (++a) ;
(C)(a++) += a;(D) (++a) += (a++);
a = ?
【参考答案】C错误,左侧不是一个有效变量,不能赋
值,可改为(++a) += a;改后答案依次为9,10,10,11
1.15.1,大小端模式对 union 类型数据的影响
下面再看一个例子:
union
{
int i;
char a[2];
}*p, u;
p = &u;
p->a[0] = 0x39;
p->a[1] = 0x38;
p.i 的值应该为多少呢?
这里需要考虑存储模式:大端模式和小端模式。
大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放
在高地址中。
小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放
在低地址中。
union 型数据所占的空间等于其最大的成员所占的空间。对 union 型的成员的存取都是
相对于该联合体基地址的偏移量为 0 处开始,也就是联合体的访问不论对哪个变量的存取都
是从 union 的首地址位置开始。如此一解释,上面的问题是否已经有了答案呢?

 



 

















推荐阅读