c++面试题总结(1)

时间:2024-11-19 18:07:07

1、int a=5,则 ++(a++)的值是()

A、5      B、   6          C、7       D、逻辑错误

a++返回的是一个临时变量,这里是右值,不能再前面++了

2、下面的代码输出什么?(取地址运算符比+运算符的优先级要高)

  1. int main(void)
  2. {
  3. int  a[5] = {1, 2, 3, 4, 5};
  4. int  *ptr = (int *)(&a+1);
  5. printf("%d %d",*(a+1),*(ptr-1));
  6. return 0;
  7. }

A、1  6     B、2   4   C、2   5    D、1   5

&a是一个指向数组的指针(行指针),a的步长就是数组的长度。也就是说执行a+1时,a要跨过n个整型数据的长度,输出*ptr就会发现越界了,是一个随机值,那么ptr-1的值就是数组的最后一个值了。

&a+1不是首地址+1, 系统会认为加一个a数组的偏移, 是偏移了一个数组的大小(本例是5个int )

int *ptr = (int *)(&a+1);

则ptr实际上是&(a[5]),也就是a+5

原因如下:

&a 是数组指针, 其类型为int (*)[5];

而指针加1要根据指针类型加上一定的值, 不同类型的指针+1之后增加的大小不同。

a 是长度为5的int数组指针,所以要加5*sizeof(int)

所以,ptr实际是ptr[5]

但是ptr与(&a+1)类型时不一样的(这点很重要)

所以ptr-1只会减去sizeof(int *)

a, &a的地址是一样的,但是意思不一样

a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址

a+1是数组下一元素的地址,即a[1], &a+1是下一个对象的地址,即a[5].

3、以下三条输出语句分别输出什么?

  1. char str1[] = "abc";
  2. char str2[] = "abc";
  3. const char str3[] = "abc";
  4. const char str4[] = "abc";
  5. const char* str5 = "abc";
  6. const char* str6 = "abc";
  7. cout << boolalpha << ( str1==str2 ) << endl; // 输出什么?
  8. cout << boolalpha << ( str3==str4 ) << endl; // 输出什么?
  9. cout << boolalpha << ( str5==str6 ) << endl; // 输出什么?

答:分别输出false,false,true。str1和str2都是字符数组,每个都有其自己的存储区,它们的值则是各存储区首地址,不等;str3和str4同上,只是按const语义,它们所指向的数据区不能修改。str5和str6并非数组而是字符指针,并不分配存储区,其后的“abc”以常量形式存于静态数据区,而它们自己仅是指向该区首地址的指针,所以相等。

4、下面代码的输出是什么?

  1. float a = 1.0f;
  2. cout<< (int)a <<endl;
  3. cout<< (int&)a <<endl;
  4. cout << boolalpha << ( (int)a==(int&)a ) << endl; // 输出什么?
  5. float b = 0.0f;
  6. cout<< (int)b <<endl;
  7. cout<< (int&)b <<endl;
  8. cout << boolalpha << ( (int)b==(int&)b ) << endl; // 输出什么?

浮点数的 1.0f 在内存里是这样表示的: 

0011 1111 1000 0000 00000000 00000000 



这个32位二进制数被当作整数输出就是: 

1065353216 

而整数的 1 在内存里是这样表示的: 

0000 0000 0000 0000 00000000 00000001 

所以 (int)a != (int&)a 



浮点的0和整数的0 在内存里都是: 

0000 0000 0000 0000 00000000 00000000 

所以 (int)b == (int&)b

5、以下代码中的两个sizeof用法有问题吗?

  1. void UpperCase( char str[] ) // 将str 中的小写字母转换成大写字母
  2. {
  3. for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
  4. {
  5. if( 'a'<=str[i] && str[i]<='z' )
  6. {
  7. str[i] -= ('a'-'A' );
  8. }
  9. }
  10. }
  11. int main(void)
  12. {
  13. char str[] = "aBcDe";
  14. cout << "str字符长度为: " << sizeof(str)/sizeof(str[0]) << endl;
  15. UpperCase( str );
  16. cout << str << endl;
  17. return 0;
  18. }

6、非C++内建型别A和B,在哪几种情况下B能隐式转化为A?

7、以下代码有什么问题?

  1. struct Test
  2. {
  3. Test(int ) { }
  4. Test() { }
  5. void fun() { }
  6. };
  7. int main(void)
  8. {
  9. Test a(1);
  10. a.fun();
  11. Test b();
  12. b.fun();
  13. return 0;
  14. }

8、以下代码有什么问题?

  1. cout<< (true?1:"0") <<endl;

9、以下代码能够编译通过吗,为什么?

  1. int main(void)
  2. {
  3. unsigned int const size1 = 2;
  4. char str1[ size1 ];
  5. unsigned int temp = 0;
  6. cin >> temp;
  7. unsigned int const size2 = temp;
  8. char str2[ size2 ];
  9. return 0;
  10. }

10、以下反向遍历array数组的方法有什么错误?

  1. int main(void)
  2. {
  3. vector array;
  4. array.push_back( 1 );
  5. array.push_back( 2 );
  6. array.push_back( 3 );
  7. for( vector::size_type i=array.size()-1; i>=0; --i )    // 反向遍历array数组
  8. {
  9. cout << array[i] << endl;
  10. }
  11. return 0;
  12. }

11、以下代码中的输出语句输出吗,为什么?

  1. struct CLS
  2. {
  3. int m_i;
  4. CLS(int i): m_i( i ) {   }
  5. CLS()
  6. {
  7. CLS( 0 );
  8. }
  9. };
  10. int main(void)
  11. {
  12. CLS obj;
  13. cout << obj.m_i << endl;
  14. return 0;
  15. }

12、C++中的空类,默认产生哪些类成员函数?

13、 以下代码有什么问题吗?

  1. int main(void)
  2. {
  3. typedef vector IntArray;
  4. IntArray array;
  5. array.push_back( 1 );
  6. array.push_back( 2 );
  7. array.push_back( 2 );
  8. array.push_back( 3 );
  9. // 删除array数组中所有的2
  10. for( IntArray::iterator itor=array.begin(); itor!=array.end(); ++itor )
  11. {
  12. if( 2 == *itor )
  13. {
  14. array.erase( itor );
  15. }
  16. }
  17. return 0;
  18. }

14、 写一个函数,完成内存之间的拷贝。[考虑问题是否全面]

答案:

4、分别输出false和true。注意转换的应用。(int)a实际上是以浮点数a为参数构造了一个整型数,该整数的值是,(int&)a则是告诉编译器将a当作整数看(并没有做任何实质上的转换)。因为以整数形式存放和以浮点形式存放其内存数据是不一样的,因此两者不等。对b的两种转换意义同上,但是的整数形式和浮点形式其内存数据是一样的,因此在这种特殊情形下,两者相等(仅仅在数值意义上)。



  注意,程序的输出会显示(int&)a=1065353216,这个值是怎么来的呢?前面已经说了,以浮点数形式存放在内存中,按ieee754规定,其内容为x0000803F(已考虑字节反序)。这也就是a这个变量所占据的内存单元的值。当(int&)a出现时,它相当于告诉它的上下文:“把这块地址当做整数看待!不要管它原来是什么。”这样,内容x0000803F按整数解释,其值正好就是(十进制数)。



  通过查看汇编代码可以证实“(int)a相当于重新构造了一个值等于a的整型数”之说,而(int&)的作用则仅仅是表达了一个类型信息,意义在于为cout<<及==选择正确的重载版本。

5、答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为个字节,因此返回。



6、答:

a. class B : public A { ……} // B公有继承自A,可以是间接继承的



b. class B { operator A( ); } // B实现了隐式转化为A的转化



c. class A { A( const B& ); } // A实现了non-explicit的参数为B(可以有其他带默认值的参数)构造函数



d. A& operator= ( const A& ); // 赋值操作,虽不是正宗的隐式类型转换,但也勉强算一个



7、答:变量b定义出错。按默认构造函数定义对象,不需要加括号。



8、答:三元表达式“?:”问号后面的两个操作数必须为同一类型。



9、答:str2定义出错,size2非编译器期间常量,而数组定义要求长度必须为编译期常量。

注释:经过测试,原作者这里解释有误,测试结果这个可以题编译能够通过, 虽然感觉好像是不能通过的, 但是后来想了下, 因为变量给const常量复制, const常量得到其对应的值的拷贝,
后面不能更改。 所以还是可以编译通过,同时str2获得的大小也是输入的值大小!



10、答:首先数组定义有误,应加上类型参数:vector<int> array。其次vector::size_type被定义为unsigned int,即无符号数,这样作为循环变量的i为0时再减就会变成最大的整数,导致循环失去控制。

  1. int main(void)
  2. {
  3. vector<int> array;
  4. array.push_back(1);
  5. array.push_back(2);
  6. array.push_back(3);
  7. for(int i = array.size() - 1 ; i >= 0 ; --i)
  8. cout<<array[i]<<endl;
  9. return 0;
  10. }

11、答:不能。在默认构造函数内部再调用带参的构造函数属用户行为而非编译器行为,亦即仅执行函数调用,而不会执行其后的初始化表达式。只有在生成对象时,初始化表达式才会随相应的构造函数一起调用。

注释:这个是有输出的,应该是一个随机数字。后面解释确实是对的

12、

  1. class Empty
  2. {
  3. public:
  4. Empty();   //缺省构造函数
  5. Empty(const Empty &);   //拷贝构造函数
  6. ~Empty();   //析构函数
  7. Empty & operator=(const Empty &);   //赋值运算符
  8. Empty* operator&();   //取址运算符
  9. const Empty* operator&() const;   //取址运算符const
  10. };

13、答:同样有缺少类型参数的问题。另外,每次调用“array.erase(itor);”,被删除元素之后的内容会自动往前移,导致迭代漏项,应在删除一项后使itor--,使之从已经前移的下一个元素起继续遍历。

  1. int main(void)
  2. {
  3. typedef vector<int> IntArray;
  4. IntArray array;
  5. array.push_back( 1 );
  6. array.push_back( 2 );
  7. array.push_back( 2 );
  8. array.push_back( 3 );
  9. // 删除array数组中所有的2
  10. for( IntArray::iterator itor=array.begin(); itor!=array.end(); ++itor )
  11. {
  12. if( 2 == *itor )
  13. {
  14. itor = array.erase( itor );
  15. itor--;
  16. }
  17. }
  18. return 0;
  19. }

注释:单单就这一道题来讲,这样是可以的,但是如果2在第一位或者最后一位仍然会有问题

14、

  1. // 功能:由src所指内存区域复制count个字节到dest所指内存区域。
  2. // 说明:src和dest所指内存区域可以重叠,但复制后dest内容会被更改。函数返回指向dest的指针
  3. void *memmove(void *dest , const void *src , size_t count)
  4. {
  5. assert( (dest != NULL) && (src != NULL));     //安全检查
  6. assert( count > 0 );
  7. char *psrc = (char *) src;
  8. char *pdest = (char *) dest;
  9. //检查是否有重叠问题
  10. if( pdest < psrc )
  11. {
  12. //正向拷贝
  13. while( count-- )
  14. *pdest++ = *psrc++;
  15. }
  16. else if( psrc < pdest )
  17. {
  18. //反向拷贝
  19. psrc = psrc + count - 1;
  20. pdest = pdest + count - 1;
  21. while( count-- )
  22. *pdest-- = *psrc--;
  23. }
  24. return dest;
  25. }
  26. // 功能:由src指向地址为起始地址的连续n个字节的数据复制到以dest指向地址为起始地址的空间内。
  27. // 说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针
  28. void *memmcpy(void *dest , const void *src , size_t count)
  29. {
  30. assert( (dest != NULL) && (src != NULL));     //安全检查
  31. assert( count > 0 );
  32. char *psrc = (char *) src;
  33. char *pdest = (char *) dest;
  34. while( count-- )
  35. *pdest++ = *psrc++;
  36. return dest;
  37. }