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++##秋招##实习##面试#