C++错误总结

这篇文章主要用于总结一些错误

问题1:未知重写说明符

#include <iostream>
#include <Windows.h>
#include <string>
#include <array>
#include <vector>


struct yu {
	string x;//品种
	float  y;//重量
	float  j;//长度

};
using namespace std;

int main(void) {
	struct yu* s1 = new struct yu;

	s1->x = { "草鱼" };
	s1->y = 5.6;
	s1->j = 15.4;
	
	cout << s1->x <<"  " << s1->y << "KG  " << s1->j << "CM" << endl;
	
	delete s1;
	system("pause");
	return 0;
}

这是报错的源代码,编译器没有任何报错,但是一编译就出问题,我看了半天才发现原来是struct中的string 前面没有加std::以为我在mani函数前加了using namespace std;
但是我定义struct的时候定义在了using namespace std;前面,所以导致了“未知重写说明符”

改进方法

1.要么在struct结构体中的string前面加上std::
2.把using namespace std;放在struct结构体前面

改进后的代码

#include <iostream>
#include <Windows.h>
#include <string>
#include <array>
#include <vector>

using namespace std;
struct yu {
	string x;//品种
	float  y;//重量
	float  j;//长度

};

int main(void) {
	struct yu* s1 = new struct yu;

	s1->x = { "草鱼" };
	s1->y = 5.6;
	s1->j = 15.4;
	
	cout << s1->x <<"  " << s1->y << "KG  " << s1->j << "CM" << endl;
	
	delete s1;
	system("pause");
	return 0;
}

问题2 : 没有与参数列表匹配的构造函数

今天敲代码遇到一个很费解的问题,明明写了构造函数,也对的上,但是编译器报错
在这里插入图片描述

问题代码

//构造函数
Father(string &name,int age);

//这是构造函数的实现
Father::Father(string &name,int age) {
this->name = name;
this->age = age;
}

//这是对象创建
Father zyy(“智羊羊”, 42);

问题所在

TMD居然说不匹配,后面经过一系类研究,终于发现问题所在了
问题就在Father(string &name,int age);中的string &name中
加了引用,而输入的字符串是const char*类型,定义的字符串是string
类型肯定不匹配

问题原因

因为加上引用,就相当于是直接修改类中name的值,而且不会产生形参副本,
就是不会构建另外一个string
但是去掉引用就没事了,这是因为不加引用会创建一个形参副本,会调用string
的拷贝函数,然后就是拷贝函数内部自动拷贝,自动转类型
意思就是不加引用会产生两个string类型,一个在类的内部,这是两块不同的内存
,内部自己会调用拷贝构造函数
进行拷贝等操作,内部可以操作,但是加引用就相当于是直接操作内部的值C++的机制是不允许的

解决方法

1.最简单的是去掉引用
2.重构构造函数,使用const char*类型
3.传入一个string 类型
string zyy1(“智羊羊”);
Father zyy(zyy1, 42);
在这里插入图片描述
在这里插入图片描述

小笔记

// 子类对象调用方法时, 先在自己定义的方法中去寻找, 如果有, 就调用自己定义的方法
// 如果找不到, 就到父类的方法中去找, 如果有, 就调用父类的这个同名方法
// 如果还是找不到, 就是发生错误!

问题3:文件结束符eof()函数

今天写代码带的时候,发现,我文件里面数据只有三行,但是while()循环却循环了四次,一次读一行,应该读三次就结束的,多读了一次,导致错误

原因

原因是eof函数,是在文件最后面,就比如说我文件里面有三行数据,读三次就没了,当读完第三行的时候,文件内部有一个文件位置指针,读完第三行后,文件指针已经指向eof了,也就是指向文件结束符了,但仅仅是指向了eof文件结束符,并没有读取到eof文件结束符,最后一行读完后,文件位置指针,指向eof后,会在多读一次,然后就遇到eof了,就结束了,文件位置指针指向了eof并不代表读到了eof结束符,eof结束符需要遇到了才会结束,并不是文件位置指针指向了结束,可以简单理解为,一行数据,需要读两次才会结束

解决方法

解决方法就是先读了在判断是否遇到eof结束符,我在代码中是这样写的
while(file.eof()) 这样写,虽然方便,但是就存在着上面的问题,这样写是先
判断是否遇到eof结束符,在读取的,读都没读取,肯定遇不到eof结束符
应该这样写
while(true){
读文件
if(file.eof()){
break;
}
}
先读文件在判断就不会出现上面的问题

错误代码

while (!file.eof()){
		string line;
		string name1;
		char name[64];
		int age;
		int salary;

		getline(file,line);
	
		int ret=sscanf_s(line.c_str(),"性别:男 姓名:%s 年龄:%d 薪资:%d",name,sizeof(name),&age,&salary);
		if (ret <= 0) {
			cout << "男嘉宾数据库信息匹配失败!" << endl;
			exit(1);
		}
		boys.push_back(Boy(name1,age,salary));
		file.close();
	}

改进后代码

while (true){
		string line;
		string name1;
		char name[64];
		int age;
		int salary;

		getline(file,line);
		if (file.eof()) {
			break;
		}
		int ret=sscanf_s(line.c_str(),"性别:男 姓名:%s 年龄:%d 薪资:%d",name,sizeof(name),&age,&salary);
		if (ret <= 0) {
			cout << "男嘉宾数据库信息匹配失败!" << endl;
			exit(1);
		}
		boys.push_back(Boy(name1,age,salary));
		file.close();
	}

问题:4:c语言中的sscanf按指定格式读取数据

sscanf函数中,只要是有字符串,就必须用char类型字符串,不能用string类型字符串,即使,使用了也不会报错,所以要特别注意

int ret=sscanf_s(line.c_str(),"性别:男 姓名:%s 年龄:%d 薪资:%d",name,sizeof(name),&age,&salary);

可以使用一个变量来接收返回值,如上代码中有三个变量,如果全部没问题就会返回3,如果返回值小于或等于0就是读取失败了

错误代码

while (true){
		string line;
		string name1;
		//char name[64];
		int age;
		int salary;

		getline(file,line);
		if (file.eof()) {
			break;
		}
		int ret=sscanf_s(line.c_str(),"性别:男 姓名:%s 年龄:%d 薪资:%d",name1,&age,&salary);
		if (ret <= 0) {
			cout << "男嘉宾数据库信息匹配失败!" << endl;
			exit(1);
		}
		boys.push_back(Boy(name1,age,salary));

改正后代码

while (true){
		string line;
		//string name1;
		char name[64];
		int age;
		int salary;

		getline(file,line);
		if (file.eof()) {
			break;
		}
		int ret=sscanf_s(line.c_str(),"性别:男 姓名:%s 年龄:%d 薪资:%d",name,sizeof(name),&age,&salary);
		if (ret <= 0) {
			cout << "男嘉宾数据库信息匹配失败!" << endl;
			exit(1);
		}

小笔记

sscanf中的所有字符串也就是%s都必须加sizeof()函数计算大小,不然编译器不知道读多少数据,不加sizeof编译器也不会报错,切记
其他类型成员也要加&取地址符

笔记 .h头文件不能相互包含头文件,因为会相互拷贝.cpp文件可以相互包含头文件

笔记 假如有一个boy类,里面有拷贝构造函数和=赋值构造函数

boy f1(数据);
boy f2=(f1);	//调用拷贝构造函数,拷贝构造函数不能连续赋值

笔记 注意这里是调用的拷贝构造函数而不是=赋值构造函数


boy f1(数据);
boy f2;
f2=f1;	

笔记 这里才是调用=赋值构造函数


笔记 =赋值构造函数和拷贝构造函数的区别,是=赋值构造函数可以连续赋值而拷贝构造函数只能赋一个值

boy f1(数据);
boy f2;
boy f3;
f3=f2=f1;	//调用=赋值构造函数,=赋值构造函数可以连续赋值

问题5:出现cout 或者各种不明确的时候解决方法

解决方法就是先把using namespace std;先注释掉,在取消注释

问题6:双向链表错误总结

在双向链表中插入数据的时候一点要注意,修改指针域顺序的先后
在这里插入图片描述
如图,我这里,先把p->prev指向了s
在这里插入图片描述

执行p->prev->next = s;的时候,p->prev不就是指向了自己嘛,这里原本是要把前一个节点的指针域指向自己,这样写,就是把自己的后置指针域,指向自己了,就会导致插入出现问题
正确的写法:
在这里插入图片描述

先使用了,在去修改

问题7:不能将 “LinkNode *” 类型的值分配到 “_LinNode *” 类型的实体

在这里插入图片描述
这里是因为我没有提前定义_LinNode

改进前

在这里插入图片描述

改进后

在这里插入图片描述
使用前需要提前声明

问题8: 不存在从某某数据类型转换某某类的适当构造函数

问题描述

当在一个类中,包含了另外一个类作为自己的数据成员,而且这个类的数据类型是定义成数组的,那么就需要使用初始化列表

问题源代码

#pragma once
#include <string>
#include <sstream>
#include "Engine.h"
#include "Tyre.h"

using namespace std;
class Automobile{
public:
	Automobile();
	Automobile(const string brand,string model,
		unsigned int price, unsigned int actual,
		string GetBrand,float GetSize,float GatAir,	//轮胎参数
		string Getbrand,string Getmodel);			//发动机参数
	~Automobile();

	string getBrand() const;
	string getModel() const;
	unsigned int getPrice() const;
	unsigned int getActual() const;

	string description() const;
private:
	Tyre tyre[4];	//轮胎
	Engine engine;	//发动机

	string brand;	//品牌
	string model;	//型号
	unsigned int price;
	unsigned int actual;	//行驶里程
};


这个问题就是初始化Tyre tyre[4];
这是初始化构造函数

Automobile::Automobile(const string brand, string model, unsigned int price, unsigned int actual,
	string GetBrand, float GetSize, float GatAir, //轮胎
	string Getbrand, string Getmodel) :	//发动机
	engine(Getbrand, Getmodel),
	tyre{(GetBrand,GetSize,GatAir),(GetBrand,GetSize,GatAir),
	(GetBrand,GetSize,GatAir),(GetBrand,GetSize,GatAir), }
{
	this->brand = brand;
	this->model = model;
	this->price = price;
	this->actual = actual;
}

在这里插入图片描述

解决问题

解决问题很简单,只需要使用正确的语法就可以了,语法如下

Automobile::Automobile(const string brand, string model, unsigned int price, unsigned int actual,
	string GetBrand, float GetSize, float GatAir, //轮胎
	string Getbrand, string Getmodel) :	//发动机
	engine(Getbrand, Getmodel),
	tyre{Tyre(GetBrand,GetSize,GatAir),Tyre(GetBrand,GetSize,GatAir),
	Tyre(GetBrand,GetSize,GatAir),Tyre(GetBrand,GetSize,GatAir), }
{
	this->brand = brand;
	this->model = model;
	this->price = price;
	this->actual = actual;
}

using namespace std;笔记

using namespace std; 是一个常见的C++语句,它的作用是将命名空间 std 中的标识符引入当前的作用域,使得可以直接使用 std 命名空间中的标识符,而无需在每个标识符前添加 std:: 前缀。

在C++标准库中,许多标准库的类、函数和对象都定义在 std 命名空间中。例如,std::coutstd::cinstd::string 等都是在 std 命名空间中定义的。

使用 using namespace std; 可以简化代码,使得在使用标准库中的标识符时不需要添加 std:: 前缀,提高了代码的可读性和编写效率。例如,通过使用 using namespace std;,可以直接写 cout << "Hello, world!" << endl; 而不需要写成 std::cout << "Hello, world!" << std::endl;

需要注意的是,using namespace std; 是在全局作用域或函数内部使用的,不推荐在头文件中使用,以避免引入命名冲突或命名污染的问题。在大型项目中,更好的做法是在需要使用的特定作用域内使用 using 语句,或者使用具体的 std 命名空间的成员。例如,可以使用 using std::cout; 来引入 std::cout,而不是一次性引入整个 std 命名空间。

总之,using namespace std; 可以简化代码,但在使用时需要注意命名冲突和代码可读性的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值