C++面试之设计题

2022年C++面试中遇到的各类设计题,包括少量网上面经、同学遇到的题。如果有错误欢迎提出!

原发布在zhihu,看得人不多就转过来了


实现string类:字节

当时要我实现的有无参构造、赋值构造、析构和拷贝函数。有几个注意事项:

  1. new的长度要+1,因为strlen()不包括\0
  2. 因为VS会报错,所以代码中我用了strcpy_s(),在牛客、飞书的编译器上可以直接用strcpy()
  3. 释放时要加中括号[]!!当时漏了这一点,于是寄了
#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++##秋招##实习##面试#
全部评论
完了,要是面试搞这个,我死翘翘,研究生用的全是Py,本科学C++比较多才选的C++赛道,现在操作符重载都写不出来
点赞 回复 分享
发布于 2023-04-23 13:20 湖北
c++的volatile和java的完全不一样
点赞 回复 分享
发布于 2023-04-21 21:21 上海

相关推荐

群星之怒:1.照片可以换更好一点的,可以适量P图,带一些发型,遮住额头,最好穿的正式一点,可以适当P图。2.内容太少。建议添加的:求职意向(随着投递岗位动态更改);项目经历(内容太少了建议添加一些说明,技术栈:用到了什么技术,还有你是怎么实现的,比如如何确保数据传输稳定的,角色注册用到了什么技术等等。)项目经历是大头,没有实习是硬伤,如果项目经理不突出的话基本很难过简历筛。3.有些内容不必要,比如自我评价,校内实践。如果实践和工作无关千万别写,不如多丰富丰富项目。4.排版建议:建议排版是先基础信息,然后教育背景(要突出和工作相关的课程),然后专业技能(一定要简短,不要长篇大论,写你会什么,会的程度就可以),然后是项目经历(一定要详细,占整个简历一定要超过一半,甚至超过百分之70都可以)。最后如果有一部分空白的话可以填补上校内获得的专业相关的奖项,没有就写点校园经历和自我评价。5.技术一定要够硬,禁得住拷打。还有作息尽量保证正常,不要太焦虑。我24双非本科还是非科班,秋招春招各找了一段实习结果都没有转正,当时都想噶了,最后6月份在校的尾巴也找到一份工作干到现在,找工作有时很看运气的不要急着自我否定。 加油
点赞 评论 收藏
分享
评论
13
73
分享

创作者周榜

更多
牛客网
牛客企业服务