C++程序员笔试训练

面试题1:使用库函数将数字转换位字符串

  • 考点:c语言库函数中数字转换位字符串的使用

在这里插入图片描述

char *gcvt(double number, int ndigit, char *buf);

参数说明:

number:待转换的double类型数值。
ndigit:保留的小数位数。
buf:用于存储转换后的字符串的缓冲区。

  • 示例代码如下
void func()
{
	int numInt = 1333;
	double numDouble = 123.12;

	char strInt[20];
	char strDouble[20];
	char buffer[20];

	_itoa(numInt, strInt, 10);
	_gcvt(numDouble, 5, strDouble);

	sprintf(buffer, "%d", numInt);

	cout << strInt << endl;
	cout << strDouble << endl;
	cout << buffer << endl;

}

面试题2:不使用库函数将整数转换为字符串

  • 考点:对数字转换为字符串,相关ASCII码的理解

解题思路:将整数的每一位上加上’0’转换成char类型并存到字符数组中

void func()
{
	int number = 12333;

	char str[20];
	int count = 0;
	while (number)
	{
		int num = number % 10;
		str[count++] = num + '0';
		number = number / 10;
	}
	//对顺序进行调整
	char newstr[20];
	for (int i = 0; i < count; i++)
	{
		newstr[i] = str[count - 1 - i];
	}
	newstr[count] = '\0';
	cout << newstr << endl;

}

面试题3:编程实现strcpy函数

  • 考点:字符串复制的实现
    在这里插入图片描述
  • 示例代码如下
char* My_strcpy(char* strDest, const char* strSrc)
{
	
	int strSrc_len=strlen(strSrc);
	
	for (int i = 0; i < strSrc_len; i++)
	{
		strDest[i] = strSrc[i];
	}
	strDest[strSrc_len] = '\0';
	return strDest;
}

int getStrLen(const char* strSrc)
{
	int len = 0;
	while (*strSrc++ != '\0')
	{
		len++;
	}
	return len;
}

int main()
{
	char strSrc[] = "abcdefg";
	char strDest[20];
	int len = 0;
	len=getStrLen( My_strcpy(strDest, strSrc));
	cout << strDest << endl;
	cout << "len=" << len << endl;


	system("pause");
	return 0;
}

在这里插入图片描述

面试题4:编程实现memcpy函数

  • 内存复制的实现
void *memcpy(void *dest, const void *src, size_t n);

其中,dest是目标地址,src是源地址,n是要复制的字节数。

memcpy函数可以用来复制任意长度的内存数据,但注意对于复杂数据类型(如结构体、类等),要确保其成员的内存布局是连续的,否则可能会导致数据被破坏。

  • 示例代码如下
void* memcpy2(void *dest,const void *src,size_t size)
{
	assert((dest != NULL) && (src != NULL));

	//强制转换
	char* newDest = (char*)dest;
	char* newSrc = (char*)src;
	
	while (size-- > 0)
	{
		*newDest++ = *newSrc++;
	}

	return newDest;
}


int main()
{

	char src[] = "asdfghjk";
	char dest[20];
	int len=strlen(src);
	memcpy2(dest, src, len);
	dest[len] = '\0';
	cout << dest << endl;

	system("pause");
	return 0;
}

面试题5:strcpy与memcpy的区别

  • strcpy和memcpy都是用来复制内存区域的函数,但是二者之间有几个关键的区别:
  1. strcpy用于复制字符串,其原型为char* strcpy(char* dest, const char* src)。它会从源字符串的地址开始复制字符,直到遇到空字符\0为止。因此,strcpy只能用来复制字符串,并且不需要指定复制的长度。

  2. memcpy用于复制任意类型的内存数据,其原型为void* memcpy(void* dest, const void* src, size_t n)。它需要传入要复制的数据的起始地址和长度,可以复制任意类型的数据,包括字符串。因此,memcpy是更通用的函数,可以处理任意类型的数据。

  3. strcpy会在目标字符串的末尾添加\0结束符,而memcpy则不会。因此,在使用memcpy复制字符串时,需要手动添加结束符。

  • 总的来说,strcpy主要用于复制字符串,而memcpy用于复制任意类型的内存数据。在复制字符串时,可以使用strcpy来保证字符串的正确复制及添加结束符。

面试题6:编程实现字符串的长度

  • 考点:strcpy库函数的实现细节

解题思路:以字符串的结束符’\0’作为标志,做一次遍历即可

int strlen1(const char*str)
{
	assert(NULL != str);
	int len = 0;
	while (*str++ != '\0')
	{
		len++;
	}
	return len;


}

int strlen2(const char* str)
{
	assert(str != NULL);
	const char* temp = str;
	while (*str++ != '\0');
	return str - temp - 1;
}

int main()
{
	char str[] = "asdfghjkl";
	//const char* str = NULL;
	cout << "len1=" << strlen1(str) << endl;
	cout << "len2=" << strlen2(str) << endl;
	system("pause");
	return 0;
}

在这个函数中,temp是一个指向字符串开头的常量字符指针,而str是一个指向字符串结尾的字符指针(指向空字符’\0’的位置)。

当str逐个递增直到遇到空字符’\0’时,str指针的位置就指向了字符串的结尾。然后,通过计算str - temp可以得到字符串的长度,但是由于字符串的长度不包括空字符’\0’本身,所以需要减去1才能得到正确的长度。
因此,str - temp - 1的结果是字符串的实际长度,去除了末尾的空字符’\0’。

  • 重点:strlen2的效率是高于strlen1的,strlen1每次循环自增两次,而strlen2每次循环自增一次。

面试题7:编程实现字符串中子串的查找

  • 考点:strstr库函数的实现细节

请写一个函数,实现strstr,即从一个字符串中,查找另一个字符串的位置,如strstr(“12345”,“34”)返回值是2号位置找到字符串34

char *strstr(const char *haystack,const char *needle);
strstr()会从字符串 haystack 中搜寻字符串 needle,并将第一次出现的地址返回。

  • 解题思路:暴力解,直接从首字母开始遍历
char* my_strstr(const char* haystack, const char* needle)
{
	
	while (*haystack!='\0')
	{
		 char* stack = (char*) haystack;
		 char* need  = (char*) needle;
		while (*stack++ == *need++)
		{
			if (*need!='\0')
			{
				return (char*)haystack;
			}
		}
		haystack++;
	}

	return (char*)haystack;
}

int main()
{
	char str1[] = "12345";
	char str2[] = "34";
	cout << "dest=" << my_strstr(str1, str2);
	system("pause");
	return 0;
}

面试题8:设置或清除特定的位

  • 考点:使用位操作符&和|
    嵌入式系统总是要求用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a的bit 3.再以上的两个操作中,要保持其他位不变。
#define BIT3 (ox1<<3)
static int a;

void set_bit3(void)
{
		a|=BIT3;
}

void clear_bit3(void)
{
		a &= ~BIT3;
}

面试题9:列举并解释c++中的4种运算符转化以及它们的不同点

  • 考点:位运算的灵活使用
  1. const_cast操作符:为程序设计师再特殊的情况下将限制为const成员函数的const定义解除,使其能更改特定属性。
  2. dynamic_cast操作符:可以将一个基类指针指向不同的子类型(派生类),然后将被转型为基础类的对象还原成原来的类。不过,限定于对象指针的类型转换,而非对象变量。
  3. rintrpret cast 操作符:将一个指针转换成其他类型的指针,新类型的指针与旧指针可以毫不相关。通常用于某些非标准的指针数据类型转换,例如将void* 转换为 char* 。它也可以用在指针和整型数之间的类型转换上。注意:它存在潜在的危险,除非有使用它的充分理由,否则就不要使用它。例如,它能够将一个 int* 类型的指针转换为 float* 类型的指针,但是这样就会很容易造成整数数据不能被正确地读取。
  4. static. cast操作符:它能在相关的对象和指针类型之间进行类型转换。有关的类之间必须通过继承、构造函数或者转换函数发生联系。static_cast 操作符还能在数字(原始的)类型之间进行类型转换。通常情况下,statie_cast 操作符大多用于将数域宽度较大的类型转换为较小的类型。当转换的类型是原始数据类型时,这种操作可以有效地禁止编译器发出

面试题10:编写类String的构造函数,析构函数和赋值函数

  • 考点:构造函数,析构函数和赋值函数的编写方法
    已知类String的原型为:
class String
{
public:
	String(const char* str = NULL);//普通构造函数

	String(const String& other);//拷贝构造函数

	~String();//析构函数

	String& operator =(const String& other);//赋值函数

private:
	char* m_String;
};

//实现如下-----------------------------------------------------

String::String(const char* str)
{
	if (str == NULL)
	{
		m_String = new char[1];
		*m_String = '\0';
	}
	else
	{
		m_String = new char[strlen(str) + 1];
		strcpy(m_String, str);
	}
}


String::String(const String& other)
{
	m_String = new char[strlen(other.m_String) + 1];
	strcpy(m_String, other.m_String);
	
}


String& String::operator =(const String& other)
{
	if (this == &other)
	{
		return *this;
	}
	delete[] m_String;
	m_String = new char[strlen(other.m_String) + 1];
	strcpy(m_String, other.m_String);

	return *this;
}


String::~String()
{
	if (m_String == NULL)
	{
		return;
	}

	delete[] m_String;
}

面试题11:编程题–各类运算符重载函数的编写(很经典)

  • 考点:编写各类运算符重载函数
  • 用c++实现一个String类,它具有比较、连接、输入、输出等功能。并且请提供一些测试用例说明如何使用这个类。不能用MFC、STL以及其他库。
  1. 类实现
#pragma once
#include<iostream>
using namespace std;

#pragma warning(disable: 4996) // 禁用警告 4996(与 strcpy 相关的警告

class MyString
{
public:
	MyString();//默认构造函数

	MyString(int n, char c);

	MyString(const char* source);

	MyString(const MyString& s);//拷贝构造函数

	MyString& operator = (char* s);//重载=,实现字符串赋值

	MyString& operator = (const MyString& s);//重载=,实现对象赋值

	~MyString();//析构函数

	char& operator[](int i);//重载[],实现数组运算

	void Print();//打印结果

	const char& operator[] (int i)const;//重载[],实现数组运算(对象为常量)

	MyString& operator +=(const MyString& s);//重载+=,实现字符串相加

	MyString& operator+=(const char* s);//+=重载,连接s字符串

	friend ostream& operator <<(ostream& out, MyString& s);//重载<<,实现输出流

	friend istream& operator >>(istream& in, MyString& s);//重载>>,实现输入流

	friend bool operator < (const MyString& left, const MyString& right);//重载 <


private:
	int size;//字符串长度

	char* data;//字符串

};
  1. 函数实现
#include "MyString.h"

MyString::MyString()
{
    //空字符串只含有'\0'一个元素
    data = new char[1];
    *data = '\0';
    size = 0;

}

MyString::MyString(int n, char c)
{
    //含有n个相同字符的字符串
    data = new char[n + 1];
    this->size = n;
    char* temp = data;
    while (n--)
    {
        *temp = c;
        temp++;
    }
    *temp = '\0';

}

MyString::MyString(const char* source)
{
    
    //对data进行赋值操作
    int len = strlen(source);
    data = new char[len + 1];

    //使用库函数写法,多一位是来存储结束符的
    //strcpy_s(data, len + 1, source);

    if (source == NULL)
    {
        //空字符串只含有'\0'一个元素
        data = new char[1];
        *data = '\0';
        size = 0;
        return;
    }

    //不适用库函数
    for (int i = 0; i < len; i++)
    {
        data[i] = source[i];
    }
    data[len] = '\0';

    this->size = len;



}

MyString::MyString(const MyString& s)
{
    //对传入实体进行拷贝
    this->size = s.size;
    this->data = new char[s.size+1];

    strcpy_s(this->data, s.size + 1, s.data);

}

MyString& MyString::operator=(char* s)
{
    if (data != NULL)
    {
        delete[]this->data;
        this->data = NULL;
    }

    //对=进行重载,起到拷贝的作用
    int len = strlen(s);
    this->size = len;
    this->data = new char[len + 1];
    strcpy_s(this->data, len + 1, s);
 
    return *this;
}

MyString& MyString::operator=(const MyString& s)
{
    //重载等号

    if (this == &s)
    {
        return *this;
    }
    this->size = s.size;
    this->data = new char[s.size + 1];
    strcpy_s(this->data, s.size + 1, s.data);
    
    return *this;
}

MyString::~MyString()
{
    //析构函数
    if (this->data != NULL)
    {
        delete[] this->data;
        data = NULL;
    }


}

char& MyString::operator[](int i)
{
    //判断合法性
    if (i < 0 || i >= this->size)
    {
        return data[0];
    }

    return data[i];
}

void MyString::Print()
{
    cout << "data:" << data << endl;
    cout << "data.size=" << size << endl;

}

const char& MyString::operator[](int i) const
{
    //重载[],实现数组运算(对象为常量)
    //判断合法性
    if (i < 0 || i >= this->size)
    {
        return data[0];
    }
    return this->data[i];

}

MyString& MyString::operator+=(const MyString& s)
{
    // 重新计算需要的字符串缓冲区大小
    int len = this->size + s.size + 1;

    // 保存原始数据
    char* temp = this->data;

    // 分配新的字符串缓冲区
    this->data = new char[len];

    // 使用 strcpy_s 复制原始数据到新缓冲区中
    strcpy_s(this->data, len, temp);

    // 使用 strcat_s 在结束符前追加 s.data,保证不会重复追加结束符
    strcat_s(this->data, len, s.data);

    // 释放原始数据的内存
    delete[] temp;

    // 更新大小
    this->size += s.size;

    return *this;
}

MyString& MyString::operator+=(const char* s)
{
    char* temp = this->data;
    int len_s = strlen(s);

    int len = this->size + len_s + 1;
    this->data = new char[len];

    strcpy_s(this->data, len, temp);
    strcat_s(this->data, len, s);

    this->size += len_s;
    

    return *this;
}

ostream& operator<<(ostream& out, MyString& s)
{
    //重载 << 打印对象s内字符串成员的所有字符

    for (int i = 0; i < s.size; i++)
    {
        out << s[i] << " ";
    }
    return out;
}

istream& operator>>(istream& in, MyString& s)
{
    char p[50];
    in.getline(p, 50);//从输入流中接收最多50个字符

    s = p;//调用赋值函数

    return in;

}

bool operator<(const MyString& left, const MyString& right)
{
    //重载 < 实现
    int i = 0;

    while (left[i] == right[i] && left[i] != 0 && right[i] != 0)
    {
        i++;
    }
    return left[i] - right[i] < 0 ? true : false;
}

  1. 函数测试
#include<iostream>
#include"MyString.h"
using namespace std;

void test()
{
	MyString p1(5, 'c');
	p1.Print();
	cout << "--------------------------------------" << endl;

	MyString p2("this is myself define!!!");
	p2.Print();
	cout << "--------------------------------------" << endl;

	MyString p3(p2);
	p3.Print();
	cout << "--------------------------------------" << endl;

	MyString p4 = "重载等号进行赋值";
	p4.Print();
	cout << "--------------------------------------" << endl;

	MyString p5 = p1;
	p5.Print();
	cout << "--------------------------------------" << endl;

	cout << p2[2] << endl;
	cout << "--------------------------------------" << endl;

	p4 += p2;
	p4.Print();
	cout << "--------------------------------------" << endl;

	p2 += "this is new!!!";
	p2.Print();
	cout << "--------------------------------------" << endl;

	cout << p2 << endl;
	cout << "--------------------------------------" << endl;

	MyString p6;
	cin >> p6;
	cout << p6 << endl;
	cout << "--------------------------------------" << endl;

	MyString p7 = "1234";
	MyString p8 = "1224";
	if (p7 < p8)
	{
		cout << "p7<p8" << endl;
	}
	else
	{
		cout << "p7>p8" << endl;
	}
	cout << "--------------------------------------" << endl;

}
int main()
{
	test();


	system("pause");
	return 0;
}

面试题12:私有继承有什么作用

  • 考点:对c++类私有继承的理解
#include<iostream>
using namespace std;

class Person
{
public:
	void eat()
	{
		cout << "Person eat" << endl;
	}
};


class student :private Person //私有继承
{
public:
	void study()
	{
		cout << "student study" << endl;
	}
};

int main()
{
	Person p;
	student s;

	p.eat();
	s.study();
	s.eat();//编译错误,私有继承后父类的public和protected函数都变成子类私有函数
	p = s;//编译错误

	return 0;
}

面试题13:私有继承和组合有什么相同点和不同点

  • 考点:私有继承和组合的理解
#include<iostream>
using namespace std;

class Engine
{
public:
	Engine(int num) :numCylinders(num)
	{

	}

	void start()
	{
		cout << "Engline start," << numCylinders << " Cylinders" << endl;
	}


private:
	int numCylinders;
};

class Car_pri:private Engine//私有继承
{
public:
	Car_pri():Engine(8)//调用基类的构造函数
	{

	}
	void start()
	{
		Engine::start();//调用基类的start
	}

};

class Car_comp
{
private:
	Engine engline; //组合Engline类对象

public:
	Car_comp() :engline(9)//给engline成员函数初始化
	{

	}

	void start()
	{
		engline.start();//调用engline的start()
	}
};

int main()
{
	Car_pri car_pri;
	Car_comp car_comp;

	car_pri.start();
	car_comp.start();

	system("pause");
	return 0;
}

在这里插入图片描述

面试题14:构造函数调用虚函数

  • c++虚拟机制的理解
#include<iostream>
using namespace std;

class A
{
public:
	A()
	{
		doSth();//构造函数调用虚函数
	}

	virtual void doSth()
	{
		cout << "I am A" << endl;
	}
};

class B :public A
{
public:
	virtual void doSth()
	{
		cout << "I am B" << endl;
	}
};

int main()
{
	B b;


	system("pause");
	return 0;
}

在这里插入图片描述

面试题15:函数模板和类模板分别是什么

函数模板和类模板是C++中的重要特性,用于实现通用编程。它们允许在编写函数或类时使用泛型类型,以增强代码的可重用性和灵活性。

函数模板允许编写一个泛型函数,其参数或返回类型可以是任意类型。通过使用函数模板,可以为不同的数据类型编写通用的函数实现,而无需为每种数据类型编写重复代码。

例如,下面是一个简单的函数模板示例:

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

类模板类似地允许创建具有泛型类型的类。通过类模板,可以定义通用的数据结构或算法,以处理任意类型的数据。

以下是一个简单的类模板示例:

template <typename T>
class Pair {
private:
    T first;
    T second;
public:
    Pair(T f, T s) : first(f), second(s) {}
    T getMax() const {
        return (first > second) ? first : second;
    }
};

通过函数模板和类模板,我们可以实现模板化的代码,使代码更加灵活和可维护。

  • 示例代码
#include <iostream>
using namespace std;

#include <iostream>

template<typename T1, typename T2>
class point_T {
public:
    T1 a;
    T2 b;

    point_T() : a(0), b(0) {}
    point_T(T1 a_val, T2 b_val) : a(a_val), b(b_val) {}

    void Print() {
        std::cout << "a: " << a << ", b: " << b << std::endl;
    }
    point_T<T1, T2>& operator=(point_T<T1, T2>& pt);

    
};

template<typename T1, typename T2>
point_T<T1, T2>& point_T<T1, T2>::operator=(point_T<T1, T2>& pt) {
    this->a = pt.a;
    this->b = pt.b;
    return *this;
}

// 全局函数 operator+ 的定义
template<typename T1, typename T2>
point_T<T1, T2> operator+(point_T<T1, T2>& pt1, point_T<T1, T2>& pt2) {
    point_T<T1, T2> temp;
    temp.a = pt1.a + pt2.a;
    temp.b = pt1.b + pt2.b;
    return temp;
}

int main() {
    point_T<int, int> point1;
    point1.Print();

    point_T<int, int> point2(2, 3);
    point2.Print();

    point_T<int, int> point3 = point2;
    point3.Print();

    point_T<int, int> point4 = point2 + point3;
    point4.Print();

    

    return 0;
}

面试题16:把一个文件中的整数排序后输出到另一个文件中

  • 运用vector容器结局实际问题
#include<iostream>
#include<fstream>//操作文件头文件
#include<vector>
using namespace std;

//冒泡排序
void bubble_sort(vector<int>& ans)
{
	int len = ans.size();

	for (int i = 0; i < len; i++)
	{
		for (int j = 0; j < len - i - 1;j++)
		{
			if (ans[j] > ans[j + 1])
			{
				int temp = ans[j];
				ans[j] = ans[j + 1];
				ans[j + 1] = temp;

			}
		}
	}
}

int main()
{
	vector<int>data;
	//到开成功in为true,否则为false
	ifstream in("G:\\c++笔试训练\\vector\\mytest.txt");
	if (!in)
	{
		cout << "infile error!" << endl;
		return 1;
	}

	int temp;

	while (!in.eof())
	{
		in >> temp;//从文件中读取整数
		data.push_back(temp);//把读取的整数放到容器中
	}

	in.close();
	bubble_sort(data);//冒泡排序

	ofstream out("G:\\c++笔试训练\\vector\\result.txt");

	if (!out)
	{
		cout << "outfile error!" << endl;
		return 1;
	}

	for (int i = 0; i < data.size(); i++)
	{
		out << data[i] << " ";
	}

	out.close();


	system("pause");
	return 0;
}
  1. in.eof()介绍
    in.eof() 是用来检查文件流对象是否已经达到文件末尾的函数。eof() 是 istream 类的成员函数,用于检查输入流是否已经达到文件末尾。当文件流对象到达文件末尾时,eof() 返回 true,否则返回 false。

  2. in>>temp理解
    operator>> 在读取数据时会自动跳过空白字符,包括空格、制表符和换行符等。这意味着当使用 in >> temp 从输入流中读取数据时,它会自动忽略前面的空格,并将下一个非空白字符读取为数据。换句话说,如果输入流中存在空格,operator>> 会跳过这些空格并读取下一个有效的数据。
    这种行为对于从文件中读取数据时特别有用,因为可以确保在读取整数或其他类型数据时不必担心额外的空格或换行符等字符对数据读取造成影响。

面试题17:看代码找错—适配器stack和queue的使用

  • 考点:理解适配器stack和queue的使用
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
using namespace std;


int main()
{
	stack<int, vector<int>>s;
	queue<int, vector<int>>q;

	for (int i = 0; i < 10; i++)
	{
		s.push(i);
		q.push(i);
	}

	while (!s.empty())
	{
		cout << s.top() << endl;
		s.pop();
	}

	while (!q.empty())
	{
		cout << q.front() << endl;
		q.pop();
	}
	system("pause");
	return 0;
}
  • 错误1:queue不能使用vector作为底层容器
    stack<int, vector>s;
    queue<int, vector>q;

    这种写法使用了自定义的容器作为 STL 标准容器的底层实现,是希望在实例化 stack 和 queue 时使用 vector 作为底层容器。

通常情况下,stack 和 queue 都是用 deque 作为默认底层容器的,但如果想要使用 vector 作为底层容器,可以通过这种写法来实现。这种写法是在 C++11 中引入的。

需要注意的是,尽管可以使用 vector 作为底层容器,但是 queue 不支持使用 vector 作为其底层容器,因为 queue 的设计不适用于 vector 的少量常量特性。当队列使用q.front()时,因为vector作为q的底层容器但是没有这个成员函数,所以会报错

面试题18:什么是STL算法

  • 考点:理解STL算法的概念和作用

STL包含了大量的算法。它们巧妙地处理存储在容器中的数据。以reverse算法为例,我们只要简单使用reverse算法就能够逆置一个区间中的元素。

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>//stl算法头文件

using namespace std;

int main()
{
	int a[4] = { 1,2,3,4 };
	vector<string> v;
	v.push_back("one");
	v.push_back("two");
	v.push_back("three");

	reverse(a, a + 4);
	for (int i = 0; i < 4; i++)
	{
		cout << a[i] << " ";
	}
	cout << endl;

	vector<string>::iterator it = v.begin();

	//reverse<vector<string>::iterator>(it, v.end());

	reverse(it, v.end());//这种写法显然更容易理解
	for (int i = 0; i < 3; i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;


	system("pause");
	return 0;
}

面试题19:什么是auto_ptr(STL 智能指针)?如何使用

  • 考点:理解auto_ptr智能指针的使用

auto_ptr是在C++标准库中的一个智能指针。它是一种智能指针类,用于管理动态分配的对象,并在其生命周期结束时自动释放相关资源。

auto_ptr最早出现在C++98标准中,但自C++11标准开始已被弃用,因为其存在一些设计上的缺陷,特别是在拷贝和赋值操作上的表现不符合预期。

下面是auto_ptr的一些特点和限制:

  1. 只能用于管理单个对象的所有权,不能用于管理数组。
  2. 不支持多个指针共享同一资源,所有权的转移只能通过赋值操作实现。
  3. 在拷贝和赋值操作时,并不会进行深拷贝,而是转移资源所有权,这可能导致潜在的问题。
  4. auto_ptr不提供自定义删除器或定制释放行为的能力。

在实际使用中,建议使用C++11引入的std::unique_ptr和std::shared_ptr等智能指针替代auto_ptr,它们提供更加安全和灵活的资源管理能力。

面试题20:说一下c++里是怎么定义常量的,常量存放在内存的哪个位置?

  1. 对于局部变量,存放在栈区。
  2. 对于全局变量,编译期一般不分配内存,放在符号表中以提高访问效率
  3. 字面值常量,比如字符串,放在常量区。
  • 知识点补充:符号表

符号表是编译器在编译过程中用来存储程序中定义的变量、函数等符号及其相关信息的数据结构。符号表中通常包含符号的名称、类型、存储位置等信息,编译器在编译过程中通过符号表来管理和查询程序中的符号,以便生成目标代码。在C++中,全局变量的信息通常会被存储在符号表中,而不会分配实际的内存空间。这样可以提高访问效率,同时也方便编译器对全局变量的管理和优化。

面试题21:简单说一下函数指针

在C++中,函数指针是一个指向函数的指针变量。函数指针可以用来调用函数,允许程序在运行时动态地确定调用哪个函数。

函数指针的声明类似于函数声明,但是需要在函数名前加上*符号。例如,一个函数指针的声明可以如下所示:

int (*ptr)(int, int);

这个声明表示ptr是一个指向返回类型为int,接受两个int类型参数的函数的指针。

函数指针的使用可以帮助实现回调函数或者在运行时选择不同实现的函数。下面是一个简单的例子,演示如何定义一个函数指针,并使用它来调用不同的函数:

#include <iostream>

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int main() {
    int (*operation)(int, int);
    
    operation = add;
    std::cout << "Addition: " << operation(5, 3) << std::endl;
    
    operation = subtract;
    std::cout << "Subtraction: " << operation(5, 3) << std::endl;
    
    return 0;
}

在这个例子中,我们定义了两个函数add和subtract,然后声明一个函数指针operation,并分别将它指向add和subtract函数。通过这种方式可以动态地在运行时选择调用哪个函数。

总的来说,函数指针是一个强大的特性,可以帮助实现更加灵活和可变的代码逻辑。它在C++中广泛用于实现回调函数、函数指针数组、函数指针作为参数等功能。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值