C/C++程序员面试易错题
c部分::::::::::::::::::::::::::::::::::: 27、 关键字volatile有什么含意? 并给出三个不同的例 子。 【参考答案】一个定义为volatile的变量是说这变量可 能会被意想不到地改变,这样,编译器就不会去假设 这个变量的值了。精确地说就是,优化器在用到这个 变量时必须每次都小心地重新读取这个变量的值,而 不是使用保存在寄存器里的备份。下面是volatile变量 的几个例子: 1). 并行设备的硬件寄存器(如:状态寄存器) 2). 一个中断服务子程序中会访问到的非自动变量 (Non-automatic variables) 3). 多线程应用中被几个任务共享的变量 31、const 有什么用途?(请至少说明两种) 【标准答案】: (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释放内存。动态内存的生存 期由我们决定,使用非常灵活,但问题也最多。 29、float 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、“new”in 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 的首地址位置开始。如此一解释,上面的问题是否已经有了答案呢?