/* #include命令的功能是()。 正确答案: C 在命令处插入一个头文件 在文件首部插入一个头文件 在命令处插入一个文本文件 在文件首部插入一个程序文件 预处理器发现#include后,就会寻找指令后面<>中的文件名,并把这个文件的内容包含到当前的文件中, 被包含的文件中的文本将替换源代码文件中的#include指令 */ ////////////////////////////////////////////////////////////////////////////////// /* 下列选项,不正确的是 正确答案: B 你的答案: B (正确) A for(int a=1;a<=10;a++); B int a=1; do { a++; }while(a<=10) C int a=1; while(a<=10) { a++; } D for(int a=1;a<=10;a++)a++; do循环以后的while后面必须要有分号“;” */ ////////////////////////////////////////////////////////////////////////////////// /* 如果有一个类是 myClass , 关于下面代码正确描述的是: myClass::~myClass(){ delete this; this = NULL; } 正确答案: C 你的答案: B (错误) a正确,我们避免了内存泄漏 b它会导致栈溢出 c无法编译通过 d这是不正确的,它没有释放任何成员变量。 this指针内容为const,不允许进行修改,故this = NULL编译不成功。 */ ////////////////////////////////////////////////////////////////////////////////// /* 如下程序: #include "stdio.h" class Base { public: Base() { Init(); } virtual void Init() { printf("Base Init\n"); } void func() { printf("Base func\n"); } }; class Derived: public Base { public: virtual void Init() { printf("Derived Init\n"); } void func() { printf("Derived func\n"); } }; int main() { Derived d; ((Base *)&d)->func(); return 0; } 该程序的执行结果 正确答案: B 你的答案: B (正确) a Base Init Derived func b Base Init Base func c Derived Init Base func d Derived Init Derived func 在构造函数不要调用虚函数。在基类构造的时候,虚函数是非虚,不会走到派生类中,既是采用的静态绑定。 显然的是:当我们构造一个子类的对象时,先调用基类的构造函数,构造子类中基类部分,子类还没有构造,还没有初始化, 如果在基类的构造中调用虚函数,如果可以的话就是调用一个还没有被初始化的对象,那是很危险的, 所以C++中是不可以在构造父类对象部分的时候调用子类的虚函数实现。 但是不是说你不可以那么写程序,你这么写,编译器也不会报错。 只是你如果这么写的话编译器不会给你调用子类的实现,而是还是调用基类的实现。 在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分, 然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数, 会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。 */ ////////////////////////////////////////////////////////////////////////////////// /* 下列关于赋值运算符“=”重载的叙述中,正确的是 正确答案: A 你的答案: A (正确) 赋值运算符只能作为类的成员函数重载 默认的赋值运算符实现了“深层复制”功能 重载的赋值运算符函数有两个本类对象作为形参 如果己经定义了复制拷贝构造函数,就不能重载赋值运算符 */ ////////////////////////////////////////////////////////////////////////////////// /* 在C++中,下列不正确的转义字符是( ) 正确答案: B 你的答案: B (正确) A'\\' B'074' C'\t' D'\0' A 转义字符,就是反斜线字符\ B 错误,内容是3个字符,如果是'\074'则是正确的8进制转义 '\074'才是转义字符 C 跳到下一制表区 D 字符串的末尾 */ ////////////////////////////////////////////////////////////////////////////////// /* 重复多次 fclose 一个打开过一次的 FILE *fp 指针会有什么结果? 正确答案: A 你的答案: A (正确) A导致文件描述符结构中指针指向的内存被重复释放,进而导致一些不可预期的异常 B不会出现异常,释放一个已经释放的指针,系统会自动忽略 C运行异常 D以上答案都不正确 fclose是一个函数名,功能是关闭一个流。使用fclose()函数就可以把 缓冲区 内最后剩余的数据输出到内核缓冲区, 并释放 文件指针 和有关的缓冲区。 函数原型:int fclose( FILE *fp ). 一次正常的fclose会争取释放FILE指针的相关内容。再次fclose释放已经释放掉了的FILE指针,所以会出错 函数fclose()不会判断指针是否null */ ////////////////////////////////////////////////////////////////////////////////// /* 若要重载+、=、<<、=和[]运算符,则必须作为类成员重载的运算符是 正确答案: D 你的答案: D (正确) A+和= B=和<< C==和<< D=和[] 解释: (1)只能使用成员函数重载的运算符有:=、()、[]、->、new、delete。 (2)单目运算符最好重载为成员函数。 (3) 对于复合的赋值运算符如+=、-=、*=、/=、&=、!=、~=、%=、>>=、<<=建议重载为成员函数。 (4) 对于其它运算符,建议重载为友元函数。 运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该函数,以实现相应的运算。 也就是说,运算符重载是通过定义函数实现的。运算符重载实质上是函数的重载。重载运算符的函数一般格式如下: 函数类型 operator 运算符名称 (形参表列) { 对运算符的重载处理 } 重载为类成员函数时参数个数=原操作数个数-1(后置++、--除外) 重载为友元函数时 参数个数=原操作数个数,且至少应该有一个自定义类型的形参 */ ////////////////////////////////////////////////////////////////////////////////// /* 内联可能会寻致二进制可执行文件尺寸变大吗? 正确答案: A 你的答案: A (正确) 是 错 假设系统有100个内联函数,每个展开后有100字节,并且被调用了100次。这就会增加1MB的大小 */ ////////////////////////////////////////////////////////////////////////////////// /* 下面的程序的输出是什么? #include<stdio.h> int main(void) { int n; char y[10] = "ntse"; char *x = y; n = strlen(x); *x = x[n]; x++; printf("x=%s\n",x); printf("y=%s\n",y); return 0; } 正确答案: B 你的答案: B (正确) x=atse,y= x=tse,y= x=atse,y=e x=tse,y=e n = strlen(x),此时n=4,因为x指向y数组,所以x[4]就是y[4]='\0', 那么*x=x[n]就是把x指向的字符串首元素改为'\0',x++之后x指向第二个字符t, 所以第一个输出x=tse,而y遇到第一个字符就是'\0',所以结束,y输出为空 */ ////////////////////////////////////////////////////////////////////////////////// /* 下列说明中 const char *ptr;ptr应该是() 正确答案: C 你的答案: C (正确) 指向字符常量的指针; 指向字符的常量指针; 指向字符串常量的指针; 指向字符串的常量指针; */ ////////////////////////////////////////////////////////////////////////////////// /* 代码执行后,a和b的值分别为? class Test{ public: int a; int b; virtual void fun() {} Test(int temp1 = 0, int temp2 = 0) { a=temp1 ; b=temp2 ; } int getA() { return a; } int getB() { return b; } }; int main() { Test obj(5, 10); // Changing a and b int* pInt = (int*)&obj; *(pInt+0) = 100; *(pInt+1) = 200; cout << "a = " << obj.getA() << endl; cout << "b = " << obj.getB() << endl; return 0; } 正确答案: A 200 10 5 10 100 200 100 10 指向虚函数表的指针在32位系统下占用4个字节,其地址分布在整个类成员变量的地址的首部, 接下来就是变量a的地址、b的地址。当将test对象obj赋给指向整型的pInt后, 指针pInt指向了地址的首部也就是虚函数表指针,所以*(pInt+0)=100改变的是虚函数表的值, 接下来*(pInt+1)=200改变的是变量a的值,变量b没有变换。 */ ////////////////////////////////////////////////////////////////////////////////// /* 关于static用途说法确的是? 正确答案: B C D 你的答案: B C D (正确) 声明静态外部类 声明静态全局变量 声明静态函数 声明静态局部变量 1:设置静态局部变量,变量只定义一次,不能被别的函数使用 2:设置静态全局变量,变量不能被外部文件所使用 3:在类中设置静态函数,只能访问静态变量 */ ////////////////////////////////////////////////////////////////////////////////// /* 在为传统面向对象语言的程序做单元测试的时候,经常用到mock对象。Mock对象通过反射数。请问反射最大程度破坏了面向对象的以下哪个特性? 正确答案: A 你的答案: A (正确) 封装 多态 继承 抽象 mock对象:也成为伪对象,在测试中的利用mock对象来代替真实对象,方便测试的进行。 封装性:指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,通过该类提供的方法实现对内部信息的操作访问。 反射机制:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性 */ ////////////////////////////////////////////////////////////////////////////////// /* 表头文件 include<stdio.h> 定义函数 int fgetc(FILE * stream); 函数说明 fgetc()从参数stream所指的文件中读取一个字符,并把它作为一个字符返回。若读到文件尾或出现错误时,它就返回EOF,你必须通过ferror或feof来区分这两种情况。 返回值 fgetc()会返回读取到的字符,若返回EOF则表示到了文件尾,或出现了错误。 */ ////////////////////////////////////////////////////////////////////////////////// /* 下面关于虚函数的描述,错误的是 正确答案: B 你的答案: B (正确) 在成员函数声明的前面加上virtual修饰,就可把该函数声明为虚函数 基类中说明了虚函数后,派生类中对应的函数也必须说明为虚函数 虚函数可以是另一个类的友元函数,但不能是静态成员函数 基类中说明的纯虚函数在其任何需要实例化的派生类中都必须实现 */ ////////////////////////////////////////////////////////////////////////////////// /* 以下函数用法正确的个数是: void test1() { unsigned char array[MAX_CHAR+1],i; for(i=0;i<=MAX_CHAR;i++){ array[i]=i; } } char*test2() { char p[] = "hello world"; return p; } char *p =test2(); void test3(){ char str[10]; str++; *str='0'; } 正确答案: A 你的答案: A (正确) 0 1 2 3 第一个问题: 重点不在于CHAR_MAX的取值是多少,而是在于i的取值范围是多少。 一般char的取值范围是-128到127,而u char 则是0~255,所以i的取值范围是0~255. 所以当CHAR_MAX常量大于255时,执行i++后,i不能表示256以上的数字,所以导致无限循环。 第二个问题: 重点在于函数中p的身份,他是一个指针,还是数组名; 如果是指针p,则p指向存放字符串常量的地址,返回p则是返回字符串常量地址值,调用函数结束字符串常量不会消失(是常量)。 所以返回常量的地址不会出错。 如果是数组p,则函数会将字符串常量的字符逐个复制到p数组里面,返回p则是返回数组p,但是调用函数结束后p被销毁,里面的元素不存在了。 例子中p是数组名,所以会出错,p所指的地址是随机值。 若是把char p[]="hello";改成char *p="hello";就可以了。 第三个问题: 重点在于str++;这实际的语句就是str=str+1;而str是数组名,数组名是常量,所以不能给常量赋值。(可以执行str+1,但是不能str=.) */ ////////////////////////////////////////////////////////////////////////////////// /* 在c++中, const int i = 0; int *j = (int *) &i; *j = 1; printf("%d,%d", i, *j) 输出是多少? 正确答案: A 你的答案: A (正确) 0,1 1,1 1,0 0,0 C++中的常量折叠:指const变量(即常量)值 放在编译器的符号表中 ,计算时编译器直接从表中取值,省去了访问内存的时间,从而达到了优化. 想要修改i的值可以: const volatile int i = 0; int *j = (int *) &i; *j = 1; printf("%d,%d", i, *j); 则输出1,1 */ ////////////////////////////////////////////////////////////////////////////////// /* 下面程序段的输出结果是: int a = 5, b = 4, c = 3, d = 2; if (a>b>c) printf("%d\n", d); else if ((c - 1 >= d) == 1) printf("%d\n", d + 1); else printf("%d\n", d + 1); 正确答案: B 你的答案: B (正确) 2 3 4 编译错误 */ ////////////////////////////////////////////////////////////////////////////////// /* 下面关于数组的初始化正确的是: 正确答案: B 你的答案: B (正确) char str[2] = {"a","b"}; char str[2][3]={"a","b"}; char str[2][3]={{'a','b'},{'e','d'},{'e','f'}}; char str[] = {"a", "b"}; */ ////////////////////////////////////////////////////////////////////////////////// /* struct T { char a; int *d; int b; int c:16; double e; }; T *p; 在64位系统以及64位编译器下,以下描述正确的是 正确答案: C 你的答案: C (正确) sizeof(p) == 24 sizeof(*p) == 24 sizeof(p->a) == 1 sizeof(p->e) == 4 缺省对齐下三条准则 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 以上都是结构体中只有基本类型时的缺省对齐方式,当有嵌套复合成员时, 【2】改为:复合成员相对于结构体首地址偏移量是复合成员最宽基本类型大小的整数背 P为指针,64位系统地址占8个字节 根据内存对齐 32字节 a_ _ _ _ _ _ _ | * d 8字节| | b4字节| |c2字节|_ _ |e8字节| 正确 double 8字节 */ ////////////////////////////////////////////////////////////////////////////////// /* 类B从类A派生,则类B可以访问类A中的( )成员? 正确答案: A C 你的答案: A C (正确) public成员 private成员 protected成员 数据成员 函数成员 */ ////////////////////////////////////////////////////////////////////////////////// /* 下面关于数组的描述错误的是: 正确答案: C D 在C++语言中一维数组的名字就是指向该数组第一个元素的指针 长度为n的数组,下标的范围是0-n-1 数组的大小必须在编译是确定 数组只能通过值参数和引用参数两种方式传递给函数 */ ////////////////////////////////////////////////////////////////////////////////// /* 如果x=2014,下面函数的返回值是() int fun(unsigned int x) { int n=0; while((x+1)) { n++; x=x|(x+1); } return n; } 正确答案: C 你的答案: C (正确) 20 21 23 25 x&(x-1)统计1的个数,x|(x+1)统计0的个数 */ ////////////////////////////////////////////////////////////////////////////////// /* int a[3][4],下面哪个不能表示 a[1][1]? 正确答案: C 你的答案: C (正确) *(&a[0][0]+5) *(*(a+1)+1) *(&a[1]+1) *(a[1]+1) */ ////////////////////////////////////////////////////////////////////////////////// /* 在Windows 32位操作系统中,假设字节对齐为4,对于一个空的类A,sizeof(A)的值为()? 正确答案: B 你的答案: B (正确) 0 1 2 4 类的实例化是在内存中分配一块地址,每个实例在内存中都有独一无二的二地址。 同样,空类也会实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化后就有独一无二的地址了。 所以,空类的sizeof为1,而不是0. 多重继承的空类的大小也是1. */ ////////////////////////////////////////////////////////////////////////////////// /* 下列关于一个类的静态成员的描述中,不正确的是 正确答案: D 你的答案: D (正确) A该类的对象共享其静态成员变量的值 B静态成员变量可被该类的所有方法访问 C该类的静态方法只能访问该类的静态成员变量 D该类的静态数据成员变量的值不可修改 静态方法里只能访问本类方法中的静态成员,不能直接访问非静态的属性和方法。 这是因为静态方法不依赖于对象,所以当类加载成功后,静态方法就可以访问了。 而此时的对象不一定存在,非静态成员自然也不一定存在。 而且即使存在非静态成员,静态方法也不知道访问哪一个对象的成员。 静态方法中也不能出现this关键字,因为this是针对对象而言的。 本类中的非静态方法可以访问本类的静态属性,也可以调用静态方法。 */ ////////////////////////////////////////////////////////////////////////////////// /* 若有以下程序 #include<stdio.h> main( ) { int a=-2,b=0; while(a++) ++b; printf("%d,%d\n",a,b); } 则程序的输出结果是? 正确答案: B 你的答案: B (正确) 1,1 1,2 2,1 2,2 第一次while判断条件中a++,先用后加,为-2不为0条件为真,执行a的自加与++b操作,a的值变为-1,b的值变为1。 第二次while判断后,a的值变为0,b的值变为2。第三次while判断条件为假,但是仍要执行自加操作,即值为1,跳出循环。打印1和2。 */ ///////////////////////////////////////////////////////////////////// /* 以下代码的输出结果是? main() { int i=0; switch(i) { case 0: i++; printf("%d..",i); case 1: printf("%d..",i); case 2: printf("%d..",i); } } 正确答案: C 你的答案: C (正确) ..1..1..0 0..1..1 1..1..1.. 1 因为没有break,代码会一直向下执行而不是跳出switch。 case后面的常量表达式实际上只起语句标号作用,而不起条件判断作用,即“只是开始执行处的入口标号”。 因此,一旦与switch后面圆括号中表达式的值匹配,就从此标号处开始执行; 而且执行完一个case后面的语句后,若没遇到break语句,就自动进入下一个case继续执行,而不再判断是否与之匹配, 直到遇到break语句才停止执行,退出switch语句。 因此,若想执行一个case分之后立即跳出switch语句,就必须在此分支的最后添加一个break语句。 */ ///////////////////////////////////////////////////////////////////// /* 下面有关虚函数和非虚函数的区别说法错误的是? 正确答案: C 你的答案: C (正确) 子类的指针访问虚函数访问的是子类的方法 子类的指针访问非虚函数访问的是子类的方法 父类的指针访问虚函数访问的是父类的方法 父类的指针访问非虚函数访问的是父类的方法 */ ///////////////////////////////////////////////////////////////////// /* 有以下程序 #include<iostream> #include<stdio.h> using namespace std; int main(){ int m=0123, n = 123; printf("%o %o\n", m, n); return 0; } 程序运行后的输出结果是() 正确答案: C 你的答案: C (正确) 0123 0173 0123 173 123 173 173 173 */ ///////////////////////////////////////////////////////////////////// /* 代码可以通过编译吗?如果不能应该如何修改? template<class T> class Foo{ T tVar; public: Foo(T t) : tVar(t) { } }; template<class T> class FooDerived:public Foo<T> { }; int main() { FooDerived<int> d(5); return 0; } 正确答案: D 你的答案: D (正确) A代码可以正确通过编译。 B编译错误,FooDerived是一个继承模板类的非模板类,它的类型不能改变。 C编译错误,tVal变量是一个不确定的类型。 D编译错误,可以在FooDerived类中添加一个构造函数解决问题。 当基类构造函数需要外部传递参数才能进行初始化时,派生类必须显式定义构造函数,为基类传递参数; 基类如果不需要传递或者可以不传递参数,派生类可以不用显式定义构造函数。 template<class T> class Foo{ T tVar; public: Foo(T t) : tVar(t) {} }; template<class T> class FooDerived:public Foo<T> { public: FooDerived(T a):Foo<T>(a){} }; */ /////////////////////////////////////////////////////////////////////