logo资料库

C_C++笔试题集锦_(已排版).doc

第1页 / 共35页
第2页 / 共35页
第3页 / 共35页
第4页 / 共35页
第5页 / 共35页
第6页 / 共35页
第7页 / 共35页
第8页 / 共35页
资料共35页,剩余部分请下载后查看
1.求下面函数的返回值(微软)
10. 写出下面关于“联合”的题目的输出?
11. 已知strcpy的函数原型:char *strcpy(char *strDest, cons
12. 已知String类定义如下:
13. .h头文件中的ifndef/define/endif 的作用?
14. #i nclude 与 #i nclude "file.h"的区别?
16. 关联、聚合(Aggregation)以及组合(Composition)的区别?
18. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
19. 多态的作用?
20. Ado与Ado.net的相同与不同?
21. new delete 与malloc free 的联系与区别?
22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?
23. 有哪几种情况只能用intialization list 而不能用assignment?
24. C++是不是类型安全的?
25. main 函数执行以前,还会执行什么代码?
26. 描述内存分配方式以及它们的区别?
29. 在8086 汇编下,逻辑地址和物理地址是怎样转换的?(Intel)
30. 比较C++中的4种类型转换方式?
B()
(1) results:
(2) results:
Typedef
Answer : 5794
Answer: 5,20,1
Answer: 10, 5
Answer:Cisco Systems
Answer: Cisco
Answer: Ciscosystems
Answer: 12 , 13 , 13
Answer: 11, 16
Answer: Two lines with “Cisco Systems” will be pri
a) When compiled and executed on x86, why does thi
b) Name several ways in which the security problem
32. 找错
33. 写出程序运行结果
34.
36. 定义 int **a[3][4], 则变量占有的内存空间为:_____
(1)A先拿,然后一人一次交替着拿;
X();
A.'\091'
B.'\\'
1.求下面函数的返回值(微软) int func(x) { int countx = 0; while(x) { countx ++; x = x&(x-1); } return countx; } 假定 x = 9999。 答案:8 思路:将 x 转化为 2 进制,看含有的 1 的个数。 2. 什么是“引用”?申明和使用“引用”要注意哪些问题? 答:引用就是某个目标变量的“别名”(alias),对引用的操作与对变量直接操作效果完全相 同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有 两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个 引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一 种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的 引用。 3. 将“引用”作为函数参数有哪些特点? (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调 函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其 相应的目标对象(在主调函数中)的操作。 (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作; 而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量 是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据 较大时,用引用比用一般变量传递参数的效率和所占空间都好。 (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样 要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错 误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。 而引用更容易使用,更清晰。 4. 在什么时候需要使用“常引用”? 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使 用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名; 例 1 int a ; const int &ra=a; ra=1; //错误 a=1; //正确 例 2 1
string foo( ); void bar(string & s); 那么下面的表达式将是非法的: bar(foo( )); bar("hello world"); 原因在于 foo( )和"hello world"串都会产生一个临时对象,而在 C++中,这些临时对象都是 const 类型的。因此上面的表达式就是试图将一个 const 类型的对象转换为非 const 类型,这 是非法的。 引用型参数应该在能被定义为 const 的情况下,尽量定义为 const。 5. 将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 } 好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变 量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生 runtime error! 注意事项: (1)不能返回局部变量的引用。这条可以参照 Effective C++[1]的 Item 31。主要原因是局部 变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知 状态。 (2)不能返回函数内部 new 分配的内存的引用。这条可以参照 Effective C++[1]的 Item 31。 虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部 new 分配内存的引 用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有 被赋予一个实际的变量,那么这个引用所指向的空间(由 new 分配)就无法释放,造成 memory leak。 (3)可以返回类成员的引用,但最好是 const。这条原则可以参照 Effective C++[1]的 Item 30。 主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与 某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果 其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务 规则的完整性。 (4)流操作符重载返回值申明为“引用”的作用: 流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl; 因此 这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括: 返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝) 构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法 让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是 惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是 C++ 语言中引入引用这个概念的原因吧。赋值操作符=。这个操作符象流操作符一样,是可以连 续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可 以被继续赋值。因此引用成了这个操作符的惟一返回值选择。 例 3 #i nclude int &put(int n); int vals[10]; int error=-1; 2
void main() { put(0)=10; //以 put(0)函数值作为左值,等价于 vals[0]=10; put(9)=20; //以 put(9)函数值作为左值,等价于 vals[9]=20; cout<=0 && n<=9 ) return vals[n]; else { cout<<"subscript error"; return error; } } (5)在另外的一些操作符中,却千万不能返回引用:+-*/ 四则运算符。它们不能返回引用, Effective C++[1]的 Item23 详细的讨论了这个问题。主要原因是这四个操作符没有 side effect, 因此,它们必须构造一个对象作为返回值,可选的方案包括:返回一个对象、返回一个局部 变量的引用,返回一个 new 分配的对象的引用、返回一个静态对象引用。根据前面提到的 引用作为返回值的三个规则,第 2、3 两个方案都被否决了。静态对象的引用又因为((a+b) == (c+d))会永远为 true 而导致错误。所以可选的只剩下返回一个对象了。 6. “引用”与多态的关系? 引用是除指针外另一个可以产生多态效果的手段。这意味着,一个基类的引用可以指向它的 派生类实例。 例 4 Class A; Class B : Class A{...}; B b; A& ref = b; 7. “引用”与指针的区别是什么? 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程 序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。此 外,就是上面提到的对函数传 ref 和 pointer 的区别。 8. 什么时候需要“引用”? 流操作符<<和>>、赋值操作符=的返回值、拷贝构造函数的参数、赋值操作符=的参数、其 它情况都推荐使用引用。 以上 2-8 参考:http://blog.csdn.net/wfwd/archive/2006/05/30/763551.aspx 9. 结构与联合有何区别? 1. 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了 一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的 存放地址不同)。 2. 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构 的不同成员赋值是互不影响的。 10. 写出下面关于“联合”的题目的输出? a) 3
#i nclude union { int i; char x[2]; }a; void main() { a.x[0] = 10; a.x[1] = 1; printf("%d",a.i); } 答案:266 (低位低地址,高位高地址,内存占用情况是 Ox010A) b) main() { union{ /*定义一个联合*/ int i; struct{ /*在联合中定义一个结构*/ char first; char second; }half; }number; number.i=0x4241; /*联合成员赋值*/ printf("%c%c\n", number.half.first, mumber.half.second); number.half.first='a'; /*联合中结构成员赋值*/ number.half.second='b'; printf("%x\n", number.i); getch(); } 答案: AB (0x41 对应'A',是低位;Ox42 对应'B',是高位) 6261 (number.i 和 number.half 共用一块地址空间) 11. 已知 strcpy 的函数原型:char *strcpy(char *strDest, const char *strSrc)其中 strDest 是 目的字符串,strSrc 是源字符串。不调用 C++/C 的字符串库函数,请编写函数 strcpy。 答案: char *strcpy(char *strDest, const char *strSrc) { if ( strDest == NULL || strSrc == NULL) return NULL ; if ( strDest == strSrc) return strDest ; char *tempptr = strDest ; 4
while( (*strDest++ = *strSrc++) != ‘\0’) ; return tempptr ; } 12. 已知 String 类定义如下: class String { public: String(const char *str = NULL); // 通用构造函数 String(const String &another); // 拷贝构造函数 ~ String(); // 析构函数 String & operater =(const String &rhs); // 赋值函数 private: char *m_data; // 用于保存字符串 }; 尝试写出类的成员函数实现。 答案: String::String(const char *str) { if ( str == NULL ) //strlen 在参数为 NULL 时会抛异常才会有这步判断 { m_data = new char[1] ; m_data[0] = '\0' ; } else { m_data = new char[strlen(str) + 1]; strcpy(m_data,str); } } String::String(const String &another) { m_data = new char[strlen(another.m_data) + 1]; strcpy(m_data,other.m_data); } String& String::operator =(const String &rhs) { if ( this == &rhs) return *this ; delete []m_data; //删除原来的数据,新开一块内存 m_data = new char[strlen(rhs.m_data) + 1]; strcpy(m_data,rhs.m_data); 5
return *this ; } String::~String() { delete []m_data ; } 13. .h 头文件中的 ifndef/define/endif 的作用? 答:防止该头文件被重复引用。 14. #i nclude 与 #i nclude "file.h"的区别? 答:前者是从 Standard Library 的路径寻找和引用 file.h,而后者是从当前工作路径搜寻并引 用 file.h。 15.在 C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”? 首先,作为 extern 是 C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关 键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。 通常,在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字 extern 声明。例如,如果模块 B 欲引用该模块 A 中定义的全局变量和函数时只需包含模块 A 的头 文件即可。这样,模块 B 中调用模块 A 中的函数时,在编译阶段,模块 B 虽然找不到该函 数,但是并不会报错;它会在连接阶段中从模块 A 编译生成的目标代码中找到此函数 extern "C"是连接申明(linkage declaration),被 extern "C"修饰的变量和函数是按照 C 语言方式 编译和连接的,来看看 C++中对类似 C 的函数是怎样编译的: 作为一种面向对象的语言,C++支持函数重载,而过程式语言 C 则不支持。函数被 C++编译 后在符号库中的名字与 C 语言的不同。例如,假设某个函数的原型为: void foo( int x, int y ); 该函数被 C 编译器编译后在符号库中的名字为_foo,而 C++编译器则会产生像_foo_int_int 之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字 称为“mangled name”)。 _foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来 实现函数重载的。例如,在 C++中,函数 void foo( int x, int y )与 void foo( int x, float y )编译 生成的符号是不相同的,后者为_foo_int_float。 同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序 的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时, 与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名 的全局变量名字不同。 未加 extern "C"声明时的连接方式 假设在 C++中,模块 A 的头文件如下: // 模块 A 头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H int foo( int x, int y ); #endif 6
在模块 B 中引用该函数: // 模块 B 实现文件 moduleB.cpp #i nclude "moduleA.h" foo(2,3); 实际上,在连接阶段,连接器会从模块 A 生成的目标文件 moduleA.obj 中寻找_foo_int_int 这样的符号! 加 extern "C"声明后的编译和连接方式 加 extern "C"声明后,模块 A 的头文件变为: // 模块 A 头文件 moduleA.h #ifndef MODULE_A_H #define MODULE_A_H extern "C" int foo( int x, int y ); #endif 在模块 B 的实现文件中仍然调用 foo( 2,3 ),其结果是: (1)模块 A 编译生成 foo 的目标代码时,没有对其名字进行特殊处理,采用了 C 语言的方 式; (2)连接器在为模块 B 的目标代码寻找 foo(2,3)调用时,寻找的是未经修改的符号名_foo。 如果在模块 A 中函数声明了 foo 为 extern "C"类型,而模块 B 中包含的是 extern int foo( int x, int y ) ,则模块 B 找不到模块 A 中的函数;反之亦然。 所以,可以用一句话概括 extern “C”这个声明的真实目的(任何语言中的任何语法特性的 诞生都不是随意而为的,来源于真实世界的需求驱动。我们在思考问题时,不能只停留在这 个语言是怎么做的,还要问一问它为什么要这么做,动机是什么,这样我们可以更深入地理 解许多问题):实现 C++与 C 及其它语言的混合编程。 明白了 C++中 extern "C"的设立动机,我们下面来具体分析 extern "C"通常的使用技巧: extern "C"的惯用法 (1)在 C++中引用 C 语言中的函数和变量,在包含 C 语言头文件(假设为 cExample.h)时, 需进行下列处理: extern "C" { #i nclude "cExample.h" } 而在 C 语言的头文件中,对其外部函数只能指定为 extern 类型,C 语言中不支持 extern "C" 声明,在.c 文件中包含了 extern "C"时会出现编译语法错误。 C++引用 C 函数例子工程中包含的三个文件的源代码如下: /* c 语言头文件:cExample.h */ #ifndef C_EXAMPLE_H #define C_EXAMPLE_H extern int add(int x,int y); #endif /* c 语言实现文件:cExample.c */ #i nclude "cExample.h" int add( int x, int y ) { 7
return x + y; } // c++实现文件,调用 add:cppFile.cpp extern "C" { #i nclude "cExample.h" } int main(int argc, char* argv[]) { add(2,3); return 0; } 如果 C++调用一个 C 语言编写的.DLL 时,当包括.DLL 的头文件或声明接口函数时,应加 extern "C" { (2)在 C 中引用 C++语言中的函数和变量时,C++的头文件需添加 extern "C",但是在 C 语言中不能直接引用声明了 extern "C"的该头文件,应该仅将 C 文件中将 C++中定义的 extern "C"函数声明为 extern 类型。 C 引用 C++函数例子工程中包含的三个文件的源代码如下: //C++头文件 cppExample.h #ifndef CPP_EXAMPLE_H #define CPP_EXAMPLE_H extern "C" int add( int x, int y ); #endif }。 //C++实现文件 cppExample.cpp #i nclude "cppExample.h" int add( int x, int y ) { return x + y; } /* C 实现文件 cFile.c */ /* 这样会编译出错:#i nclude "cExample.h" */ extern int add( int x, int y ); int main( int argc, char* argv[] ) { add( 2, 3 ); return 0; } 15 题目的解答请参考《C++中 extern“C”含义深层探索》注解。 16. 关联、聚合(Aggregation)以及组合(Composition)的区别? 涉及到 UML 中的一些概念:关联是表示两个类的一般性联系,比如“学生”和“老师”就 8
分享到:
收藏