Administrator
发布于 2023-12-11 / 10 阅读 / 0 评论 / 0 点赞

长沙九维时空技术(C++实习生)

岗位情况

公司详情

领域:音视频

项目:云手机平台,webRTC

薪资:

  • 3500(全勤情况下)

  • 双休 (可能周六加班)

  • 9:00-6:00,弹性

转正后:

  • 8-10k

笔试

链表和数组的区别

int *p1[10];和int (*p2)[10];

int *p1[10]int (*p2)[10] 是两个不同的声明形式,它们有以下区别:

  1. int *p1[10]:这是一个数组,数组中每个元素都是指向 int 类型的指针。可以将其理解为一个包含 10 个指针的数组。每个指针可以指向一个或多个 int 值。

    cppCopy Codeint *p1[10];
    

  2. int (*p2)[10]:这是一个指针,指向一个包含 10 个 int 元素的数组。可以将其理解为一个指向数组的指针。

    cppCopy Codeint (*p2)[10];
    

总结:

  • int *p1[10] 声明了一个包含 10 个指针元素的数组。

  • int (*p2)[10] 声明了一个指向包含 10 个 int 元素的数组的指针。

molloc()是否有错?

  1. 手写快排和冒泡

#include <iostream>

using namespace std;

// 交换函数,用于交换数组中两个元素的位置

void swap(int& a, int& b) {

int temp = a;

a = b;

b = temp;

}

// 划分函数,将数组划分为左右两部分,并返回划分后基准元素的索引

int partition(int arr[], int low, int high) {

int pivot = arr[high]; // 选择最右边的元素作为基准

int i = low - 1; // i表示小于基准元素的区域边界

for (int j = low; j <= high - 1; j++) {

if (arr[j] < pivot) {

i++;

swap(arr[i], arr[j]); // 将小于基准的元素移到左边区域

}

}

swap(arr[i + 1], arr[high]); // 将基准元素放到正确的位置上

return i + 1; // 返回基准元素的索引

}

// 快速排序函数

void quickSort(int arr[], int low, int high) {

if (low < high) {

int pivotIndex = partition(arr, low, high); // 划分数组

quickSort(arr, low, pivotIndex - 1); // 对左半部分递归排序

quickSort(arr, pivotIndex + 1, high); // 对右半部分递归排序

}

}

// 打印数组

void printArray(int arr[], int size) {

for (int i = 0; i < size; i++) {

cout << arr[i] << " ";

}

cout << endl;

}

int main() {

int arr[] = {9, 2, 5, 7, 1, 8, 3};

int n = sizeof(arr) / sizeof(arr[0]);

cout << "原始数组:";

printArray(arr, n);

quickSort(arr, 0, n - 1);

cout << "排序后的数组:";

printArray(arr, n);

return 0;

}

  1. UDP和TCP的区别和应用

UDP和TCP都属于计算机网络中的传输层协议,但它们有以下区别和不同的应用场景:

  1. 可靠性: TCP是一种可靠性协议,它保证了数据传输的可靠性,确保数据的完整性和顺序。UDP则是一种不可靠性协议,它不对数据传输的可靠性做出任何保证,因此可能会丢失或重复。

  2. 连接性: TCP是面向连接的协议,必须先建立连接然后再进行数据传输,以保证数据的正确传输。UDP则是无连接的协议,发送数据前不需要建立连接,每个数据包都是独立的。

  3. 速度: 由于TCP需要保证数据传输的可靠性和顺序,因此它通常会比UDP慢一些。UDP则相对来说更快,因为它不需要进行错误检查、确认和重传等操作。

  4. 应用场景: 在需要高可靠性、顺序传输的数据传输场景下(如文件传输、电子邮件等),TCP是首选协议。在需要快速传输且可靠性不是第一考虑因素的场景下(如音频、视频、游戏等),UDP是首选协议。

总之,TCP和UDP都有各自的优缺点和适用场景,需要根据具体的情况选择合适的协议

技术面

自我介绍

项目自己做的吗?

os设计是moon课的,我负责实现

项目中最难的,影响深刻的点?

os,plic 设备,总是出异常,中断,系统总是崩,

解决方法:查,

50多个终端异常码,对着异常码查。

然后看到底是哪出问题?

多线程同步?

”锁和cv信号量?共享内存

惊群效应,多个线程等待一个锁,

该锁释放,所有线程全国都起来抢一个锁,造成巨量浪费

用信号量(这里说错了),就只唤醒一个,
(开始胡说。。。。)

本质上是一个双锁,外锁和内锁,当前持有锁的线程,在内锁中执行代码,获得内锁时释放外锁

第一个等待该锁的(也就是下一个要执行的)获得外锁等待内锁。

等真正到自己执行时,获得内锁释放外锁。

就这样,实现了只通知一个,不会引起惊群“

------
事后,其实是是条件变量std::condition_variable,cv.notify_one()

至于后面的解释,我也不知道是不是对的。

您的回答有一些问题和混淆。

首先,锁和条件变量是多线程同步中常用的工具,它们可以协调不同线程之间的执行。当一个线程需要改变某个共享资源的值时,需要先获取锁来保证互斥性,然后再修改共享资源的值。如果另一个线程希望访问同一个共享资源,它需要等待锁的释放。当一个线程已经完成操作后,需要释放锁来允许其他线程对共享资源进行操作。

其次,信号量和条件变量是不同的同步机制。信号量是一种计数器,可以用来控制并发执行的线程数量。信号量具有两个基本操作:wait(等待)和signal(发布)。wait 操作会减少信号量的值,如果信号量的值变为 0,则在该信号量上等待的线程会被阻塞。signal 操作会增加信号量的值,并且唤醒至少一个在该信号量上等待的线程。

而条件变量是一种在多线程环境下用于线程间等待和通知的机制。它可以实现一些比较复杂的同步模式。条件变量包含一个等待队列和两个基本操作:wait 和 signal。wait 操作会使当前线程在条件变量的等待队列中等待,同时释放相关的锁。当另一个线程完成某些操作并发出 signal 信号时,被阻塞的线程会被唤醒,并重新尝试获取相关的锁。

最后,您提到的“双锁”机制,我不太理解它的具体含义。如果两个锁都需要获得才能执行代码,那么就相当于一个嵌套的互斥锁,这种情况下可能会导致死锁。因此,通常情况下只需要一个锁来保证互斥性。

综上所述,您回答的部分内容有误,建议在面试中注重对术语和概念的准确理解和表达,同时多思考实际问题中的具体场景和应用。

死锁

成因:

  • 多个锁

  • 锁的获取顺序不一样

  • 资源不释放

解决方法:

  • 尽量少用锁

  • 确保锁的顺序一致

  • 获取不了锁,一应该释放已有锁

(脑瘫瞎说)

哲学家问题,大家先哪左边锁,又拿右边锁

多态

设计模式中用的多

依赖倒置原则

高层模块不应该直接依赖底层模块,而应该依赖其抽象

这样高层模块不至于因为底层实现的更改而导致要跟着改变

c++内存管理

C++内存管理是指在C++程序中有效地分配和释放内存资源的过程。C++是一种直接支持内存管理的语言,它提供了各种机制来管理内存,包括手动管理和自动管理。下面是对C++内存管理的详细解释:

1. 手动内存管理:

C++允许开发人员手动分配和释放内存,这意味着程序员负责在需要时分配内存,并在使用完后手动释放它。手动管理内存的主要机制是通过`new`和`delete`运算符。

- new运算符:`new`运算符用于在堆上分配内存,并返回指向分配的内存的指针。语法如下:

```cpp

type *ptr = new type;

```

这将分配一个类型为`type`的对象,并将指针`ptr`指向该对象。

- delete运算符:`delete`运算符用于释放由`new`分配的内存。语法如下:

```cpp

delete ptr;

```

这将释放`ptr`指向的内存。

手动内存管理需要程序员显式地跟踪内存的分配和释放,确保在不再使用时及时释放内存,否则可能导致内存泄漏或悬空指针等问题。

2. 自动内存管理:

C++还提供了自动内存管理的机制,以减轻程序员手动管理内存的负担。自动内存管理主要通过两种方式实现:栈上分配和智能指针。

- 栈上分配:栈是一种自动管理内存的数据结构,它用于存储局部变量和函数调用的上下文信息。在C++中,局部变量的内存分配和释放是自动进行的。当变量超出其作用域时,其内存将自动释放。例如:

```cpp

void foo() {

int x = 10; // 变量x在栈上分配内存

// ...

} // 变量x超出作用域,内存自动释放

```

- 智能指针:智能指针是一种封装了指针的对象,它可以自动管理动态分配的内存。通过智能指针,内存的分配和释放可以自动进行,从而避免手动管理内存的错误和繁琐。C++标准库提供了两种智能指针:`std::unique_ptr`和`std::shared_ptr`。

- std::unique_ptr:`std::unique_ptr`是一种独占指针,它拥有对动态分配内存的唯一所有权。当`std::unique_ptr`超出作用域时,它自动释放所拥有的内存。示例:

```cpp

std::unique_ptr<int> ptr = std::make_unique<int>(10); // 分配一个int类型的对象

// ...

```

- std::shared_ptr:`std::shared_ptr`是一种共享指针,它允许多个智能指针共享对同一块内存的所有权。内部使用引用计数来跟踪共享的指针数量,并在没有指针引用时自动释放内存。示例:

```cpp

std::shared_ptr<int> ptr1 = std::make_shared<int>(10); // 分配一个int类型的对象

std::shared_ptr<int> ptr2 = ptr1; // 共享ptr1指向的内存

// ...

```

使用智能指针可以更安全地管理内存,避免内存泄漏和悬空指针问题。然而,仍然需要注意循环引用可能导致的内存泄漏问题。

除了手动和自动内存管理之外,C++还提供了一些其他的内存管理技术和概念,例如:

- 内存分配器(Memory Allocators):内存分配器是一种用于管理堆上内存分配和释放的机制。C++标准库提供了一些内存分配器,例如`std::allocator`和`std::allocator_traits`。开发人员也可以自定义内存分配器来满足特定的需求。

- RAII(Resource Acquisition Is Initialization):RAII是一种C++的编程范式,它利用对象的生命周期来管理资源(包括内存)。通过在对象的构造函数中获取资源,在析构函数中释放资源,可以确保资源在对象生命周期结束时被正确释放。智能指针就是基于RAII的思想实现的。

- 运算符重载:C++允许运算符重载,包括`new`和`delete`运算符。通过重载这些运算符,开发人员可以自定义内存分配和释放的行为,例如使用自定义的内存分配器或实现特定的内存管理策略。

总结起来,C++提供了多种内存管理的机制和技术,包括手动管理、自动管理(栈上分配和智能指针)、内存分配器、RAII和运算符重载。选择适当的内存管理方式取决于具体需求和情况,开发人员需要在性能、安全性和可维护性之间做出权衡。

全局变量和静态变量

全局变量和静态变量在C++中有一些重要的区别。下面是它们之间的主要区别:

1. 作用域:

- 全局变量:全局变量在整个程序中可见,可以在任何函数内部访问。

- 静态变量:静态变量的作用域限定在声明它的函数或文件内部,只能在所在的函数内部或文件内部访问。

2. 存储位置:

- 全局变量:全局变量存储在全局/静态区,它在程序启动时创建,在程序结束时销毁。

- 静态变量:静态变量也存储在全局/静态区,它在程序启动时创建,在程序结束时销毁。

3. 生命周期:

- 全局变量:全局变量的生命周期与整个程序的生命周期相同,即它们在程序启动时创建,在程序结束时销毁。

- 静态变量:静态变量的生命周期延长到整个程序的生命周期,即使在所在的函数内部,静态变量的值在函数调用结束后也会保留。

4. 默认初始化:

- 全局变量:全局变量在定义时会自动初始化为默认值,如0或空指针,除非显式指定其他初始值。

- 静态变量:静态变量在定义时会自动初始化为默认值,如0或空指针,除非显式指定其他初始值。

5. 访问权限:

- 全局变量:全局变量可以被程序中的任何函数访问和修改。

- 静态变量:静态变量可以被声明它的函数内部访问和修改,但对于其他函数是不可见的。

6. 编译单元:

- 全局变量:全局变量可以跨越多个编译单元(多个源文件)共享。

- 静态变量:静态变量只能在声明它的函数或文件内部共享。

需要注意的是,静态变量也可以在类中声明,这种情况下它们被称为静态成员变量,与普通的静态变量有一些区别。静态成员变量在类的所有实例之间共享,而不是每个实例都有自己的拷贝。

hr面

项目自己写的吗?

同上

获奖经历

自己的缺点

内向,怕生.....

什么时候意识到这一点?

学生会面试,演讲,说话不利索

实习面试

工作时遇到要和同事合作的任务怎么办?

第一次见面时尽量记住每个人的名字,大概认识一下

既然是与和同事合作,那就去与哪位同事先商量,分配一下任务。

(被打断)hr:"不不不,任务大多不是这么明确告诉你与具体的某某合作,你要自己判断"

我:?????(心理)

哦哦,感谢你提醒了我,在第一次见面时可能要先了解每个同事大概是做什么的,到真正需要与人合作时才不至于不知道找谁。

事后总结

应该再讲一下向别人请教时,虚心请教

反问:薪资、假期、上班时间

最上面

(可能加班,每年4月要上交)

WebRTC

一对多/多对多通信

如果需要实现一对多或多对多通信,按照上面代码的方式,那么在有其他客户端加入时就需要实时创建一个新的 peer,对其进行协商。这种方式产生的架构叫 Mesh。Mesh 中,每个客户端都是可以直接连接到其他端点的。

与 Mesh 对应的架构是 MCU,MCU 则是有一个中央服务器,每个端都连接到此服务器。中央服务器将接收每个端点的数据,因此可以对数据进行处理,如合并、调整等。

Mesh ???

WebRTC 简单入门与实践 - 掘金 (juejin.cn)

  1. 改linux内核

  2. 安卓镜像

  3. ia s

  4. 驱动

  5. 游戏驱动

  6. linux的应用

  7. libevent库


评论