【2014.11.19】程序员面试

  1. 编写代码时,注意考虑边界条件,特殊输入(比如空指针,空字符串等)及错误处理。
  2. 空类型。 空类型的实例中不包含任何信息,求sizeof应该是0,但是当我们声明该类型的实例的时候,它必须在内存中占有一定的空间,否则无法使用这些实例。占用多少内存由编译器决定。Visual Studio中,每个空类型的实例占用1字节的空间。调用构造函数和析构函数只需要知道函数的地址即可,而这些函数的地址只与类型相关,与类型的实例无关。编译器发现一个类型中含有虚函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针。32位机器上求sizeof得到4, 64位机器上求sizeof得到8.
  3. 四个与类型转换相关的关键字。
    1. const_cast:
    2. dynamic_cast:
    3. static_cast:
    4. reinterpret_cast:
  4. 复制构造函数传入的参数是一个实例的后果:如果是传值参数,把形参复制到实参会调用复制构造函数,因此,如果允许复制构造函数传值,就会在复制构造函数内调用复制构造函数,就会形成永无休止的递归调用从而导致栈溢出。C++标准不允许复制构造函数传值参数。

    以下三种对象需要调用复制构造函数:

    1) 一个对象作为函数参数,以值传递的方式传入函数体

    2) 一个对象作为函数返回值,以值传递的方式从函数返回

    3) 一个对象用于给另外一个对象进行初始化。

  5. 赋值运算符函数
    1. 返回值的类型声明为该类型的引用,并在该函数结束前返回实例自身的引用(即*this)
    2. 传入的参数类型声明应为常量引用。如果是实例,那么从形参到实参会调用一次复制构造函数,降低了代码效率。
    3. 释放实例自身已有的内存,如果忘记在分配新内存之前释放自身已有的空间,程序将出现内存泄露。
    4. 需要判断传入的参数和当前的实例(*this)是不是同一个实例。如果是同一个,则不进行赋值操作,直接返回。

      class CMyString
      {
      public:
          CMyString(char* pData = NULL);
          CMyString(const CMyString& str);
          CMyString& operator= (const CMyString& str);
          ~CMyString();
          void print();
      private:
          char* m_pData;
      };

      CMyString::CMyString(char* pData)
      {
          if (pData == NULL)
          {
              m_pData = new char[1];
              *m_pData = '\0';
          }
          else
          {
              m_pData = new char[strlen(pData) + 1];
              strcpy_s(m_pData, strlen(pData) + 1, pData);
          }

      }

      CMyString::CMyString(const CMyString& str) //复制构造函数
      {
          m_pData = new char[strlen(str.m_pData) + 1];
          strcpy_s(m_pData, strlen(str.m_pData) + 1, str.m_pData);
      }

      CMyString& CMyString::operator=(const CMyString& str)  //赋值运算符函数
      {
          if (this == &str)
              return *this;
          delete[] m_pData;
          m_pData = NULL;
          m_pData = new char[strlen(str.m_pData) + 1];
          strcpy_s(m_pData, strlen(str.m_pData) + 1, str.m_pData);

          return *this;
      }

      CMyString::~CMyString()
      {
          delete[] m_pData;
      }

  6. 数组和指针。
    1. int data1[] = {1,2,3,4,5}; sizeof(data1) = 20
    2. int* data2 = data1; sizeof(data2) = 4
    3. 当数组名作为函数参数进行传递时,数组自动退化为同类型的指针。
  7. 宽度优先遍历:先访问树的第一层结点,再访问树的第二层结点…一直到访问到最下面一层结点。
  8. 位运算
    1. 左移运算符:m<<n表示把m左移n位,最左边的n位将被丢弃,同时在最右边补上n个0。
    2. 右移运算符:m>>n表示把m移n位,最右边的n位将被丢弃,如果数字是无符号的,则用0填补最左边的n位;如果是个有符号的数值,则用数字的符号位填补最左边的n位。
    3. 把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。(用于计算一个整数的二进制中含有多少个1)
  9. C++中,成员变量的初始化顺序只与他们在类中声明的顺序有关,而与在初始化列表中的顺序无关。
  10. 正整数的最大值0x7FFF FFFF,最小的负整数是0x8000 0000。
  11. 右移运算符可以代替除以2(num>>2)。位于运算符可以代替求余运算符(%)来判断一个数是奇数还是偶数。(num & 0x1 == 1)

posted on 2014-11-19 16:46  sjtujoe  阅读(188)  评论(0编辑  收藏  举报