C++试题(jk) | 悬笔一绝 那岸边浪千叠
Cobb 714 1

一、单项选择题:(每题2分,共计16分)

1、关于this指针,以下说法正确的是 (  A  )
A、保证每个对象拥有自己的数据成员,但共享处理这些数据的代码
B、保证基类私有成员在子类中可以被访问
C、保证基类保护成员在子类中可以被访问
D、保证基类公有成员在子类中可以被访问


2、下面代码断输出的结果为(  D  )
#include<stdio.h> 
void main(void) 
{
      int a = 0, b = 0, c = 0; 
      if((++a>0) && ((++b>0) || (++c>0))) 
      {
            a++;
            b++;
            ++c;
      }
      printf("\na=%d, b=%d, c=%d\n", a, b, c);
}
A、a=2, b=2, c=2    B、a=1, b=1, c=2    C、a=1, b =2, c=2    D、a=2, b=2, c=1


3.如下代码段,最终输出的结果( C   )
#define S  2+3
void main()
{
    int a = S*S;
    printf("a = %X\n", a);
}

A、    a = 25    B、    a = 11
C、    a = B    D、    a = 0xB

4.设j和k都是int类型,则for循环语句
 for(j=0,k=0;j<=9&&k!=876;j++) scanf("%d",&k); (  A  )
A、最多执行10次
B、最多执行9次
C、是无限循环
D、循环体一次也不执行

5.现有如下定义
int coco[4][4] = { 2,9,9,9, 6,8,5,62, 58,56,9,8, 7,4,2,0};
int (*ptr) [4] = coco,*p=coco[0];
以下能正确表示数组元素coco[1][2]的表达式的是(  D  )
A *((*ptr+1)[2])
B *(*(p+6) )
C (*ptr+1)
D *(*(coco+1)+2)

6.下面程序运行的结果是( B   )
char* s = "Mstar";
s += 2;  // 偏移
printf("%s\n",s);
A、Mstar
B、tar
C、‘t’的地址
D、t

7.现有如下程序
#include <stdio.h>

void swap(int * x,int y)
{
    int temp = 0;
    temp = *x;
    *x = y;
    y = temp;
    return;
}

int main()
{
    int x = 2, y = 8
    swap (&x, y);
    printf("x=%d, y=%d\n", x, y);
    return 0;
}
输出结果是(  A  )
A、 x=8, y=8
B、 x=8, y=2
C、 x=2, y=8
D、 x=8, y=2

8、下面这个代码输出的是( C  )
#include <iostream> 
#include <vector>
using namespace std;
int main(void)
{ 
vector<int>array; 
array.push_back(100); array.push_back(300); array.push_back(300); array.push_back(300); array.push_back(300); array.push_back(500); vector<int>::iterator itor; for(itor=array.begin();itor!=array.end();itor++) { if(*itor==300) { itor=array.erase(itor); } } 

for(itor=array.begin();itor!=array.end();itor++) { cout<<*itor<<" "; } return 0;}
A 、100 300 300 300 300 500
B、 100 300 300 300 500
C、 100 300 300 500  // 返回新的it位置,跳过两个
D、 100 300 500
E 、100 500

二、填空题(每题4分,共计32分)


1、以下程序片段 
main()
{
    int i = 2, j = 3, k = 4;
    if(i++ == j)
        printf("%d,%d\n", i++, j);
    else
        printf("%d, %d\n", ++i, ++j);
}
程序运行后i,j的值分别是      4      ,      4       。



2、设以下类定义:
class Base
{
public:
    Base(){}
    virtual ~Base(){}
protected:
    int ma;
};
class Derive : public Base
{
public:
    Derive(){}
    ~Derive(){}
private:
    int mb;
};
int main()
{
    Base *p = new Derive();
    cout << typeid(p).name() << endl;
    cout << typeid(*p).name() << endl;
    cout << sizeof(Base) << endl;
    cout << sizeof(Derive) << endl;
    return 0;
}
请写出程序打印结果:
       Base*      ,     Derive*       ,      8      ,       12     





4、以下程序片段的输出是______7______, _______3______. 
static int m[3][4] = {1, 2, 3, 4,  5, 6, 7, 8};
int *p = &m[0][0];
p++;   // 此时第0组的第0个元素位置指向了 2 , 所以p[1]就是3
printf("%d, %d", m[1][2], p[1]);

5、 A为基类,B为派生类,派生类和基类的成员同名,B可以通过   A的作用域    访问基类A的成员变量; 
如果基类中定义了一个静态成员,并且该基类有3个派生类,整个系统中最多有    1    个该成员的实例存在。

6、以下程序片段的输出结果是:   (下文有详细解释)
_____B:: with number 20____________,
______B:: with number 10__________ 
class A
{
public:
    virtual void Fun(int number = 10)
    {
        std::cout << "A:: with number " << number;
    }
};

class B: public A
{
public:
    virtual void Fun(int number = 20)
    { 
        std::cout << "B:: with number " << number;
    }
};

int main()
{
    B b;
    A &a = b;
    b.Fun();  // 静态
    a.Fun();  // 动态
}
// 限定符是在编译阶段阶段确定的
// 参数压栈也是编译阶段阶段确定的




7、下面代码的功能是判断一个单链表是否有环。请在空白处填写代码,完成其功能。
bool IsExitsLoop(ListNode *head)  
{  
    ListNode *slow = head, *fast = head;  
    while(_fast != NULL && fast->next != NULL_)   
    {  
        slow = slow->next;  
        _fast = fast->next->next;__
        if(slow == fast) break; 
    }  
    return !(fast == NULL || fast->next == NULL);
}

8、某大学生M突患重病,有同学暗中捐款相助。M转危为安后,想知道是谁捐款给他。分别询问了5位同学,得到以下回答: 
1)或者甲捐了,或者乙捐了。
2)如果甲捐,那么丙也捐了。  
3)如果乙没捐,那么丁捐了。 
4)甲和乙都没有捐。 
5)丙和丁都没有捐。
实际上这5为同学的回答只有一句是假的。由此可以推断出     乙      捐了。

填空题6 详解:

#if 0
// 分清编译阶段和运行阶段要做的事情
// 限定符、参数压栈、是在编译阶段阶段确定的

class A
{
public:
    virtual void Fun(int number = 10)
    {
        std::cout << "A:: with number " << number;
    }
};

class B: public A
{
 //public:  //  main()中a.Fun();仍然能够执行,限定符是在编译阶段阶段确定的,编译节点看的是A中的
            // 运行阶段才看的是B中的函数,  A类中的是public,所以可以运行
            // 如果A类中改成private则不可执行
 private:
    virtual void Fun(int number = 20)
    { 
        std::cout << "B:: with number " << number;
    }
};

int main()
{
    B b;
    A &a = b;
    // b.Fun();  // 静态, private限定符在编译阶段有效,所以无法访问。
    a.Fun();  // 动态绑定,参数是在编译阶段压栈确定的。
}

// 参数压栈是编译阶段阶段确定的, 确定参数 10
// 运行阶段确定是哪个函数

#endif 

三、简答题:(共计32分)


备注:
简单题核心:详细有条理
复杂题核心:说出核心点

1、引用和指针的区别(4分)
  1)、汇编指令上,引用就是通过指针实现的,引用表现的和指针相同
  2)、指针不需要非得初始化;定义引用必须初始化的。 操作指针可能会操作空指针,野指针,所以引用是更加安全的指针,
  3)、使用指针修改它指向的内存时,必须要做指针解引用操作(*p=);引用变量可以直接赋值修改它
引用的内存的值,引用使用更加方便。
  4)、可以通过给指针变量赋值,让指针指向其它的内存;但是引用初始化
的时候指定引用的变量内存后,就不能再引用其它内存了,指针使用起来,更加灵活。
  5)、引用只有一级引用,指针可以多级引用

2、解释静态绑定和动态绑定(4分)
  静态绑定:是在编译期间发生的绑定,底层是call 函数地址
  动态绑定:是在运行期间的绑定,通过对象找到虚函数指针,通过虚函数指针找到虚函数表,然后在虚函数表中找到虚函数的地址放入寄存器,然后call 寄存器在运行时调用指定的虚函数

3、解释什么是多态(4分)
  1)基类指针指向不同的派生类对象,调用同名覆盖方法,指针指向哪个对象,就会调用哪个派生类对象的方法。
  2)设计功能接口时,用基类的指针或者引用来统一接收不同的派生类对象即可代码简洁、复用能力强,不用给每一个派生类对象都设计函数接口


4、请列举你所熟悉的容器并做简要功能描述(6分)
  // (底层实现并解释 和 增删查的时间复杂度,使用场景)
  1)顺序容器 vector:底层是个可扩容的数组,当空间装满的时候,会以2倍扩容的方式,开辟新的空间,因为是数组,所以内存连续,下标访问快,非末尾的增加删除慢,会引起大量的数据移动。
链表容器 list  :底层是个双向循环链表,因为是链表,所以内存不连续,增加删除快,如果要访问某一个元素的时候,需要遍历链表。
  2)关联容器:有序的关联容器:set  map底层是个红黑树
  3)无序的关联容器:unordered_set,unordered_map:底层是个链式哈希表。
  4)容器适配器:stack(栈) queue(队列) priority_queue(优先级队列,默认是一个大根堆)


5、请列举你所熟悉的智能指针并做简要功能描述(6分)
  智能指针将裸指针封装为一个类,利用对象出作用域自动析构的特点,
  将资源释放写在析构函数中,防止资源泄露;
  1)auto_ptr :拷贝和赋值时会进行资源转移,再次访问原智能指针会访问空指针;
  2)unique_ptr: 无法进行拷贝和赋值,但是提供了右值引用参数的拷贝构造和赋值函数,也是做资源转移避免进行资源转移;
  3)shared_ptr:强智能指针,能改变资源的引用计数,资源引用计数为0时才会释放;
两个强智能指针交叉引用时,会导致资源无法释放;
  4)weak_ptr:弱智能指针,无法改变资源的引用计数,作为一个观察者,通过查看资源的引用计数,来确定资源是否已被释放;可通过lock方法提升为强智能指针;



6、请列举你知道的C++11新标准的语法,并做简要功能描述(8分)
  Nullptr, 判空
  =delete, 删除函数实现
  =default 构造函数默认实现
  右值引用
  智能指针,出作用域自动释放
  lambda表达式,函数对象,和算法结合使用,作为条件判断。
  auto, 自动推导类型  迭代器 vector<int>::iterator map<int, string>::iterator
  迭代器的简化foreach遍历
  无序关联容器unorderde_set\unorderde_map

四、编程题:(来自网易内推面试题 每题8分,总分32分)

备注: 1、做编程题应想清楚再干,这样会节约时间。 2、最好是能够推翻第一想法,使用下一个或下下个想法。

9706

1、有一天,小明在游戏中获得了一串数字,直觉告诉他这不是一串普通的数字串,或许可以破解一些关于网易的秘密。破解的第一步,他很想知道,在这串数字中,最多可以挑出多少个’9706’串。挑选的规则为: (1)挑出的数字’9’,’7’,’0’,’6’在原串中可以不连续,但是数字的先后顺序不能改变 (2)使用过的数字不能被再次使用。如’123901370997606’可以最多挑出2个’9706’,而’6079’则无法挑出任何一个’9706’。 输入 第一行是整数T(T <= 100),表示下面有T组数据。之后T行,每行为一组数据,每组数据为一个字符串。每个字符串的长度L <= 50000。每个字符串只会包含数字[‘0’…’9’]。 输出 输出T行,每行对应一个数据的输出结果,表示字符串最多能挑出多少个’9706’。 样例输入 4 6097 97069706 997776600069 123901370997606 样例输出 0 2 1 2

#if 0
 int main()
 {
    int u = 0;
    cin >> u;
    vector<int> v;

    for (int i = 0; i < u; i++)
    {
        char str[50001] = { 0 };
        cin >> str;
        int count = 0;
        int size = strlen(str);
        for (int j = 0; j < size; j++)
        {
            if (str[j] == '9')
            {
                int ch = '7';
                for (int k = j + 1; k < size; k++)
                {
                    if  (str[k] == ch)
                    {
                        if (ch == '7')
                        {
                            str[k] = -1;
                            ch = '0';
                        }
                        else if (ch == '0')
                        {
                            str[k] = -1;
                            ch = '6';
                        }
                        else if (ch == '6')
                        {
                            str[k] = -1;
                            count++;
                            break;
                        }
                    }
                }
            }
        }
        v.push_back(count);
    }
    for (auto d : v)
    {
        cout << d << endl;
    }
 }
#endif 



给奶牛分苹果

2、分苹果问题 n 只奶牛坐在一排,每个奶牛拥有 ai 个苹果,现在你要在它们之间转移苹果,使得最后所有奶牛拥有的苹果数都相同,每一次,你只能从一只奶牛身上拿走恰好两个苹果到另一个奶牛上,问最少需要移动多少次可以平分苹果,如果方案不存在输出 -1。 输入描述: 每个输入包含一个测试用例。每个测试用例的第一行包含一个整数 n(1 <= n <= 100),接下来的一行包含 n 个整数 ai(1 <= ai <= 100)。 输出描述: 输出一行表示最少需要移动多少次可以平分苹果,如果方案不存在则输出 -1。

输入例子: 4 7 15 9 5 输出例子: 3

#if 0
int main()
{
    int n;
    cin >> n;
    vector<int> vec;
    int sum = 0;
    for (int i = 0; i < n; i++)
    {
        int tmp;
        cin >> tmp;
        vec.push_back(tmp);
        sum += tmp;
    }

    //  苹果的总数如果不能给牛平均分配,方案 -1
    if (sum % n != 0)
    {
        cout << -1;
        return 0;
    }
    int count = 0;
    for (int i = 0; i < n; i++)
    {
        // abs求绝对值,牛面前的苹果取模为0才可平均分配
        if (abs(vec[i] - sum / n) % 2 != 0)
        {
            cout << -1;
            return 0;
        }
        // 只处理那只牛的苹果大于平局数,总和计算一下就是移动的次数
        if (vec[i] > sum / n)
        {
            count += (vec[i] - sum / n) / 2;
        }
    }
    cout << count;
}

#endif 


顺序处理多个最长子串

3、编程:给定两个字符串A,B(只包含26个英文字母),输出所有公共的最长子字符串(如果出现重复子串,则输出多次) 输入包括两行,每行为一个连续字符串(大小写敏感) 输出包括多行,每行为扫描到的最长公共子串,按照该子串在字符串A(即第一行输入字符串)中出现的先后次序输出 样例输入: abcxyzabcrst opqrstabc 样例输出: abc rst

思路: C++试题(jk) |  悬笔一绝 那岸边浪千叠


#if 0
// 备注: 如果使用BF算法,那么处理相同的公共子串困难
// 动态规划,表格问题,重复出现,左上角数字+1,从表格右->左输出
int main()
{
    string s1 = "abcxyzabcrst";
    string s2 = "opqrstabc";

    // 创建表格
    //int a[s1.size()][s2.size()] = {0};
    vector<vector<int>> a;
    a.resize(s1.size());
    for (auto& b : a)
    {
        b.resize(s2.size());
    }

    // 核心代码
    int maxlen = 0;
    for (int i = 0; i < s1.size(); i++)
    {
        for (int j = 0; j < s2.size(); j++)
        {
            if (s1[i] == s2[j])
            {
                if (i == 0 || j == 0)
                    a[i][j] = 1;
                else
                    a[i][j] = a[i - 1][j - 1] + 1;
                if (a[i][j] > maxlen)
                    maxlen = a[i][j];
            }
        }
    }

    cout << maxlen << endl;

    // 从最后一列开始输出
    for (int j = s2.size()-1; j >= 0; j--) // col
    {
        for (int i = 0; i < s1.size(); i++) // row
        {
            if (a[i][j] == maxlen)
            {
                cout << s2.substr(j - maxlen+1, maxlen) << endl;
                break;
            }
        }
    }

    return 0;
}

#endif 


母串中删除子串

4、编程:在一个整数的数组中删除另外一个整数数组中的元素,并保留原数组的次序 输入包括两行:

  1. 第一行是被删除的整数列表(记为列表A),每个整数之间使用空格分隔
  2. 第二行是需要删除的整数列表(记为列表B),每个整数之间使用空格分隔 输出只有一行,即列表A中删除列表B元素后的整数列表,输出元素按照在列表A中的次序排列,每个整数之间使用空格分隔 样例输入: 1 2 3 4 5 2 4 样例输出: 1 3 5

#if 0

int main()
{
    // strtok
    list<int> src;
    list<int> del;

    string str1;
    getline(cin, str1);

    char* p = strtok((char*)str1.c_str(), " ");
    if (p != NULL)
    {
        src.push_back(atoi(p));
    }

    // 把字符串转成数组放入链表中
    for (;;)
    {
        p = strtok(NULL, " ");
        if (p == NULL)
            break;
        src.push_back(atoi(p));
    }

    string str2;
    getline(cin, str2);

    p = strtok((char*)str2.c_str(), " ");
    if (p != NULL)
    {
        del.push_back(atoi(p));
    }

    // 把字符串转成数组放入链表中
    for (;;)
    {
        p = strtok(NULL, " ");
        if (p == NULL)
            break;
        del.push_back(atoi(p));
    }

    list<int> result;

    // back_inserter(result) 尾插容器迭代器 (https://www.jianshu.com/p/6862a79eba0a)
    // 求交集的函数 
    // set_intersection(src.begin(), src.end(),del.begin(), del.end(), back_inserter(result));

    // 求差集
    set_difference(src.begin(), src.end(), del.begin(), del.end(), back_inserter(result));


    for (auto v : result)
    {
        cout << v << " ";
    }
    cout << endl;
}

#endif 

五、设计题:(新浪笔试 8分)

1.MySQL作为持久化存储,在互联网IT行业被广泛使用。但MySQL由于其性能受限于磁盘性能,逐渐无法满足web2.0时代大型互联网服务的性能要求。

Memcache作为内存缓存服务,以其高性能著称,逐步被众多互联网公司引入以提高吞吐量以及响应性能。

互联网常用的存储架构选型是Memcache作为缓存 + MySQL作为数据库,假设业务请求量为100万/s,MySQL可支持10万/s的qps。

1.Memcache需要最低满足多少命中率? 90万 / 100万 = 90% 2.假设单个K-V是200Byte,估算Memcache带宽? (200 B* 90万) / 1024 /1024 = 171.66M 3.每天访问过Memcache的key总数(去重)共1亿条,估算Memcache需要消耗多少内存? (1亿 * 200B * 0.9)/ 1024 /1024 / 1024 = 16.76G

评论区

索引目录