错误C2440无法将void *转换为double **或double *

时间:2017-04-17 17:33:30

标签: c++ visual-studio

我在使用C ++编写代码时遇到问题。编译器发给我错误C2440,我不知道为什么。以下是代码,问题出现在void main ()区域,特别是行R = callocR[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);
}    

3 个答案:

答案 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.它管理自己的内存,包括根据需要删除和调整大小。它非常火,忘了。

Documentation on std::vector

此后出现了各种智能指针,尤其是

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); - ?!
  • 如果使用malloc / calloc / realloc,则必须使用C ++转换返回的void指针。
  • 不要忘记删除已分配的内存。

例如:

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);
}