C++面试之设计题
2022年C++面试中遇到的各类设计题,包括少量网上面经、同学遇到的题。如果有错误欢迎提出!
原发布在zhihu,看得人不多就转过来了
实现string类:字节
当时要我实现的有无参构造、赋值构造、析构和拷贝函数。有几个注意事项:
- new的长度要+1,因为strlen()不包括\0
- 因为VS会报错,所以代码中我用了strcpy_s(),在牛客、飞书的编译器上可以直接用strcpy()
- 释放时要加中括号[]!!当时漏了这一点,于是寄了
#include<iostream>
#include<string.h>
using namespace std;
class String {
private:
char* m_str;
public:
// 无参构造
String(const char* str = "") {
// +1是为了包含\0
int len = strlen(str) + 1;
m_str = new char[len];
strcpy_s(m_str, len, str);
}
// 拷贝构造
String(const String& s) {
int len = strlen(s.m_str) + 1;
m_str = new char[len];
strcpy_s(m_str, len, s.m_str);
}
// 析构
~String() {
if (m_str) {
delete[] m_str;
m_str = nullptr;
}
}
// 赋值
String& operator=(const String& s) {
if (*m_str != *s.m_str) {
if (m_str != nullptr) {
delete[] m_str;
m_str = nullptr;
}
int len = strlen(s.m_str) + 1;
m_str = new char[len];
strcpy_s(m_str, len, s.m_str);
}
return *this;
}
};
实现生产者和消费者模型:字节
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>
using namespace std;
int main() {
mutex mx;
condition_variable cv;
queue<int> q;
const int capicity = 5;
thread producer([&] {
for (int i = 0; i < 10; i++) {
unique_lock<mutex>lock(mx);
cv.wait(lock, [&] {return q.size() <= capicity; });
cout << "thread: " << this_thread::get_id() << "produce " << i << endl;
q.push(i);
cv.notify_all();
}
});
thread consumer([&] {
while (true) {
unique_lock<mutex> lock(mx);
cv.wait(lock, [&] {return !q.empty(); });
cout << "thread: " << this_thread::get_id() << "consume " << q.front() << endl;
q.pop();
cv.notify_all();
}
});
producer.join();
consumer.join();
return 0;
}
3个线程轮流打印1、2、3:字节
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
using namespace std;
int main() {
mutex mx;
condition_variable cv;
int flag = 1;
thread t1([&] {
for (int i = 0; i < 10; i++) {
unique_lock<mutex>lock(mx);
cv.wait(lock, [&] {return flag==1; });
cout << "loop " << i << " print 1" << endl;
flag = 2;
cv.notify_all();
}
});
thread t2([&] {
for (int i = 0; i < 10; i++) {
unique_lock<mutex>lock(mx);
cv.wait(lock, [&] {return flag == 2; });
cout << "loop " << i << " print 2" << endl;
flag = 3;
cv.notify_all();
}
});
thread t3([&] {
for (int i = 0; i < 10; i++) {
unique_lock<mutex>lock(mx);
cv.wait(lock, [&] {return flag == 3; });
cout << "loop " << i << " print 3" << endl;
flag = 1;
cv.notify_all();
}
});
t1.join();
t2.join();
t3.join();
return 0;
}
实现智能指针:字节
同学说有考到,一般应该不会问这么难
#include<iostream>
using namespace std;
template <typename T>
class SharedPtr {
private:
int* m_count;
T* m_ptr;
public:
SharedPtr() : m_count(new int{ 0 }), m_ptr(new T) {}
SharedPtr(T* ptr) : m_count(new int), m_ptr(ptr) {
// 判空
if (ptr) {
*m_count = 1;
}
else {
*m_count = 0;
}
}
~SharedPtr() {
// 为空或者引用计数为1
if (!m_ptr || *m_count == 1) {
delete m_count;
delete m_ptr;
m_count = nullptr;
m_ptr = nullptr;
}
else {
--(*m_count);
}
}
SharedPtr(const SharedPtr& rhs) {
m_count = rhs.m_count;
m_ptr = rhs.m_ptr;
*m_count++;
}
SharedPtr& operator=(const SharedPtr& rhs) {
if (this != &rhs) {
if (m_ptr) {
--(*m_count);
if (*m_count == 0) {
delete m_count;
delete m_ptr;
}
m_count = rhs.m_count;
m_ptr = rhs.m_ptr;
++(*m_count);
}
}
return *this;
}
SharedPtr(SharedPtr&& rhs) : m_count(rhs.m_count), m_ptr(rhs.m_ptr) {
++(*m_count); // 移动后ptr销毁,count会减一,这里重新加一
}
int use_count() { return *m_count; }
};
大小端转换:intel
大端:高位字节保存在地址
小端:高位字节保存在地址
大端转小端即0x12345678转为0x78563412
小端:
高地址---------低地址
12 | 34 | 56 | 78
大端:
高地址---------低地址
78 | 56 | 34 | 12
要求的是转int
#include<iostream>
using namespace std;
int convert(int src) {
// 0x12345678转为0x78563412
return (src & 0x000000FF) << 24
| ((src & 0x0000FF00) << 8)
| ((src & 0x00FF0000) >> 8)
| ((src & 0xFF000000) >> 24);
}
int main() {
// 校验
int a = 0x12345678;
cout << hex << a << endl;
int b = convert(a);
cout << hex << b << endl;
return 0;
}
如何判断大小端:某嵌入式公司
int main()
{
int a = 0x12345678;
char *b = (char *)&a;
if(b[0] == 0x12)
cout << "big";
else
cout << "small";
return 0;
}
// 或者
int main()
{
union test
{
int a = 1;
char b;
}t;
if (t.b == 1)
cout << "small" << endl;
else
cout << "big" <<endl;
}
实现strcpy:h3c
char* my_strcpy(char* src, const char* tgt) {
// 没有考虑长度覆盖的问题
char* ret = src;
// 优化点:判断src和tgt是否为空
while (*tgt != '\0') {
*(ret++) = *(tgt++);
}
*ret = '\0';
return src;
}
实现单例:某团
懒汉模式。
修改:删除volatile,减少面试争议
#include<iostream>
#include<mutex>
using namespace std;
class Singleton {
private:
static Singleton* m_ptr;
static mutex m_mx;
Singleton() {} // 构造函数私有化,防止外部创建实例
public:
static Singleton* get() { // 双判断
if (m_ptr == nullptr) {
lock_guard<mutex> lock(m_mx);
if (m_ptr == nullptr) {
m_ptr = new singleton;
}
}
return m_ptr;
}
};
手写死锁:某团
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
int main() {
mutex mx1;
mutex mx2;
thread t1([&] {
mx1.lock();
cout << "t1 lock A" << endl;
this_thread::sleep_for(chrono::seconds(1));
mx2.lock();
cout << "t1 lock B" << endl;
mx1.unlock();
mx2.unlock();
});
thread t2([&] {
mx2.lock();
cout << "t2 lock B" << endl;
this_thread::sleep_for(chrono::seconds(1));
mx1.lock();
cout << "t2 lock A" << endl;
mx2.unlock();
mx1.unlock();
});
t1.join();
t2.join();
return 0;
}
ip地址从string转为int:小红书
不确定是否还有其他问题,当时写的有很多漏洞,改的麻了
int str2int(const string& ip) {
// 需要考虑各种异常
// 1.ip为空,返回0
// 2.ip的'.'不正常(数量不为3,第一个字符为'.')
// 3.ip的数值不在0-255之间
// 4.包含了数字以外的字符
if (ip == "" or ip[0] == '.') {
return -1; //或者抛异常
}
int ipInt = 0;
int tmp = 0;
int dot = 0;
for (int i = 0; i < ip.size(); i++) {
if (ip[i] == '.' && dot < 3 && ip[i - 1] != '.') {
dot++;
if (tmp > 255) {
return -1;
}
ipInt += tmp;
ipInt <<= 8;
tmp = 0;
}
else if (ip[i] <= '9' && ip[i] >= '0') {
tmp *= 10;
tmp += ip[i] - '0';
if (tmp > 255) {
return -1;
}
}
else {
return -1;
}
}
if (tmp > 255) {
return -1;
}
ipInt += tmp;
return ipInt;
}
#C++##秋招##实习##面试#
SHEIN希音公司福利 222人发布