c++笔试面试总结

来源:互联网 发布:阿里巴巴云计算是什么 编辑:程序博客网 时间:2024/05/14 07:58

C++:

1. c++的new可以指定地址
struct T:B
{
    public:
        void * operator new(size_t sz, T& t){}
};

int main()
{
    T tb;
    T * t = new(tb) T;    //必须是tb在前,因为tb指明size,不知道这个有什么用
}

2. c++中的=号必须是class的成员函数,不能是全局函数。
原因:
int operator=(int a, integer b);
这样重载之后,语句2 = a; 表述也是正确的,但是却是明显的语法错误为了避免此类错误,需要将赋值操作符重载为成员函数

3.new的操作。
1:call operator new. if operator new is overridden by user then compiler willcall user-defined version. operator new return void *
2:call constructor to construct object
3:change void * to user-defined type(class type, withstatic_cast<class*>(void* address));
so we can override operator new and change the memory allocation in thefunction. we can pre-allocate a big block of memory and in the operator new wejust allocate from this memory instead of allocating from system memory. ofcourse we can override operator delete and release the memory back to thememory block instead of system memory. actually this is called memory pool.

4. placement new
new可以指定一个内存地址构造对象,而不是申请一个新的内存地址。
方法:new (address) type(parameters);
当然可以用placement new,但是没有placement delete,所以当使用了placement new后,需要使用显示调用析构函数清除对象本身,但是没有释放内存,因为free不会调用析构函数。
所以说构造函数和析构函数都是可以显示调用的。
placement new会调用带两个参数的void * operator new(size_t sz,void * t); //第二个参数不一定要void*,任何参数都可以,只要返回void*的内存地址就可以。
placement new的地址应该由申请address的人释放,不建议new对象的人释放。
参考:http://hi.baidu.com/qufuping1981/blog/item/81120df0e27091aca40f5213.html

5. c++中将user-defined类型转成basic类型:
1. 写个函数将两个类型转换
2. 在类中写个类型转换成员函数,比如
class T{
public;
operator int(){return 1;}    //貌似这个格式就是这样的,必须int写在()上,而不能写在前面
};

 

6.c++ operator overloading:
http://www.cs.caltech.edu/courses/cs11/material/cpp/donnie/cpp-ops.html

 

7.c++中+号返回的是右值,不能当左值用。operator+操作符返回的是对象,不是引用,=号返回的引用,即左值,可以赋值。

 

8. &的优先级比==低,所以需要if((x&i)==x)用个括号将&括起来

+的优先级比<<高


9. shared condition variant.
1. require mutex
2. test predicate
3. if predicate is true then do something and release mutex
4. if predicate is false then cond_wait for the predicate. if it returns thencontinue to test predicate(jump to 2).

10. c++中交换两个数不用临时变量的方法:
1. a = a+b; b= a-b ; a=a-b
2. a = a^b; b= a^b;a=a^b;
挺无聊的题目,但是确实不用临时变量。

 

11. 类非静态成员变量不能作为成员函数的默认参数

12. struct继承默认是public的,class默认是private的。

13. uml中+号是public,-号是private,#是protected。

14. c++类的const方法可以由const对象调用。因为const方法的this是const的,非const的this可以传给const的this,即
const对象只能调用const函数。因为const方法里面的this是const的。非const方法里面的this是非const的。
class T{
public:
    const void func()const{
    }
    void func(){
    }
    T(){}
};

int main(){
    T t;
    t.func();        //non constversion
    const T ct;
    ct.func();    //const version
}

这里必须有构造函数,因为如果不加的话,const T ct;通不过编译的。因为const对象是初始化一次,而且不能被修改,所以只能在构造函数中初始化,但是默认的构造函数是什么都不做的,即它不会初始化 const对象,所以会报错,而用户自定义的构造函数虽然什么都没干,但是编译器会认为它将const成员初始化了,所以编译通过。

 

15. 为什么空类的sizeof不是0,而是1。
这就是我们刚才所说的实例化的原因(空类同样可以被实例化),每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以a,b的大小为1.
就是new 0的时候未定义。

 

16. C++ padding:

class T
{
public:
    int a;
    char b;
};

class T:Tpublic T
{
public:
    char c;
};
sizeof(T)=12,父类的padding被带到了子类中,子类的padding自己重新算

17. 纯虚类虚表:

存虚类没有虚表
虚表放在代码段
每个有虚函数的类有个虚表,如果不实例化对象,则没有虚表简历(所以存虚函数没有虚表).
如果父类子类都有自己的虚函数,则父类子类都有各自的虚表,只是各自的虚表里面的内容可能不相同(所以可能有多态功能)
如果存虚函数被继承了并且子类示例化了,子类有虚表,但是存虚父类依旧没有虚表。

1. 单类的:
class T{
    virtual void vfunc(){}
    virtual void vvfucn(){}
};

//class T的虚表
_ZTV1T:
    .long   0
    .long   _ZTI1T
    .long   _ZN1T5vfuncEv       //这个是虚表,具体的函数实现在代码段的其他地方。
    .long   _ZN1T6vvfucnEv       //两个虚函数
    .weak   _ZTI1T
    .section   .rodata._ZTI1T,"aG",@progbits,_ZTI1T,comdat
    .align 4
    .type   _ZTI1T, @object
    .size   _ZTI1T, 8
有两个virtual function:_ZN1T5vfuncEv,_ZN1T6vvfucnEv。

2. 有继承的:
class T{
    virtual void vfunc(){}
    virtual void vvfucn(){}
};

class TT:public T{
    virtual void vfunc(){}
};

//class TT的虚表:
_ZTV2TT:
    .long   0
    .long   _ZTI2TT
    .long   _ZN2TT5vfuncEv    //vfunc使用classTT的vfunc
    .long   _ZN1T6vvfucnEv    //vvfunc是有父类classT的vvfunc
    .weak   _ZTI2TT
    .section   .rodata._ZTI2TT,"aG",@progbits,_ZTI2TT,comdat
    .align 4
    .type   _ZTI2TT, @object
    .size   _ZTI2TT, 12

//class T的虚表
_ZTV1T:
    .long   0
    .long   _ZTI1T
    .long   _ZN1T5vfuncEv    //父类的虚表不受继承的影响
    .long   _ZN1T6vvfucnEv
    .section    .eh_frame,"a",@progbits

虚表指针是放在对象内存layout的头部的。

 

C语言:

1.      int a[10]={0};      可以对a进行初始化全0,int a[10]={}同样可以初始化a。

2.       

#define NUM 5
int main(){
   NUM++;    //错误的,不能对右值进行赋值
}

 

3.      printf("%03.1f\n",123.34);   //输出 123.3,%03.1f表示最小长度为3包含.号,不足的加0前面,小数点后面为1位,多的小数点直接去除,不进位。

 

4.      printf("%3.5s\n","asdfsaf");   //就输出5位,asdfs,没有多余的。最小3位。


5.  int n = 10;
int a[n] ;     不行,但是gcc现在可以的 ,面试官说c90不行,c99可以。Vs2008也不行,看来gcc还是做过改动的。

 

6.      int a[3] = {0x112233,0x334455,0x778899};
int * a1 = &a[0]+1;
printf("%p,%p,%p\n",a1,&a[0],a);
int * b = (int*)((int)a1+1);    //指向a1的地址+1的地方。
printf("%x\n",*b);    //输出0x99003344   

 

7.      int n = 10;
typeof(n) b = 10;    //typeof(n) 即int   ,即int b=10;

 

8.      内核里有很多#define(x) do{x}while(0);      //目的是保证x被执行一次。

 

9.      struct pair{int a,int b;};
struct pair g_pair;
  void test(struct pair & p){
     p = g_pair;
  }
it can work. first time to use this method. got confused with java.

 

10.   

#include<stdio.h>
#include <stdlib.h>
#include <string.h>
struct test
{
    int a:5;
       int:2;
    int b:2;
    int c:4;
};

int main()
{
    struct test t;
    struct test * tp = &t;
    tp+=1;
    memcpy(&t,"EMC EXAMINATION",sizeof(t));
    printf("%d,%d,%x,%x,%d\n",t.a,t.b,t,*tp,t.c);
}
EMC的笔试题目:在使用bit位操作时,如果一个int只用了k位,那么剩余的32-k位将被填上k位的最高位的值。
比如b只用了2位,那么剩余的30位会被填上1,因为b的最后两位是10.
c用了4位,剩余28位被填上了0,因为c的最后四位是0110

 

11.   

int a = 0;
~a = -1;
-a = 0;
所以判断一个数是不是unsigned必须使用取反~

 

12.  貌似!的优先级比>高,所以
int a = 1;
k = !~a++>3; 所以!~a++用于等于0只要a不等于0,而0>3用于等于0,所以k用于等于零。

13.  指针不能相加的。
int a[]={1,23,23};
int * p  = a;
int * q = a+1;
p = q+p;        //compilation error

14.  动态存储方式,就是程序运行时分配释放的,不是编译时。

15.  const char * a = "sdf";   //*a是const,不能变,但a可以变。
char * const a = "sdf";    //a不可以变,但是*a能变。

16.  'A'=65,'0'=30,'a'=97

17.  char*strs[N]={"01010101","0101010","001010","01010101001"};一维数组,每个元素是个char*指针。

18.  二维数组不能对第一维度赋值。 因为不能对数组赋值,即char a[]="asdf",char b[]="sdf";不能a=b。

19.   

char a[]="abcdfd"; a的大小为7,6个字符+1个0.

a^b=c==> a=c^b    //learn from sohu campus hire

 

20.   

判断一个数n是否有2个幂:
 n&&!(n&(n-1))    //先要判断n是否为0

21.  -1的表示为0xffffffff, 但是如果是有符号数,则输出-1, 无符号数输出4294967295

22.  memcpy不能overlap
memmove可以overlap 

23.   

c++ 负数取模:a%b=a-(a/b)*b
负数取模:1%-3 = 1-(1/(-3))*(-3) = 1
         -8%5 = -8 - ((-8)/5)*5 = -3

24.   

#include <stdio.h>  

struct node{  

  node* next;  

  node* prev;  

};  

int main()  

{  

    node n[2];  

    node* p1 = &n[0];  

    node* p2 = p1++;  

    printf("%d,",p1 - p2);  

    printf("%d,", (unsigned long)&(p1->next) - (unsigned long)&(p2->next));  

    printf("%d,", (unsigned long)&(p1->prev) - (unsigned long)&(p2->next));  

    return 0;  

这道题目是考察对指针+1与-1时跨度的问题。
对结构体指针p1,当p1++时跨度是8个字节,因为sizeof(struct node)是8,同样p2-p1跨度是8个字节,但是差只有1,因为他们的计算对象是结构体。
而对于printf("%d,", (unsigned long)&(p1->next) - (unsigned long)&(p2->next)); 这个应该是8因为他将地址转成了long型,则将地址作为整数进行计算,所以地址跨度即变量差值,结果为8。
如果是printf("%d,",  &(p1->next) - &(p2->next));  则两个变量的地址跨度是8字节,但是变量的sizeof为4,则变量差距为2。
所以由上可知,变量的跨度是地址的跨度/sizeof(变量)。

 

25.  问int **a[10]; 的意思   //1维数组,维度10,每一个元素是int**,指向个二维数组。 //二维指针数组

 

26.  int *(*a)[10];           //a是个指针,指向一个数组,数组元素为int*
其实二个都是3三维数组

27.  int (*a[10])()函数指针数组

指针相关的:太牛了
int   f()         f是一個函數,返回一個整型值
int   *f()        f是一個函數,返回一個整型指針
int   (*f)()       f是一個函數指針,所指向的函數返回一個整型值
int   *(*f)()      f是一個函數指針,所指向的函數返回一個整型指針
int   f[]         f是一個整型數組
int   *f[]       f是一個指針數組,數組元素的類型是整型指針
int   (*f)[]       f是指针,指向一个数组,数组元素為整型
int   f()[]        非法。f是一個函數,但是函數不可能返回一個數組,函數只能返回標量值。
int   (*f[])()      f是一個數組,數組元素類型為函數指針,所指向的函數返回整型值
int   *(*f[])()    f是一個指針數組,指針所指向的類型是返回值為整型指針的函數

 

28.   

l-value:storage represented by an expression. //a place that is writable.
r-value: the value contained in the storage.     // just a valuewhich cannot be writable.