大疆秋招笔试

单选

1.以下关于extern的说法,错误的是()

A. extern修饰的符号可以在其他模块使用        B. extern int foo();等同于int foo();

C. 匿名命名空间内定义的变量不可被extern        D.exter "C"修饰的方法支持重载

解析:

A. extern修饰的符号可以在其他模块使用:正确extern用于声明外部符号,使其在多个文件之间共享。

B. extern int foo(); 等同于 int foo();:正确extern声明的函数默认是全局可见的,与直接声明函数没有区别。

C. 匿名命名空间内定义的变量不可被extern:正确。匿名命名空间内的符号只能在当前编译单元内访问,无法通过extern在其他地方引用。

D. extern "C"修饰的方法支持重载:错误extern "C"用于指定C语言链接方式,不支持C++的函数重载,因为C语言本身不支持重载。

2. 关于如下代码的说法,正确的是()

class A {
public: 
    void func(){
        printf("hello world!");
    }
private:
    int a;
};

int main(int argc, char *argv[]){
    A*p=nullptr;
    p->func();
    return 0;
}

A. 编译警告:空指针,运行崩溃

B. 编译通过,运行崩溃

C. 编译通过,可运行,控制台输出“hello world!”

解析:正确的说法是 B. 编译通过,运行崩溃

  1. 编译通过:代码会成功编译,因为在C++中,调用成员函数不需要检查指针是否为空。编译器不会在编译阶段检查 p->func()p 是否为 nullptr

  2. 运行崩溃:代码中 p 被初始化为 nullptr,但是 p->func() 调用了空指针对象的方法。虽然函数本身没有访问类的成员变量 a(如果访问成员变量,可能会更快导致崩溃),但在大多数系统上调用空指针成员函数仍然会导致运行时错误(崩溃)。

 3. 64位系统下,对如下结构体取sizeof,结果应为()

struct DATA64{ 
    int* a; 
    char b; 
    int c; 
    int64_t d; 
}

解析:24字节。由于不同成员有不同的大小,编译器会对结构体进行对齐。

  1. int* a: 指针类型,64位中占用8字节。
  2. char b: 占用1字节,但为了对齐到下一个 int c 的4字节边界,编译器会在 b 后面填充3个字节,使得总长度为4字节。
  3. int c: 占用4字节,刚好对齐。
  4. int64_t d: 占用8字节,需要对齐到8字节边界,所以编译器可能会填充额外的字节。

 4. 使用小端字节序时,对于int a=0x12345678,在内存中由低到高的布局是()

解析:在小端字节序(Little-Endian)中,数据的低字节存储在内存的低地址处,高字节存储在内存的高地址处。

对于 int a = 0x12345678,其十六进制表示可以分为4个字节:

  • 0x12(高字节)
  • 0x34
  • 0x56
  • 0x78(低字节)

在小端字节序下,这4个字节在内存中的布局(从低地址到高地址)将是:

  • 低地址 -> 0x78
  • 接着 -> 0x56
  • 接着 -> 0x34
  • 高地址 -> 0x12

因此,内存中的布局由低到高依次为: 0x78 0x56 0x34 0x12

5. 不稳定的排序算法有:

  • 快速排序(Quick Sort)
  • 选择排序(Selection Sort)
  • 堆排序(Heap Sort)
  • 希尔排序(Shell Sort)

这些算法在排序过程中可能会改变具有相同值的元素的相对顺序,因此它们是不稳定的。

 6. 以下对于内存管理的说法,错误的是()

A. 进程内存空间分为数据段、代码段、BSS、堆、栈

B. 当内存空间充足时,应用程序直接访问物理内存,当内存不足时,操作系统会分配虚拟内存给应用程序使用

C. 内存分段比内存分页的内存交换效率低

D. 内存分页机制下,内存分配的最小单位为一页

解析:

A. 正确。进程内存空间通常分为代码段、数据段、BSS段、堆、栈等不同区域。

B. 错误。应用程序无论内存是否充足,都不直接访问物理内存,而是通过操作系统的内存管理机制访问虚拟内存。操作系统会将虚拟内存映射到物理内存中,并根据需要使用分页或分段技术进行内存管理。当物理内存不足时,操作系统会将部分数据交换到硬盘上的交换空间或页面文件中。

C. 正确。内存分段的管理比分页复杂,且内存交换效率通常低于分页机制。

D. 正确。在内存分页机制下,内存分配的最小单位是“页”(page),通常是4KB大小。

多选

1. 以下关于static的说法,正确的是()

A. 设计和使用静态全局变量,静态局部变量的函数时,需要考虑重入问题

B. 全局static变量和局部static变量的存储区位置不同

C. static可以限制符号的可见范围

D. 静态全局变量过大时,可能会导致堆栈溢出

解析:

A. 正确。静态全局变量和静态局部变量在函数内部保持状态,如果函数是多线程访问的,则需要考虑重入问题和线程安全问题。

B. 错误。全局 static 变量存储在数据段中,而局部 static 变量也存储在数据段中,但它的作用域仅限于所在的函数内部。它们的存储区位置相同,但作用域不同。

C. 正确static 可以限制符号的可见范围。在函数内部声明 static 变量会将其作用范围限制在函数内;在全局作用域声明 static 变量则会限制其只在当前编译单元内可见。

D. 错误。静态全局变量存储在数据段,而堆栈溢出通常是由于栈空间耗尽造成的,静态全局变量的大小不会影响栈空间。

2. 以下关于构造函数和析构函数的说法,错误的是()

A. 向std::vector中插入元素时,只涉及到对象的拷贝,所以不会调用移动构造函数

B. 将构造函数设计成虚函数,可实现不同类型的数据初始化多态

C. 将析构函数设计成虚函数,可实现不同类型的数据释放多态

D. 如果在拷贝构造函数中使用值传参,最大的问题是多一次数据拷贝。如果对象数据量很小,使用值传参也是可以接受的 

解析:

A. 错误。向 std::vector 中插入元素时,如果支持移动语义(即对象有移动构造函数),且元素可以被移动,则可能会调用移动构造函数。并不总是只涉及到对象的拷贝。

B. 错误。构造函数不能是虚函数。C++标准中规定构造函数不支持虚函数机制,因此无法通过将构造函数设计成虚函数来实现多态。

C. 正确。将析构函数设计成虚函数,可以确保在多态情况下正确调用派生类的析构函数,防止资源泄漏,达到多态释放资源的目的。

D. 正确。如果在拷贝构造函数中使用值传参,会导致多一次数据拷贝,这确实可能带来性能损失,但如果对象的数据量很小,代价较小,可以接受。

3. 以下关于虚函数的说法,正确的是()

A. C++的虚函数是在编译时期动态绑定的

B. C++的虚函数是在运行时期动态绑定的

C. 尽量将短小的虚函数定义为内联函数,可以加快程序编译速度

D. 使用多重继承后,编译器会添加多个虚表指针

解析:

A. 错误。C++的虚函数是在运行时期进行动态绑定的,这种机制使得调用哪个函数由对象的实际类型决定,而不是编译时决定。

B. 正确。虚函数的动态绑定是在运行时期进行的,这样在执行期间能够正确调用派生类的函数实现。

C. 正确。将短小的虚函数定义为内联函数可以减少函数调用的开销,并可能提高程序的性能,但编译器可能会根据情况决定是否实际进行内联化。

D. 正确。使用多重继承时,编译器会为每个基类创建一个虚表指针,因此会有多个虚表指针(vptr),以正确处理不同基类的虚函数。

4.  以下关于STL容器的说法,错误的是()

A. std::deque只能从最后面插入元素                B. std::list是一个单链表结构

C. 当删除std::vector内中间的一个元素时,所有迭代器都将失效

D. std::map基于哈希表实现

解析:

A. 错误std::deque(双端队列)允许在前面和后面插入元素,而不仅仅是在最后面。

B. 错误std::list 是一个双向链表(双向链表结构),不是单链表。

C. 正确。在 std::vector 中删除中间的元素会导致元素后面的所有元素向前移动,这样所有指向这些元素的迭代器都会失效。

D. 错误std::map 基于红黑树(或其他自平衡的二叉搜索树)实现,而不是哈希表。哈希表实现的容器是 std::unordered_map

5. 以下关于多线程的说法,正确的是()

A. 线程之间栈是公有的                B. 线程之间堆是公有的

C. 读写锁可实现线程同步            D. 信号量可实现线程同步 

解析:

A. 错误。线程之间的栈是私有的。每个线程都有自己的栈,用于存储局部变量和函数调用信息。

B. 正确。线程之间的堆是公有的。多个线程可以共享进程的堆区域,它们可以在堆中分配和访问共享的数据。

C. 正确。读写锁(如 std::shared_mutex)可以实现线程同步,允许多个线程并行读访问,而写访问是互斥的。

D. 正确。信号量(如 std::semaphore)也可以实现线程同步,控制线程对共享资源的访问。

6. 数据结构中的线性结构有() 

解析:

  • 数组(Array):固定大小的顺序存储结构,可以通过索引直接访问元素。
  • 链表(Linked List):由节点组成的链式存储结构,每个节点包含数据和指向下一个节点的指针。
    • 单链表(Singly Linked List):每个节点只包含一个指向下一个节点的指针。
    • 双链表(Doubly Linked List):每个节点包含两个指针,一个指向下一个节点,另一个指向前一个节点。
    • 循环链表(Circular Linked List):链表的最后一个节点指向第一个节点,形成一个环。
  • 栈(Stack):遵循“后进先出”(LIFO)原则的线性数据结构,支持在一端插入和删除元素。
  • 队列(Queue):遵循“先进先出”(FIFO)原则的线性数据结构,支持在一端插入,在另一端删除元素。
    • 双端队列(Deque):允许在两端插入和删除元素的队列。

其他

1. std::shared_ptr的引用计数是线程安全的

2. 对于任意一颗二叉树,如何确定这颗二叉树的结构:中序+前/后

编程

第一题:

 解答:100%AC

#include <iostream>
#include <unordered_map>
#include <vector>
#include <algorithm>

int main() {
    // 每个机场无人机的数量
    std::unordered_map<int, int> airportDrones;

    // 降落数
    int numLandings;
    std::cin >> numLandings;

    for (int i = 0; i < numLandings; ++i) {
        int airport;
        std::cin >> airport;
        // Increment the number of drones at the airport
        airportDrones[airport]++;
    }

    // 起飞数
    int numTakeoffs;
    std::cin >> numTakeoffs;

    for (int i = 0; i < numTakeoffs; ++i) {
        int airport;
        std::cin >> airport;
        // 把起飞对应的机场无人机数-1
        if (airportDrones[airport] > 0) {
            airportDrones[airport]--;
            // 如果机场没有无人机 移除
            if (airportDrones[airport] == 0) {
                airportDrones.erase(airport);
            }
        }
    }

    // Count the number of airports with each number of drones (1 to 15)
    std::vector<int> countDistribution(15, 0);
    for (const auto& pair : airportDrones) {
        int count = pair.second;
        if (count > 0 && count <= 15) {
            countDistribution[count - 1]++;
        }
    }

    // Output the result
    for (int i = 0; i < 15; ++i) {
        std::cout << countDistribution[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

第二题:

解答:75%AC

#include <iostream>
#include <deque>
#include <string>

int main() {
    std::string s;
    std::cin >> s;

    std::deque<char> dq(s.begin(), s.end());

    int steps = 0;
    
    while (1) {
        bool replaced = false;

        std::deque<char> new_dq;

        while (!dq.empty()) {
            if (dq.size() >= 2 && dq[0] == '0' && dq[1] == '1') {
                new_dq.push_back('1');
                new_dq.push_back('0');
                dq.pop_front(); // Remove '0'
                dq.pop_front(); // Remove '1'
                replaced = true;
            } else {
                new_dq.push_back(dq.front());
                dq.pop_front();
            }
        }

        if (!replaced) {break;}

        dq = new_dq;
        steps++;
    }
    std::cout << steps << std::endl;

    return 0;
}

 

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值