我从C++编码开始,我最近遇到了一个问题,我无法真正找到解决方案,因为我不明白我的错误。
我的程序用于将开尔文转换为摄氏度,但它无法连续进行超过 3 个温度。一旦我通过 4,它就会为我提供正确的转换,但内存问题(超出范围?
"xxx"中的错误:双重释放或损坏(输出):0x0000000001c94c40
当我输入超过四个温度时,它会给出一些随机数,这可能是其他地址的值。
这是我的程序。
#include <iostream>
using namespace std;
unsigned int NumberT {0}; //Definition of the global variables
double* Kelvin=new double[NumberT];
double* Celsius=new double[NumberT];
unsigned int i=0;
double* Conversion (double, double, unsigned int) //Conversion function
{
for(unsigned int i=0;i<NumberT;++i)
{
Celsius[i]=Kelvin[i]-273.15;
}
return Celsius;
}
void printTemperatures (double, double, unsigned int) //Print function
{
for(unsigned int i=0;i<NumberT;++i)
{
cout<<"The temperature is "<< Kelvin[i] <<" [K], which is "<< Celsius[i] <<" [C]"<<endl;
}
return;
}
int main () //Main
{
cout<<"How many temperatures do you want to enter?"<<"n";
cin>>NumberT;
cout<<"What are the temperatures?"<<"n";
for (unsigned int i=0;i<NumberT;++i)
{
cin>>Kelvin[i];
}
Conversion (Kelvin[i], Celsius[i], NumberT);
printTemperatures (Kelvin[i], Celsius[i], NumberT);
delete [] Celsius;
delete [] Kelvin;
return 0;
}
所以我真的很高兴知道我的代码出了什么问题,为什么会这样。我听说我们不应该使用全局变量,这也许可以帮助我理解为什么。
顺便说一下,我有兴趣就如何用良好的语法编写正确的代码提供一些建议,而不会遇到范围问题。因为我想学习如何编写一个最"通用"的函数,以便我可以拉取它并在另一个程序中与其他变量一起使用它。
提前感谢您的支持
PS:我正在使用g ++作为编译器和2011 C++标准
现代C++的一个好习惯是永远不要使用手动内存管理 - 如果您在 C++11 或更高版本的代码中看到new
或delete
,这是代码异味的标志。
请改用std::make_shared
/std::make_unique
,使用value types
和std::move
。
参见赫伯·萨特(Herb Sutter)的最新演讲"默认C++中的泄漏自由"。
对于您的特定示例
unsigned int NumberT {0}; //Definition of the global variables
double* Kelvin=new double[NumberT];
您在此处创建一个包含 0 个元素的数组,然后执行大量未分配的内存覆盖,然后尝试释放它。这是行不通的。
在从std::cin
读取NumberT
后,将数组分配移动到 U,它应该会大大改善。
下一个改进是切换到没有全局变量的更函数式的样式(您不需要它们)。
然后切换到使用std::shared_ptr
s。
正如另一个所说。数组初始化是问题所在。 一般来说,由于您不知道元素的初始大小,我会立即考虑向量。在这种情况下,您可以删除"多少个元素...."并引入退出字符或解析 X 分隔值。
当然,使用数组并没有错,但您必须(重新)以正确的大小初始化它们。因此,在您获得NumberT
之后.尽管如此,对于数组与矢量,请检查此数组与矢量
我已经发布了一个使用向量的实现,但仍然基于您的方法。
(注意:此代码效率不高,因为它执行大量矢量复制,并且不会引入新概念。请自行搜索引用和 std::move 的参数)
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<double> ToCelcius(std::vector<double> kelvinValues) //Conversion function
{
std::vector<double> celciusValues;
for (auto value : kelvinValues)
{
celciusValues.push_back(value - 273.15);
}
return celciusValues;
}
void PrintTemperatures(std::vector<double> kelvinSource, std::vector<double> celsiusSource) //Print function
{
for (uint16_t valueIndex = 0; valueIndex < kelvinSource.size(); valueIndex++)
{
std::cout << "The temperature is " << kelvinSource.at(valueIndex) << " [K], which is " << celsiusSource.at(valueIndex)<< " [C]" << std::endl;
}
}
int main() //Main
{
uint16_t numberOfValues;
std::cout << "How many temperatures do you want to enter?" << "n";
std::cin >> numberOfValues;
std::cout << "What are the temperatures?" << "n";
std::vector<double> kelvinValues;
double value;
for (uint16_t i = 0; i< numberOfValues; ++i)
{
if (std::cin >> value) {
kelvinValues.push_back(value);
}
continue;
}
auto celciusValues = ToCelcius(kelvinValues);
PrintTemperatures(kelvinValues, celciusValues);
return 0;
}
您的问题是在进行内存分配时NumberT
0
。
当您执行以下操作时:
double* Kelvin=new double[0];
不执行初始化,因此指针具有不确定的值。 写入和读取此记忆具有不确定的行为。
当您在具有不确定值的指针上使用delete[]
时,您的代码可能会崩溃。
此问题非常适合使用vector<double>
而不是double[]
数组,没有理由不使用此容器提供的动态内存处理工具。
用作此示例:
//Replace arrays with vectors
vector<double> Kelvin;
vector<double> Celsius;
//in your main to read user input
for (unsigned int i=0;i<NumberT;++i)
{
double read;
cin >> read;
Kelvin.push_back(read);
}
//In your conversion function
for (std::vector<double>::iterator it = Kelvin.begin(); it != Kelvin.end(); ++it)
{
Celsius.push_back((*it)-273.15);
}
其他提示:
-你不需要声明全局变量(例如,你可以在main()
开始时声明它)并通过引用传递变量,如下所示:
void Conversion (vector<double> & Kelvin, vector<double> & Celsius);
-当vector
超出范围(在您的main()
结束时)时,他们将为您完成delete
工作。