我在使用C ++编写代码时遇到问题。编译器发给我错误C2440,我不知道为什么。以下是代码,问题出现在void main ()
区域,特别是行R = calloc
和R[i] = calloc
。谢谢你的回答。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
using namespace std;
double F (double x);
double G (double x);
double P (double x);
void romberg(double f(double), double a, double b, int n, double **R);
double F (double x)
{
return (1.0/ (1.0 + x));
}
double G (double x)
{
return (exp(x));
}
double P (double x)
{
return (sqrt(x));
}
void romberg(double f(double), double a, double b, int n, double **R)
{
int i, j, k;
double h, sum;
h = b - a;
R[0][0] = 0.5 * h * (f(a) + f(b));
cout << " R[0][0] = ";
cin >> R[0][0];
for (i = 1; i <= n; i++)
{
h *= 0.5;
sum = 0;
for (k = 1; k <= pow(2,i)-1; k+=2)
{
sum += f(a + k * h);
}
R[i][0] = 0.5 * R[i-1][0] + sum * h;
cout << "R[i][0] = ";
cin>>i, R[i][0];
for (j = 1; j <= i; j++)
{
R[i][j] = R[i][j-1] + (R[i][j-1] - R[i-1][j-1]) / (pow(4,j)-1);
cout << " R[i][j] = ";
cin>>i, j, R[i][j];
}
}
}
void main()
{
int n = 10;
int i;
double **R;
double F(double), G(double), P(double);
R = calloc((n+1), sizeof(double *));
for (i = 0; i <= n; i++)
R[i] = calloc((n+1), sizeof(double));
cout<<"The first function is F(x) = 1/(1 + x)\n";
romberg(F, 0.0, 2.0,3, R);
cout<<"The second function is G(x) = exp(x)\n";
romberg(G,-1.0, 1.0, 4, R);
cout<<"The third function is P(x) = sqrt(x)\n";
romberg(P,0.0, 1.0, 7, R);
}
答案 0 :(得分:1)
C ++比C(和calloc
是C函数)有更严格的规则,关于执行赋值时编译器将为您执行的转换类型。将void *
分配给void *
以外的任何内容都需要您告诉编译器,&#34;是的,这看起来很愚蠢并且有风险,但我知道我在做什么。&#34; < / p>
通过C和C ++编程的历史,有很长时间的拙劣隐式转换历史。使这个转换成为错误至少会让程序员在继续之前停下来思考它。
在这种情况下,最合乎逻辑的简单解决方案是
std::vector<std::vector<double>> descriptive_name_goes_here(n+1, std::vector<double>(n+1));
这将分配所有必需的存储并将其全部设置为0.它管理自己的内存,包括根据需要删除和调整大小。它非常火,忘了。
此后出现了各种智能指针,尤其是
std::unique_ptr<std::unique_ptr<double[]>[]> descriptive_name_goes_here =
std::make_unique<std::unique_ptr<double[]>[]>(n+1);
和for
循环到make_unique
内部维度,并将所有已分配的值分配给0。
unique_ptr
处理内存管理,确保在不再引用时分配的数据被销毁。作为成员变量,unique_ptr
可以使容器中的对象传递或存储在颈部疼痛,因为如果可以复制unique_ptr
,那么它不一定是唯一的,会吗? vector
为你处理废话。
Documentation on std::unique_ptr
Documentation on std::make_unique
如果上述两个是不可能的,到2017年,这应该是一个完全人为的限制,或者是对需要遗留编译器的遗留代码进行操作的结果,请使用
double ** descriptive_name_goes_here = new double*[n+1]
和for
循环到new
内部维度,并将所有已分配的值分配给0.
此选项将所有内存管理责任放在程序员身上,甚至编程之神偶尔会错过需要delete[]
的情况。它还意味着程序员负责支持Rules of Three and Five以确保任何包装类中的销毁,复制,赋值和移动逻辑是正确的。
这是低级别工作的绝对最后手段,例如编写vector
或智能指针。
{+ 1}}在c ++中唯一的位置是奇怪的边缘情况,坦率地说,我现在无法想到。很可能没有。
我可以建议用一维数组制作一个简单的矩阵类吗?数组方法看起来很漂亮,简单而优雅,并且通常具有非常糟糕的缓存性能。这些阵列阵列(或矢量矢量)中的每一个都包含在存储器中散布的许多不同的存储器块。这使得CPU更难以预测下一步的位置以及要加载的数据。每次CPU必须停止并等待加载缓存时,您的性能下降都会以数量级进行测量。
calloc
这很容易变成用于概括存储数据的模板
答案 1 :(得分:0)
在c ++中有一个vector
容器(一个C ++标准模板),它类似于一个数组,但有一个例外,它会自动处理它自己的存储需求,以防它增长
您需要切换到RAII
例如:
由此:
double **R;
R = calloc((n+1), sizeof(double *));
for (i = 0; i <= n; i++)
R[i] = calloc((n+1), sizeof(double));
要:
vector <vector <double> >R(n+1, vector<int>(n+1));
你不需要释放已分配的内存,当向量超出范围时它将是免费的。
您只需要将romberg
的签名更改为:
void romberg(double f(double), double a, double b, int n, vector <vector <double> >R)
您也可以阅读RAII c ++概念。
PS:只需从void *
明确地转换为double *
和double **
,就可以避免您获得的错误,但这样可能会导致内存泄漏等更多复杂问题等
答案 2 :(得分:-1)
你的主要看起来很奇怪:
void main
代替int main
double F(double), G(double), P(double);
- ?!例如:
int main()
{
const int n = 10;
double **R;
R = new double*[n+1];
for (int i = 0; i <= n; i++)
R[i] = new double[n+1];
cout << "The first function is F(x) = 1/(1 + x)\n";
romberg(F, 0.0, 2.0,3, R);
cout << "The second function is G(x) = exp(x)\n";
romberg(G,-1.0, 1.0, 4, R);
cout<<"The third function is P(x) = sqrt(x)\n";
romberg(P,0.0, 1.0, 7, R);
// free allocated memory
for (int i = 0; i <= n; i++)
delete[] R[i];
delete[] R;
}
请注意,inits double的循环不会将它们全部设置为0.
或者更好地使用std :: vector并更新其他代码以使用它:
#include <vector>
using namespace std;
int main()
{
const int n = 10;
vector<vector<double> > R(n+1, vector<double>(n+1));
cout << "The first function is F(x) = 1/(1 + x)\n";
romberg(F, 0.0, 2.0,3, R);
cout << "The second function is G(x) = exp(x)\n";
romberg(G,-1.0, 1.0, 4, R);
cout<<"The third function is P(x) = sqrt(x)\n";
romberg(P,0.0, 1.0, 7, R);
}