面试题1:赋值运算符函数
/*
* 面试题一:赋值运算符函数
* 题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数
class CMyString
{
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
private:
char* m_pData;
};
* 注意点:
* 1、是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身的引用(*this)。
* 只有返回一个引用,才可以允许连续赋值。否则,如果函数的返回值是void,
* 则应用该赋值运算符将不能进行连续赋值。假设有3个CMyString的对象:str1、str2和str3,在程序中
* 用语句str1=str2=str3将不能通过编译。
* 2、是否把传入的参数的类型声明为常量引用。如果传入的参数不是引用而是实例,那么从形参到实参会
* 调用一次复制构造函数。把参数声明为引用可以避免这样的无谓消耗,能提高代码的效率。同时,我们在
* 赋值运算符函数内不会改变传入的实例的状态,因此应该为传入的引用参数加上const关键字。
* 3、是否释放实例自身已有的内存。如果我们忘记在分配新内存之前释放自身已有的空间,则程序将出现内存泄漏。
* 4、判断传入的参数和当前的实例(*this)是不是同一个实例。如果是同一个,则不进行赋值操作,直接返回。
* 如果事先不判断就进行赋值,那么在释放实例自身内存的时候就会导致严重的问题:当*this和传入的参数是同一个实例时
* 一旦释放了自身的内存,传入的参数的内存也同时被释放了,因此再也找不到需要赋值的内容了。
*/
/*
经典的解法,适用于初级程序员
*/
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string.h>
#pragma warning(disable:4996)
class CMyString
{
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator=(const CMyString& str);
void Print();
private:
char* m_pData;
};
CMyString::CMyString(char* pData)
{
if (pData == nullptr) {
m_pData = new char[1];
m_pData[0] = '\0';
}
else {
int length = strlen(pData);
m_pData = new char[length + 1];
strcpy(m_pData, pData);
}
}
CMyString::CMyString(const CMyString& str)
{
int length = strlen(str.m_pData);
m_pData = new char[length + 1];
strcpy(m_pData, str.m_pData);
}
CMyString::~CMyString()
{
delete[] m_pData;
}
CMyString& CMyString::operator=(const CMyString &str)
{
if (this == &str) // 判断传入的参数和当前的实例(*this)是不是同一个实例
return *this;
delete[] m_pData; // 分配新内存之前释放自身已有的空间
m_pData = nullptr;
m_pData = new char[strlen(str.m_pData) + 1];
strcpy(m_pData, str.m_pData);
return *this;
}
// ===================测试代码======================
void CMyString::Print()
{
std::cout << m_pData << std::endl;
}
void Test1()
{
/*
测试用例
* 把一个CMyString的实例赋值给另外一个实例
*/
std::cout << "Test begins:" << std::endl;
char* text = "Hello world";
CMyString str1(text);
CMyString str2 = str1;
std::cout << "The expected result is:"<< text << "\n";
std::cout << "The actual result is: " ;
str2.Print();
}
void Test2()
{
// 赋值给自己
std::cout << "赋值给自己" << "\n";
char* text = "Hello world";
CMyString str1(text);
str1 = str1;
std::cout << "The expected result is:" << text << "\n";
std::cout << "The actual result is: ";
str1.Print();
}
void Test3()
{
// 连续赋值
std::cout << "Test3 begins:" << "\n";
char* text = "Hello World";
CMyString str1(text);
CMyString str2, str3;
str3 = str2 = str1;
std::cout << "The expected result is:" << text << "\n";
std::cout << "The actual result is: ";
str2.Print();
std::cout << std::endl;
std::cout << "The expected result is:" << text << "\n";
std::cout << "The actual result is: ";
str3.Print();
std::cout << std::endl;
}
int main()
{
Test1();
Test2();
Test3();
system("pause");
}
面试题2:实现Singleton模式
/** 面试题2:实现Singleton模式
* 单例模式,即一个类只有一个实例对象。C++一般的方法是将构造函数、拷贝构造函数
* 以及赋值操作符函数声明为private级别,从而阻止用户实例化一个类。那么,如何才能获得
* 该类的对象呢?这时,需要类提供一个public&static的方法,通过该方法获得这个类为一个的一个
* 实例化对象。这就是单例模式基本的一个思想。
* 单线程环境:
* 1、饿汉式:即类产生的时候就创建好实例对象,这是一种空间换时间的方式
* 2、懒汉式:即在需要的时候,才创建对象,这是一种时间换空间的方式
*/
#include<stdio.h>
#include"CSingleton.h"
#include<iostream>
#include<thread>
#include<mutex>
#include<Windows.h>
#include<process.h>
using namespace std;
/**
* 饿汉式的单例实现
*/
class Singleton
{
private:
Singleton() {
m_count++;
cout << "Singleton begin:" << endl;
Sleep(1000);
cout << "Singleton end!" << endl;
}
static Singleton* single;
public:
static Singleton *GetSingleton();
static void print();
static int m_count;
};
// 饿汉模式的关键:初始化即实例化
Singleton *Singleton::single = new Singleton;
int Singleton::m_count = 0;
Singleton* Singleton::GetSingleton() {
// 不再需要进行实例化
return single;
}
void Singleton::print() {
cout << m_count << endl;
}
// 回调函数
void threadFunc(void *p) {
DWORD id = GetCurrentThreadId(); //获得线程id
cout << id << endl;
Singleton::GetSingleton()->print(); // 构造函数并获得实例,调用静态成员函数
}
int main()
{
int threadNum = 3;
HANDLE threadHdl[100];
// 创建3个线程
for (int i = 0; i < threadNum; i++) {
threadHdl[i] = (HANDLE)_beginthread(threadFunc, 0, nullptr);
}
// 让主线程等待所有的线程结束后再退出
for (int i = 0; i < threadNum; i++) {
WaitForSingleObject(threadHdl[i], INFINITE);
}
cout << "main" << endl; // 验证主进程是否是最后退出
system("pause");
}
// 饿汉模式
class Singleton
{
private:
Singleton() {
cout << "Singleton()" << endl;
}
static Singleton* instance;
public:
static Singleton* GetSingleton() {
return instance;
}
static Singleton* Destory() {
delete instance;
instance = NULL;
}
};
Singleton* Singleton::instance = new Singleton();
int main()
{
Singleton* sl1 = Singleton::GetSingleton();
Singleton* sl2 = Singleton::GetSingleton();
Singleton* sl3 = Singleton::GetSingleton();
cout << sl1 << endl;
cout << sl2 << endl;
cout << sl3 << endl;
system("pause");
}
// 懒汉模式
class Singleton
{
private:
Singleton() {
cout << "Singleton()" << endl;
}
static Singleton* instance;
public:
static Singleton* GetSingleton()
{
if (NULL == instance) {
instance = new Singleton();
cout << "对象创建成功" << endl;
}
else {
cout << "对象已经创建成功,无须再创建!" << endl;
}
return instance;
}
static Singleton* Destory() {
delete instance;
instance = NULL;
}
};
Singleton* Singleton::instance = NULL;
int main()
{
Singleton* sl1 = Singleton::GetSingleton();
Singleton* sl2 = Singleton::GetSingleton();
Singleton* sl3 = Singleton::GetSingleton();
cout << sl1 << endl;
cout << sl2 << endl;
cout << sl3 << endl;
system("pause");
}
面试题3:数组中的重复的数字
// 面试题3:数组中重复的数字
/** 数组中重复的数字
* 题目一:找出数组中重复的数字
* 在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,
* 但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
* 例如,如果输入长度为7的数组{2, 3, 1, 0, 2, 5, 3},那么对应的输出是重复的数字2或者3
*/
#include<stdio.h>
#include<iostream>
using namespace std;
bool duplicate(int numbers[], int length, int* duplication)
{
if (numbers == nullptr || length <= 0) {
return false;
}
for (int i = 0; i < length; i++) {
if (numbers[i] < 0 || numbers[i] > length) {
return false;
}
}
for (int i = 0; i < length; ++i) {
while (numbers[i] != i)
{
if (numbers[i] == numbers[numbers[i]]) {
*duplication = numbers[i];
return true;
}
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
return false;
}
// =================测试代码======================
bool contains(int array[], int length, int number)
{
for (int i = 0; i < length; ++i) {
if (array[i] = number) {
return true;
}
}
return false;
}
void test(char* testName, int numbers[], int lengthNumbers, int expected[], int expectedExpected, bool validArgument)
{
cout << testName << "begins" << endl;
int duplication;
bool validInput = duplicate(numbers, lengthNumbers, &duplication);
if (validArgument == validInput) {
if (validArgument) {
if (contains(expected, expectedExpected, duplication))
cout << "Passed" << endl;
else
cout << "Failed" << endl;
}
else
{
cout << "Passed" << endl;
}
}
else {
cout << "Failed " << endl;
}
}
// 重复的数字是数组中最小的数字
void test1()
{
int numbers[] = { 2, 1, 3, 1, 4 };
int duplications[] = { 1 };
test("test", numbers, sizeof(numbers) / sizeof(int), duplications, sizeof(duplications), true);
}
int main()
{
test1();
system("pause");
}
面试题4:二维数组中的查找
/** 面试题4:二维数组中的查找
* 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,
* 每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个
* 二维数组和一个整数,判断数组中是否含有该整数。
*/
#include<iostream>
#include<stdio.h>
using namespace std;
bool Find(int* matrix, int rows, int columns, int number)
{
bool found = false;
if (matrix != nullptr && rows > 0 && columns > 0)
{
int row = 0;
int column = columns - 1;
while (row < rows && column >= 0)
{
if (matrix[row * columns + column] == number)
{
found = true;
break;
}
else if (matrix[row * columns + column] > number)
{
--column;
}
else
{
++row;
}
}
}
return found;
}
// ================ 测试代码==================
void Test(char* testName, int* matrix, int rows, int columns, int number, bool expected)
{
if (testName != nullptr)
cout << testName << "begins" << endl;
bool result = Find(matrix, rows, columns, number);
if (result == expected)
cout << "Passed" << endl;
else
{
cout << "Failed" << endl;
}
}
// 1 2 8 9
// 2 4 9 12
// 4 7 10 13
// 6 8 11 15
// 要查找的数在数组中
void Test1()
{
int matrix[][4] = { {1, 2, 8, 9}, {2, 4, 9, 12}, {4, 7, 10, 13}, {6, 8, 11, 15} };
Test("Test1", (int*)matrix, 4, 4, 7, true);
}
int main()
{
Test1();
system("pause");
}
面试题5:替换空格
/** 面试题5:替换空格
* 题目:请实现一个函数,把字符串中的每个空格替换成"%20"。
* 例如,输入"We are happy.",则输出"We%20are%20happy."。
*/
#include<stdio.h>
#include<iostream>
#include<string>
using namespace std;
/* length为字符数组str的总容量,大于或等于字符串str的实际长度 */
void ReplaceBlank(char str[], int length)
{
if (str == nullptr && length <= 0)
return;
/* originalLength为字符串的str的实际长度 */
int originalLength = 0;
int numberOfBlank = 0;
int i = 0;
while (str[i] != '\0')
{
++originalLength;
if (str[i] == ' ')
++numberOfBlank;
++i;
}
/* newLength为把空格替换成'%20'之后的长度 */
int newLength = originalLength + numberOfBlank * 2;
if (newLength > length)
return;
int indexOfOriginal = originalLength;
int indexOfNew = newLength;
while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal)
{
if (str[indexOfOriginal] == ' ')
{
str[indexOfNew--] = '0';
str[indexOfNew--] = '2';
str[indexOfNew--] = '%';
}
else
{
str[indexOfNew--] = str[indexOfOriginal];
}
--indexOfOriginal;
}
}
// 空格在句子中间
void Test1()
{
const int length = 100;
char str[length] = "hello world";
ReplaceBlank(str, 100);
cout << str << endl;
system("pause");
}
int main()
{
Test1();
}