【C++期末编程题题库】代码+详解18道

适合期末复习c++看,或者刚入门c++的小白看,有的题会补充知识点,期末复习题的代码一般比较简单,所以语法上没那么严谨。本文所有题目要求全在代码块的最上面。

目录

1、设计复数类

 2、设计Computer类

3、实现相加的函数模板

4、圆类的设计

5、学生类设计

6、求圆与直线位置关系

7、家庭账户共享

8、栈类的设计

9、主人召唤宠物

10、点圆圆柱单继承

11、点长方形长方体单继承

12、点圆球体运行时多态

13、学生数据写入文件和读取

14、图形抽象类派生具体类求多个图形面积

15、 除数为0的异常处理

 16、学生数据修改【文件操作】

17、分数的加减

 18、统计字符数组中某个字符出现次数


1、设计复数类

//设计复数类Complex和友元运算符重载>>及<<实现复数类对象的标准输入和输出
#include<iostream>
using namespace std;

class Complex
{
private:
	double real, imag;
public:
	Complex(double r = 0, double i = 0)
	{
		real = r;
		imag = i;
	}
	//下面是友元的声明,所以函数参数只写类型是可以的
	friend istream& operator>>(istream&, Complex&);
	friend ostream& operator<<(ostream&, Complex&);
};
istream& operator>>(istream& input, Complex& c)
{
	//输入实部和虚部
	input >> c.real >> c.imag;
	return input;//返回istream,符合operator>>的实现
}

ostream& operator<<(ostream& output, Complex& c)
{
	if (c.imag > 0)
		output << c.real << "i+" << c.imag;
	else if (c.imag < 0)
		output << c.real << "i" << c.imag;
	else
		output << c.real << "i";

	return output;
}

int main()
{
	Complex c;
	cin >> c;
	cout << c;
	return 0;
}


 2、设计Computer类

//计算机Computer的属性包括型号、生产厂家和价格,用文件流中write()函数将若干
//计算机中的信息写入文件Computer.dat中,然后用read()函数将Computer.dat中所有数据读出。
#include<iostream>
#include<string>
#include<fstream>
using namespace std;

//涉及文件读写操作了,肯定要访问成员变量,用struct即可
struct Computer
{
	int id;
	string manufacter;
	double price;
};

int main()
{
	Computer c;
	cout << "Please input the id, manufacter and price of Computer:";
	cin >> c.id >> c.manufacter >> c.price;
	ofstream out("Computer.dat", ios::binary | ios::out);
	if (!out.is_open())//如果文件打开不成功//也可写为if(!out)
	{
		cout << "fail to open the file\n" << endl;
		exit(-1);
	}
	out.write((const char*)&c, sizeof(c));//写入是const char*
	out.close();

	ifstream in("Computer.dat", ios::binary | ios::in);
	if (!in)
	{
		cout << "fail to open the file\n" << endl;
		exit(-1);
	}
	in.read((char*)&c, sizeof(c));//读取是char*
	in.close();
	
	cout << "the data of Computer is:" << endl;
	cout << c.id << " " << c.manufacter << " " << c.price << endl;

	return 0;
}


3、实现相加的函数模板

//编写两个相长度数值型一维数组对应元素相加的函数模板
#include<iostream>
using namespace std;

template<class T>
void add(T a[], T b[], T c[], int n)
{
	for (int i = 0; i < n; i++)
		c[i] = a[i] + b[i];
}

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int b[5] = { 1, 2, 3, 4, 5 };
	int c[5];
	add(a, b, c, 5);
	for (int i = 0; i < 5; i++) cout << c[i] << " ";
	cout << endl;

	return 0;
}


4、圆类的设计

//1、圆类的设计:设计一个圆类,计算出它的周长,面积,
//并有圆心移动和半径移动(就是变化的意思)的操作,并打印出数据
#include<iostream>
using namespace std;

//这里最好不要用float,除非你写为3.14f,因为你写一个小数3.14默认为double
//如果你用float,这里就会发生截断,因为是从double到float
const double pi = 3.14;

class Circle
{
public:
	//也可采用c++11的初始化列表方式
	/*Circle(int x = 0, int y = 0, int r = 0)
		:_x(x)
		,_y(y)
		,_r(r)
	{}*/

	Circle(double x = 0, double y = 0, double r = 0)
	{
		_x = x; _y = y; _r = r;
	}
	double circum()
	{
		return 2 * pi * _r;
	}
	double area()
	{
		return pi * _r * _r;
	}
	void movep(double x, double y)
	{
		_x += x; _y += y;
	}
	void mover(double r)
	{
		_r += r;
	}
	void show()
	{
		cout << "圆心:(" << _x << "," << _y << ") 半径:" << _r << endl;
	}

private:
	double _x, _y, _r;
};

int main()
{
	Circle c(1.2, 1.3, 2.1);
	c.show();
	cout << "circum:" << c.circum() << "   " << "area:" << c.area() << endl;
	c.movep(1.1, 2.2);
	c.show();
	c.mover(1.2);
	c.show();

	return 0;
}


5、学生类设计

//学生类设计求学生最高分最低分和平均分,并打印出学生信息
#include<iostream>
#include<string>
using namespace std;

class Student
{
private:
	int _id;
	string _name;
	double _score;

public:
	Student(int id = 0, string name = "", double score = 0.0)
	{
		_id = id;
		_name = name;
		_score = score;
	}

	void input(int id, string name, double score)
	{
		_id = id;
		_name = name;
		_score = score;
	}

	double Getscore()
	{
		return _score;
	}

	void show()
	{
		cout << "id:" << _id << " " << "name:" << _name << " " << "score:" << _score << endl;
	}
};

double maxscore(Student stu[], int n)
{
	double maximum = 0.0;
	for (int i = 0; i < n; i++)
		if (maximum < stu[i].Getscore()) maximum = stu[i].Getscore();
	return maximum;
}

double minscore(Student stu[], int n)
{
	double minimum = 100;
	for (int i = 0; i < n; i++)
		if (minimum > stu[i].Getscore()) minimum = stu[i].Getscore();
	return minimum;
}

double averscore(Student stu[], int n)
{
	double sum = 0.0;
	for (int i = 0; i < n; i++)
		sum += stu[i].Getscore();
	return sum / n;
}

int main()
{
	Student stu[3];
	int id; string name; double score;
	for (int i = 0; i < 3; i++)
	{
		cin >> id >> name >> score;
		stu[i].input(id, name, score);
	}

	for (int i = 0; i < 3; i++) stu[i].show();

	cout << "maxscore:" << maxscore(stu, 3) << endl;
	cout << "minscore:" << minscore(stu, 3) << endl;
	cout << "averscore:" << averscore(stu, 3) << endl;

	return 0;
}


6、求圆与直线位置关系

//定义直线类和圆类,求两者位置关系(相切、相交或相离)
#include<iostream>
#include<cmath>
using namespace std;

//直线:ax + by + c = 0
class Circle;//必须先声明Circle类,不然友元函数找不到Circle
class Line
{
private:
	double _a, _b, _c;
public:
	Line(double a = 0, double b = 0, double c = 0)
	{
		_a = a;
		_b = b;
		_c = c;
	}
	//这里不用友元也可以,你可以用一个geta等等来获取私有成员,对于圆类同理
	friend int position_relation(const Line&, const Circle&);
};

class Circle
{
private:
	double _x, _y, _r;//圆心和半径
public:
	Circle(double x = 0, double y = 0, double r = 0)
	{
		_x = x;
		_y = y;
		_r = r;
	}
	friend int position_relation(const Line&, const Circle&);
};

//圆与直线位置关系公式:d=ax+by+c/根号下a*a+b*b【其中abc均为直线的,x和y是圆的圆心】
//如果d>r:相离 d==r:相切 d<r:相交
int position_relation(const Line& l, const Circle& c)
{
	double d = l._a * c._x + l._b * c._y + l._c / sqrt(l._a * l._a + l._b * l._b);
	//因为d是算出来的,浮点数会有精度损失,所以比较的时候要靠精度来比
	if (fabs(d - c._r) > 0.000001) return -1;     //相离
	else if (fabs(d - c._r) < 0.000001) return 1; //相交
	else return 0;							//相切
}

int main()
{
	Line l(2.1, 2.2, 2.3);
	Circle c(1.1, 1.2, 1.3);
	int ret = position_relation(l, c);
	if (ret == -1) cout << "相离" << endl;
	else if (ret == 1) cout << "相交" << endl;
	else cout << "相切" << endl;

	return 0;
}

回顾友元:

在C++中,友元函数(Friend Function)是一种特殊的函数,它可以访问并操作类的私有成员,即使它不是类的成员函数。通过友元函数,我们可以实现对类的私有成员的非成员函数访问权限。友元提供了一种突破封装的方式。友元函数提供了一种在需要时访问类的私有成员的机制,但应该慎重使用,因为过多的友元函数可能破坏类的封装性。

友元函数特性:

  • (1) 友元函数可以访问类的私有和保护成员,但不是类的成员函数。
  • (2) 友元函数不能被const修饰。由于友元函数不属于任何类的成员函数,它们无法被 const 修饰。
  • (3) 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  • (4) 一个函数可以是多个类的友元函数。
  • (5) 友元函数的调用与普通函数的调用和原理相同。
  • (6)友元函数/友元类是单向的,A在B类中被声明为友元函数/友元类,表示A是B的友元函数/友元类,但B不是A的友元类函数/友元类;
  • (7)友元函数在类中声明时用friend修饰,但是在定义时不需要用friend修饰;
  • (8)友元函数不能被继承:父类的友元函数,继承后并不会成为子类的友元函数;
  • (9)友元函数不具有传递性:A类和B类都是C类的友元类,但是A类和B类并不是友元类;

7、家庭账户共享

//家庭银行账户共享,即一个家庭几个成员共享财产,设计一个Familymember类
//实现钱财的支出和存钱,并显示剩余钱额【定义静态成员实现】
#include<iostream>
#include<string>
using namespace std;

class Familymember
{
private:
	string _name;
public:
	Familymember(string name = "");
	static double money;
	static void save(double m);
	static void expend(double m);
	static void show();
};
//类外初始化静态成员变量不要加static
double Familymember::money = 0;//类內声明,类外定义

Familymember::Familymember(string name)
{//类內声明已经有默认参数,类外就不能给了,否则就重定义默认参数了
	_name = name;
}
//类外定义静态成员函数不能加static
void Familymember:: save(double m)
{
	money += m;
}

void Familymember::expend(double m)
{
	money -= m;
}

void Familymember::show()
{
	cout << "remained money:" << money << endl;
}

int main()
{
	Familymember wife("zhu"), husband("jiang");
	wife.save(10000);
	husband.expend(5000);
	husband.save(20000);
	wife.show();//对象可以访问静态成员函数,但静态成员函数没有this指针
	husband.show();
	Familymember::show();

	return 0;
}


8、栈类的设计

//设计一个静态栈类,内有构造函数,且有压栈和入栈操作,并返回栈顶元素,输入数据
//以0表示结束
//学校期末要求不高,我以前的博客写过动态栈,想了解的可以看看
#include<iostream>
using namespace std;

//这里不要定义为size,因为size是一个关键字,用于定义类型大小,如果你这里
//常量名称定义为size就会冲突!但是在devc++就能跑过去,可能dev不严谨,vs下是过不去的
const int stackSize = 100;

class Stack
{
private:
	int sta[stackSize];
	int _top;//栈顶

public:
	Stack();
	int push(int x);//入栈
	int pop();//出栈
};

Stack::Stack()
{//直接置空即可
	_top = 0;
}

int Stack::push(int x)
{
	if (_top == stackSize)
		return 0;//栈满返回0

	sta[_top++] = x;
	return x;
}

int Stack::pop()
{
	if (_top == 0)
		return 0;//栈空返回0
	//返回删除之后的栈顶
	return sta[--_top];
}

int main()
{
	Stack s;
	int x;
	cout << "Please input pushed data:" << endl;
	cin >> x;
	while (x && s.push(x))
	{
		cout << "Please input pushed data:" << endl;
		cin >> x;
	}
	
	while (x = s.pop())
		cout << "the poped data is :" << x << endl;

	return 0;
}

​​​​​​​


9、主人召唤宠物

//主人召唤宠物,宠物有名字和应答语,主人也有名字,他可以召唤宠物,看召唤名字与宠物
//的名字是否一致,若一致,宠物就会回应应答语
#include<iostream>
#include<string>
using namespace std;
class Pet
{
private:
	string _name;
	string _ans;

public:
	Pet(string name = "", string ans = "")
	{
		_name = name;
		_ans = ans;
	}

	void answer(string name) const
	{
		if (name == _name)//调用string的operator==
			cout << _ans << endl;
		else
			cout << "dear host, you are not calling me!" << endl;
	}
};

class Host
{
private:
	string _name;

public:
	Host(string name = "")
	{
		_name = name;
	}
	
	void call(const Pet& p, string name)
	{
		p.answer(name);
	}
};

int main()
{
	Host h("MeiZhu");
	Pet dog("huihui", "wangwang");
	Pet cat("huahua", "miaomiao~");
	h.call(dog, "huihui");
	h.call(cat, "huahuaya");

	return 0;
}


10、点圆圆柱单继承

//点圆圆柱单继承,即圆类继承点【圆心】类,再由圆柱类继承圆类,求出面积和体积
#include<iostream>
using namespace std;

const double pi = 3.14;

class Point
{
private://private即可,圆类求面积和体积用不到圆心
	double _x, _y;
public:
	Point(double x = 0, double y = 0)
	{
		_x = x;
		_y = y;
	}
	double area()
	{
		return 0.0;
	}
	double volume()
	{
		return 0.0;
	}
};

class Circle : public Point
{
protected://这里若用private的话,Cylinder求面积和体积就无法使用了
	double _r;

public:
	Circle(double r = 0.0, double x = 0.0, double y = 0.0)
		:Point(x, y)
	{
		_r = r;
	}
	double area()
	{
		return pi * _r * _r;
	}
	double volume()
	{
		return 0.0;
	}
};

class Cylinder : public Circle
{
private:
	double _h;

public:
	Cylinder(double x = 0.0, double y = 0.0, double r = 0.0, double h = 0.0)
		:Circle(r, x, y)
	{
		_h = h;
	}
	double area()
	{	//上下底圆的面积+侧面积:长方形面积
		return 2 * pi * _r * _r + 2 * pi * _r * _h;
	}
	double volume()
	{	//圆柱体积为底面积*高
		return Circle::area() * _h;
	}
};

int main()
{
	Circle cir(2.1, 1.1, 2.2);
	Cylinder cy(2.2, 2.3, 2.4, 1.2);
	cout << cir.area() << "    " << cir.volume() << endl;
	cout << cy.area() << "    " << cy.volume() << endl;

	return 0;
}


11、点长方形长方体单继承

//点长方形长方体单继承,长方形继承点类,长方体继承长方形类,求面积和体积
#include<iostream>
using namespace std;

class Point
{
private:
	double _x, _y;

public:
	Point(double x = 0.0, double y = 0.0)
	{
		_x = x;
		_y = y;
	}
	double area()
	{
		return 0.0;
	}
	double volume()
	{
		return 0.0;
	}
};
//长方形
class Rectangle : public Point
{
protected://不能设为private,不然长方体类中用不了了
	double _length, _width;

public:
	Rectangle(double x = 0.0, double y = 0.0, double l = 0.0, double w = 0.0)
		:Point(x, y)
	{
		_length = l;
		_width = w;
	}
	double area()
	{
		return _length * _width;
	}
	double volume()
	{
		return 0.0;
	}
};
//长方体
class Cuboid : public Rectangle
{
private:
	double _h;

public:
	Cuboid(double x, double y, double l, double w, double h)
		:Rectangle(x, y, l, w)
	{
		_h = h; 
	}
	double area()
	{//长方体表面积:2长*宽+2长*高+2宽*高
		return 2 * _length * _width + 2 * _length * _h + 2 * _width * _h;
	}
	double volume()
	{//长方体体积:底面积*高
		return _length * _width * _h;
	}
};

int main()
{
	Rectangle rec(1.1, 2.0, 2.3, 2.4);
	Cuboid cub(1.2, 2.2, 2.4, 4.5, 1.1);
	cout << "area of rectangle is :" << rec.area()  << "\t" << "volume of rectangle is:" << rec.volume() << endl;
	cout << "area of cuboid is :" << cub.area() << "\t" << "volume of cuboid is:" << cub.volume() << endl;

	return 0;
}


12、点圆球体运行时多态

//点圆球体运行时多态:由圆类继承点类,球类继承圆类,实现求面积和体积,要求多态实现
#include<iostream>
using namespace std;

const double pi = 3.14;

class Point
{
private:
	double _x, _y;
public:
	Point(const double& x, const double& y)
	{//这种加const写法的才是最标准的,因为应付期末,没有那么高的要求的
		_x = x;
		_y = y;
	}
	virtual double area() = 0;
	virtual double volume() = 0;
};

class Circle : public Point
{
protected:
	double _r;
public:
	Circle(double x, double y, double r)
		:Point(x, y)
	{
		_r = r; 
	}
	virtual double area()
	{	//圆的面积:π*r*r
		return pi * _r * _r;
	}
	virtual double volume()
	{
		return 0.0;
	}
};
//球体类
class Sphere : public Circle
{
private:
	double _z; //因为球体的是三维的,所以它的圆心应该再增加一个维度
public:
	Sphere(double x, double y, double r, double z)
		:Circle(x, y, r)
	{
		_z = z;
	}
	double area()
	{
		return 4 * pi * _r * _r;
	}
	double volume()
	{   //V=(4/3)πr^3
		return 4 * pi * _r * _r * _r / 3;
	}
};


int main()
{
	Point* p;
	Circle c(1.1, 1.2, 1.3);
	Sphere s(1.2, 1.3, 1.4, 1.5);
	p = &c;
	cout << " circle: " << p->area() << "\t\t" << p->volume() << endl;
	p = &s;
	cout << " sphere: " << p->area() << "\t" << p->volume() << endl;

	return 0;
}


13、学生数据写入文件和读取

//学生数据写入文件,并读取文件数据到程序中【使用read和write实现】
#include<iostream>
#include<fstream>
using namespace std;

struct Student
{
	char name[20];
	int id;
	int age;
	char gender[5];
};

int main()
{
	//创建一个输出流对象,并打开文件,以二进制的方式写
	//写法1:
	//ofstream outfile;
	//outfile.open("test.txt", ios::binary | ios::trunc);
	//trunc:如果文件存在先删除,再创建【一般是不用的】
	//写法2:更简洁!
	ofstream outfile("test.txt", ios::binary | ios::trunc);
	if (!outfile)//或写为if(!outfile.is_open())
	{//判断文件是否打开成功
		cout << "file open error!" << endl;
		exit(1);//exit(非0)都代表异常退出
	}

	Student stu[3];
	cout << "Please input the data of 3 students" << endl;
	for (int i = 0; i < 3; i++)
	{
		cin >> stu[i].name >> stu[i].id >> stu[i].age >> stu[i].gender;
		//写入文件,以二进制形式写入
		outfile.write((const char*)&stu[i], sizeof(stu[i]));
	}
	outfile.close();//关闭文件以便以下一次的读出数据

	//再把学生数据读出
	Student tmp[3];//保存从文件中读出的数据
	ifstream infile("test.txt", ios::binary);

	//读取方法一:直接读取整个数组的数据中
	//infile.read((char*)tmp, sizeof(tmp));
	//或写为infile.read((char*)&tmp[0], sizeof(tmp));//因为都是首元素的地址,读取的是一整个数组

	cout << "The Student data read from file is:" << endl;
	for (int i = 0; i < 3; i++)
	{//读取方法二:读取数据一个一个数组元素来读取
		infile.read((char*)&tmp[i], sizeof(tmp[i]));
		cout << tmp[i].name << " " << tmp[i].id << " " << tmp[i].age
			<< " " << tmp[i].gender << endl;
	}
	infile.close();

	return 0;
}

测试结果如下:

 此时打开test.txt文件可以看出是二进制的形式,我们看不懂,但是从文件中读入到程序当中就能看出来了,主要是因为这种二进制读写方式很方便


14、图形抽象类派生具体类求多个图形面积

//用图形类派生圆类和三角形类,分别求面积,并求出面积之和【多态实现】
#include<iostream>
using namespace std;

const double pi = 3.14;

class Graph
{
public:
	virtual double area() = 0;
};

class Circle : public Graph
{
private:
	double _x, _y, _r;
public:
	Circle(const double& x, const double& y, const double& r)
		:_x(x)
		,_y(y)
		,_r(r)
	{}
	double area()
	{
		return pi * _r * _r;
	}
};

class Triangle : public Graph
{
private:
	double _bottom, _h;
public:
	Triangle(const double& bottom, const double& h)
		:_bottom(bottom)
		,_h(h)
	{}
	double area()
	{
		return 0.5 * _bottom * _h;
	}
};

double sumarea(Graph* g[], int n)
{
	double sum = 0.0;
	for (int i = 0; i < n; i++)
		sum += g[i]->area();

	return sum;
}

int main()
{
	Circle c1(1.1, 1.2, 1.3), c2(1.2, 1.3, 1.4);
	Triangle t1(2.1, 3.1), t2(1.1, 3.4);
	Graph* g[4] = { &c1, &c2, &t1, &t2 };
	cout << sumarea(g, 4) << endl;

	return 0;
}


15、 除数为0的异常处理

建议先看我写过的异常文章:【C++】异常【完整版】-CSDN博客

//写一个实现除法的函数,主函数利用异常处理除数为0的情况
#include<iostream>
#include<string>
using namespace std;

//division:除法,dividend:被除数,divisor:除数
double division(double x, double y)
{
	if (y == 0)
	{
		//我们不建议写为throw 0.0, 因为这种处理方式和之前讲的错误码一样,没什么意义
		//不如直接用错误码了
		throw string("发生除0错误!");
	}
	return x / y;
}

int main()
{
	try
	{
		double x, y;
		cin >> x >> y;
		cout << "x / y = " << division(x, y) << endl;
		cin >> x >> y;
		cout << "x / y = " << division(x, y) << endl;
	}
	catch (const string& err)
	{
		cout << err << endl;
	}
	//下面用基类捕获的方式,若除数为0,会直接报错!
	//但有时如出现数组越界问题等,会直接打印出错误信息
	//catch (exception& e)
	//{
	//	cout << e.what() << endl;
	//}

	return 0;
}


 16、学生数据修改【文件操作

//建立学生类,将学生数据写入文件,然后读取回程序中,并修改第3个学生的信息,然后写入文件
//然后再读取到程序中并打印【要求:read和write实现,并使用文件指针定位的seekp和seekg】
#include<iostream>
#include<fstream>
#include<string>
using namespace std;

struct Stu
{
	int id;
	char name[20];//不能用string,不然会报错:读取访问权限冲突,除非用c_str,原因下面解释
	double score;
};

int main()
{
	Stu stu[20];
	//为什么要用fstream呢?因为下面有读指针和写指针操作同时进行的,这里定义fstream对象
	//既可以读又可以写,很方便,省得下面你又得关闭文件,然后又打开文件...
	fstream io("stu.txt", ios::binary | ios::out | ios::in);
	if (!io)
	{
		cout << "Fail to open the file!" << endl;
		exit(-1);
	}

	cout << "Please input the datas of students:" << endl;
	for (int i = 0; i < 3; i++)
		cin >> stu[i].id >> stu[i].name >> stu[i].score;
	io.write((const char*)stu, sizeof(stu));//一次性把整个数组全都写入文件中
	io.close();

	io.open("stu.txt", ios::binary | ios::in | ios::out);
	if (!io)
	{
		cout << "Fail to open the file!" << endl;
		exit(-1);
	}
	Stu tmp;
	cout << "Please input the updated datas of the third student:" << endl;
	cin >> tmp.id >> tmp.name >> tmp.score;
	io.seekp(2 * sizeof(tmp), ios::beg);//写文件指针定位,从原来第3个学生的位置开始
	io.write((const char*)&tmp, sizeof(tmp));//把修改后的数据放回文件中第3个学生的位置
	io.close();

	io.open("stu.txt", ios::binary | ios::out | ios::in);
	io.read((char*)stu, sizeof(stu));//修改完第3个学生数据后读回数组中
	io.close();//一定要关闭文件!

	cout << "The students' datas read from file are:" << endl;
	for (int i = 0; i < 3; i++)
		cout << stu[i].id << " " << stu[i].name << " " << stu[i].score << endl;

	return 0;
}

问题①、C++中文件读写类对象时,如果类对象中有string类型的成员变量,如何处理?

在C++中,对于类对象的二进制读写,涉及到对象的内存布局和成员变量的特性。而对于`string`这样的对象,它的内部实现复杂,包括指针指向堆上的动态内存,涉及到分配和释放内存等操作。因此,直接进行二进制读写可能会导致读取权限冲突。当你尝试将包含`string`成员变量的对象写入文件时,实际上只会将指针的值写入文件,而不是字符串的内容。而在读取文件时,再次加载这个对象,那个指针就指向了一个无效的内存地址。这会导致访问非法内存,进而出现读取权限冲突。为了避免这个问题,你可以考虑使用序列化和反序列化来实现文件的读写操作。序列化是指将对象转换为序列化的字节流,而反序列化则是将字节流重新转换为对象。通过序列化和反序列化操作,可以确保对象的完整性和正确性。你可以使用C++的一些库(如Boost.Serialization、Protocol Buffers)来实现对象的序列化和反序列化。这些库提供了易于使用和强大的功能,让你可以方便地进行对象的读写操作,而不会发生读取权限冲突的问题。

在C++中,文件读写类对象时,是可以包含string类型的成员变量的。C++的文件读写操作对于大多数基本类型和标准库类型(包括string)都有支持。当你将一个自定义的类对象写入文件时,包含了string类型成员变量的类实例将被完整地写入文件中。但需要注意的是,string对象的存储是动态的,所以仅将类对象的二进制数据写入文件是不够的,还需要将string的内容一并写入文件,并在读取时进行相应处理。你可以使用C++标准库中的fstream类进行文件读写操作。例如,可以使用ofstream类对象将类对象写入文件,再使用ifstream类对象从文件中读取类对象。在写入时,可以使用成员函数c_str()将string类型转换为C风格字符串,并使用成员函数write()写入文件;在读取时,可以使用成员函数getline()读取文件中的字符串,并重新构造string对象。

注意,在进行文件读写操作时,需要保证文件的打开和关闭操作正确执行,并处理可能出现的异常情况,以确保数据的完整性与安全性。同时,为了确保跨平台的文件读写兼容性,建议在二进制读写时使用文本模式(例如使用"rb"和"wb"参数)。

以下是一个简单的示例代码,演示了如何进行文件读写操作:

#include <fstream>
#include <iostream>
#include <string>

class MyClass {
public:
    std::string name;
    int age;
};

int main() {
    MyClass obj;
    obj.name = "Alice";
    obj.age = 20;

    std::ofstream outfile("data.txt", std::ios::binary);
    if (outfile.is_open()) {
        outfile.write(obj.name.c_str(), obj.name.length() + 1);
        outfile.write(reinterpret_cast<char*>(&obj.age), sizeof(obj.age));
        outfile.close();
        std::cout << "对象写入文件成功" << std::endl;
    } else {
        std::cout << "打开文件失败" << std::endl;
        return 1;
    }

    std::ifstream infile("data.txt", std::ios::binary);
    if (infile.is_open()) {
        std::string name;
        std::getline(infile, name, '\0');
        obj.name = name;
        infile.read(reinterpret_cast<char*>(&obj.age), sizeof(obj.age));
        infile.close();

        std::cout << "从文件中读取的对象:" << std::endl;
        std::cout << "name: " << obj.name << std::endl;
        std::cout << "age: " << obj.age << std::endl;
    } else {
        std::cout << "打开文件失败" << std::endl;
        return 1;
    }

    return 0;
}

该示例中,定义了一个包含string类型成员变量的MyClass类,通过ofstream对象将类的实例写入文件,再通过ifstream对象从文件中读取类对象。在写入时,使用了成员函数c_str()获取string对象的C风格字符串;在读取时,使用了成员函数getline()读取字符串,并重新构造了string对象。最后,将读取到的类对象的成员变量输出到控制台。

问题②、c++中,在文件操作中,为什么读取完数据后,要关闭文件,才能写入数据到文件?  

在C++中,关闭文件的目的不是为了读取完数据后才能写入数据到文件,而是为了确保对文件进行完整的操作并释放相关资源。

文件在被打开后会占用一些系统资源,如文件描述符等。当读取完数据后,如果不关闭文件,文件依然保持打开状态,此时其他程序可能无法对该文件进行操作或者文件的状态可能不会及时更新。此外,一些操作系统可能会限制同时打开的文件数量,如果不关闭文件,可能会达到限制而导致其他文件无法正常打开。最重要的是,关闭文件还可以确保数据的完整性和正确性。在写入数据时,操作系统会将数据缓存到内存中,然后根据一定的策略将数据写入到文件中,这个过程是异步的。如果在写入数据的过程中突然关闭文件,可能会导致数据丢失或不完整。

因此,为了保证文件操作的正确性和系统资源的释放,我们通常会在读取完数据后关闭文件,然后再进行写入操作。这样可以确保文件的状态正确、数据的完整性并释放相关的资源。


17、分数的加减

//定义分数类,内有构造函数和显示分数的show函数,并利用友元函数实现分数的加减
#include<iostream>
using namespace std;

class Fraction
{
private:
	double dividend, divisor;//dividend:被除数,即分子 divisor:除数,即分母
public:
	Fraction(const double& divid = 0.0, const double& divir = 0.0)
		:dividend(divid)
		,divisor(divir)
	{}

	void show()
	{
		cout << dividend << "/" << divisor << endl;
	}

	friend Fraction operator+(const Fraction&, const Fraction&);
	friend Fraction operator-(const Fraction&, const Fraction&);
};

Fraction operator+(const Fraction& f1, const Fraction& f2)
{
	return Fraction(f1.dividend * f2.divisor + f1.divisor * f2.dividend
		, f1.divisor * f2.divisor);
}

Fraction operator-(const Fraction& f1, const Fraction& f2)
{
	return Fraction(f1.dividend * f2.divisor - f1.divisor * f2.dividend
		, f1.divisor * f2.divisor);
}

int main()
{
	Fraction f1(2, 3), f2(1, 2), f3;
	f3 = f1 + f2;
	f3.show();
	f3 = f1 - f2;
	f3.show();
	
	return 0;
}


 18、统计字符数组中某个字符出现次数

//定义求一个字符数组中某字符有多少个的函数sum(),用c++实现
#include<iostream>
using namespace std;

int sum(char* arr, char target)
{
	int cnt = 0;
	int i = 0;
	while (arr[i] != '\0')
	{
		if (arr[i] == target)
			cnt++;
		i++;
	}

	return cnt;
}

int main()
{
	char arr[] = "hello world!";
	char target = 'o';
	int ret = sum(arr, target);
	cout << target << "出现了:" << ret << "次" << endl;

	return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/293645.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Java SSM框架实现新闻推送系统项目【项目源码】计算机毕业设计

基于java的SSM框架实现新闻推送系统演示 SSM框架 当今流行的“SSM组合框架”是Spring SpringMVC MyBatis的缩写&#xff0c;受到很多的追捧&#xff0c;“组合SSM框架”是强强联手、各司其职、协调互补的团队精神。web项目的框架&#xff0c;通常更简单的数据源。Spring属于…

Python 快速合并PDF表格转换输出CSV文件

单位的刷脸考勤机后台系统做得比较差&#xff0c;只能导出每个部门的出勤统计表pdf&#xff0c;格式如下&#xff1a; 近期领导要看所有部门的考勤数据&#xff0c;于是动手快速写了个合并pdf并输出csv文件的脚本。 安装模块 pypdf2&#xff0c;pdfplumber&#xff0c;前者用…

年底了,准备跳槽的可以看看...

前两天跟朋友感慨&#xff0c;今年的铜九铁十、裁员、疫情导致好多人都没拿到offer!现在已经1月了&#xff0c;具体明年的金三银四只剩下两个月。 对于想跳槽的职场人来说&#xff0c;绝对要从现在开始做准备了。这时候&#xff0c;很多高薪技术岗、管理岗的缺口和市场需求也出…

企业该如何选择好的跨境数据传输平台

跨境数据传输平台是一种可以帮助企业在不同国家和地区之间安全传输数据的工具。它可以通过对数据进行加密、脱敏、压缩等处理&#xff0c;确保数据在传输过程中的安全性和完整性。同时&#xff0c;它还可以根据不同的合规要求&#xff0c;对数据进行分类、分级、备份等处理&…

Prometheus实战篇:Prometheus监控redis

准备环境 docker-compose安装redis docker-compose.yaml version: 3 services:redis:image:redis:5container_name: rediscommand: redis-server --requirepass 123456 --maxmemory 512mbrestart: alwaysvolumes:- /data/redis/data: /dataport:- "6379:6379"dock…

数据结构之各大排序(C语言版)

我们这里话不多说&#xff0c;排序重要性大家都很清楚&#xff0c;所以我们直接开始。 我们就按照这张图来一一实现吧&#xff01; 一.直接插入排序与希尔排序. 这个是我之前写过的内容了&#xff0c;大家可以通过链接去看看详细内容。 算法之插入排序及希尔排序&#xff08…

Spring中的工厂类

目录 1.ApplicationContext 4.2.BeanFactory 1.ApplicationContext ApplicationContext的实现类&#xff0c;如下图&#xff1a; ClassPathXmlApplicationContext&#xff1a;加载类路径下 Spring 的配置文件 FileSystemXmlApplicationContext&#xff1a;加载本地磁盘下 S…

安徽2024考试公告一览表!有需要的速收藏

考公群体&#xff0c;越来越多&#xff01; 考研减少的很多学生转来考公&#xff0c;24年国考人数突破291万&#xff0c;较23年增长约40万 考试难度&#xff0c;逐年增大&#xff0c;逐年创新&#xff01; 结束的24国考&#xff0c;江浙省考&#xff0c;学生普遍反映难度增大&a…

[C#]使用OpenCvSharp实现二维码图像增强超分辨率

【官方框架地址】 github.com/shimat/opencvsharp 【算法介绍】 借助于opencv自带sr.prototxt和sr.caffemodel实现对二维码图像增强 【效果展示】 【实现部分代码】 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin…

代码随想录-刷题第四十七天

139. 单词拆分 题目链接&#xff1a;139. 单词拆分 思路&#xff1a;本题可以使用记忆化回溯&#xff0c;不再过多介绍&#xff0c;主要讲解完全背包方法。 单词就是物品&#xff0c;字符串s就是背包&#xff0c;单词能否组成字符串s&#xff0c;就是问物品能不能把背包装满。…

VSCode编辑器下载与安装

1、下载 官网下载地址&#xff1a; 打开下载地址&#xff0c;如下图&#xff0c;根据自己的平台选择相应版本下载&#xff08;本文只针对Windows系统的安装&#xff0c;所以下载Windows版的&#xff09;。 点击会自动下载&#xff0c;下载完成文件如下图&#xff1a; 2、安装…

python入门,list列表详解

目录 1.list的定义 2.index查找某元素的下标 3.修改 ​编辑 4.插入 ​编辑 5.追加元素 1.append,追加到尾部 2.extend,追加一批元素 ​编辑 6.删除元素 1.del 列表[下标] 2.列表.pop(下标) 3.列表.remove(元素) 7.清空列表 8.统计某一元素在列表内的数量 9.计算…

计算机组成原理 控制器

控制器 #mermaid-svg-cDexVavlf0QIZRSF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-cDexVavlf0QIZRSF .error-icon{fill:#552222;}#mermaid-svg-cDexVavlf0QIZRSF .error-text{fill:#552222;stroke:#552222;}#me…

iOS苹果和Android安卓测试APP应用程序的差异

Hello大家好呀&#xff0c;我是咕噜铁蛋&#xff01;我们经常需要关注移动应用程序的测试和优化&#xff0c;以提供更好的用户体验。在移动应用开发领域&#xff0c;iOS和Android是两个主要的操作系统平台。本文铁蛋讲给各位小伙伴们详细介绍在App测试中iOS和Android的差异&…

设计模式之装饰者模式【结构型模式】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某…

Linux内存管理:(五)反向映射RMAP

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 1. 前置知识&#xff1a;page数据结…

【unity】基于Obi的绳/杆蓝图、绳杆区别及其创建方法

绳索 是通过使用距离和弯曲约束将粒子连接起来而形成的。由于规则粒子没有方向(只有位置)&#xff0c;因此无法模拟扭转效应(维基百科)&#xff0c;绳子也无法保持其静止形状。然而&#xff0c;与杆不同的是&#xff0c;绳索可以被撕裂/劈开&#xff0c;并且可以在运行时改变其…

LeetCode(36)有效的数独 ⭐⭐

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff09; 注…

微商城怎么弄才能开通呢?

​微商城的开通&#xff0c;对于许多商家来说&#xff0c;是进入移动电商领域的重要一步。它不仅能帮助你扩大销售渠道&#xff0c;还能让你更好地管理和服务你的客户。那么&#xff0c;微商城怎么弄才能开通呢&#xff1f; 1、注册微信公众号&#xff1a;首先&#xff0c;你需…

奇数码问题

title: 奇数码问题 date: 2024-01-05 11:52:04 tags: 逆序对 cstefories: 算法进阶指南 题目大意 解题思路 将二维转化为一维&#xff0c;求他的逆序对&#xff0c;如果逆序对的奇偶性相同&#xff0c;则能够实现。 代码实现 #include<iostream> #include<string.h&…