0

I have the following code below,

std::complex<double>** x;
x = calloc(10,sizeof(complex <double> *));

This code failed to compile with the following error message.

error: invalid conversion from 'void*' to 'std::complex<double>*' [-fpermissive]

How can I successfully compile? Why does this code fail to compile?

Kaustav Ray
  • 744
  • 6
  • 20
Eri Isurugi
  • 49
  • 1
  • 4
  • 8
    Use `std::vector`. – milleniumbug Dec 31 '13 at 13:29
  • 4
    Just grab a [good C++ book](http://stackoverflow.com/q/388242/1782465). Mixing C and C++ is never a good idea. But to answer you, just use `new[]` or `std::vector`. – Angew is no longer proud of SO Dec 31 '13 at 13:29
  • +1 to counter unexplained downvotes. the question is good. one should not try to "punish" questions asked by novices: everyone has been a novice at some time (but not everyone is able to ask a good question). – Cheers and hth. - Alf Dec 31 '13 at 14:09
  • @Cheersandhth.-Alf, I didn't downvote, but the question really show lack of any research whatsoever. That's a reason for downvote, don't you think? The OP doesn't tell at all what he has done to figure out what the error means and why he's given this error. Besides, [sympathy upvote is not how the system is meant to be used](http://meta.stackexchange.com/q/87487/169090). – Shahbaz Dec 31 '13 at 18:32
  • @Shabaz: childish downvotes is not how the system is meant to be used. and in particular, childish authority fallacies is not how real people argue their points of view. it's a very ungood example you set. – Cheers and hth. - Alf Dec 31 '13 at 18:42

5 Answers5

6

You're trying to write C++ as if it were C, which allows dangerous implicit conversions like this.

To allocate a dynamic array of size 10, use

std::vector<std::complex<double>> numbers(10);

and, if you really want a pointer to the first element

x = numbers.data();
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Or `std::addressof(numbers[0])`. – Shoe Dec 31 '13 at 13:41
  • That is not really the same structure, in the original the `x` variable is a pointer to pointers that would map better to `std::vector*>`. Not saying that the code might not benefit with this simplification though... – David Rodríguez - dribeas Dec 31 '13 at 13:58
  • @DavidRodríguez-dribeas: The declaration of `x` was missing when I wrote the answer; I inferred its type from the error message. If the OP actually wants a 2-dimensional array, then generalising this to a vector of vectors isn't a bad option (although there may be better options). – Mike Seymour Dec 31 '13 at 14:06
4

In C++, void * doesn't automatically cast to other pointers (unlike in C). So if you use malloc and the family in C++, you need to cast the result yourself.

However, you should note that malloc doesn't understand C++'s constructors. So if you want to allocate a C++ object (not a C struct for example, or more precisely a POD), you should use new (and delete/delete[] correspondingly) which correctly takes care of constructors and destructors.

Alternatively, you can use one of the many structures provided by the standard library, such as std::vector.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
2

The problems.

This code from the question, …

    x = calloc(10,sizeof(complex <double> *));

is ungood for two reasons:

  • unlike C, C++ does not have an implicit conversion from void*, and

  • creating a jagged array by means of C++ new is bad enough, doing it with the C level allocation functions is general an abomination (except where required by some function that one needs to call).

The first bullet point is why it fails to compile in C++.


What to do.

A purely technical fix is to use a cast, and then preferably a C++ named cast such as static_cast or reinterpret_cast. Both work fine in practice for conversion from void*. However, in my opinion reinterpret_cast expresses the conceptual operation more correctly, so I’d choose that – if I chose to cast.

A slightly better solution is to use C++ new instead of C calloc. With new you have to add an empty parenthesis at the end to to get the guaranteed zero-initialization of calloc. But the main problem is still that it's every low level and difficult (much work) to get right.

A much better general solution is to use a C++ container class.

The standard library offers std::vector, with which the jagged array can be constructed like this:

typedef complex<double> Complex;
typedef vector<Complex> ComplexVec;
typedef vector<ComplexVec> ComplexVec2D;

ComplexVec2D x( 10 );

Then each ComplexVec can just be resized, since std::vector is a dynamically sized array.


What to do if you really want a MATRIX.

If you really want a matrix, i.e. an array of arrays of equal length, then instead of a jagged array consider a C++ class which just provides 2D indexing into a single vector.

In C++03-style it can go like this (off the cuff code):

typedef complex<double> Complex;

class ComplexMatric
{
private:
    vector<Complex> items_;
    int             width_;

public:
    Complex& operator()( int x, int y )
    { return items_[y*width_ + x]; }

    Complex const& operator()( int x, int y ) const
    { return items_[y*width_ + x]; }

    ComplexMatrix( int w, int h )
        : items_( w*h )
        , width_( w )
    {}
};

And you'd use it like this:

ComplexMatrix x( 10, some_height );

This includes doing proper allocation and deallocation, and even supporting copying by assignment.

Disclaimer: code untouched by compiler's hands.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
1

Instead of using calloc, try using new[] operator instead. This is the C++ way to dynamically create an array.

x = new complex<double>[10];

The new[] returns a pointer to whatever type followed the operator, in this case it is a pointer with type complex<double> which points to an array of complex<double> with 10 elements inside.

Be aware, though, you have to use delete[] operator to deallocate the memory (not free()). Otherwise no one know what's going to happen :-).

delete[] x;
  • Even better: instead of using `new[]` and `delete[]`, just use `std::vector` :) – Andy Prowl Dec 31 '13 at 13:46
  • Well I'd say an array is not a vector. If the OP really need an array, creating an array might be a better choice. It really depends. But I agree that, in general, using vector is better. – Wutipong Wongsakuldej Dec 31 '13 at 13:49
0

Assuming your x is of type std::complex<double>*, you get this error because calloc returns a void pointer. Without -fpermissive implicit casts are not allowed. So, you'll have to cast between void* and std::complex<double>*. However, in C++ it is recommended to use new instead of malloc or calloc, and personally I'd recommend you to use std::vector.

Sebastian
  • 8,046
  • 2
  • 34
  • 58
  • x is defined std::complex **x . I want that x is Two-dimensional array – Eri Isurugi Dec 31 '13 at 13:31
  • Then this is a bit more complex, have a look at [How do I declare a 2d array in C++ using new?](http://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new). – Sebastian Dec 31 '13 at 13:41
  • 1
    Please *don't* look at that question, since it's using a bunch of `new`. – Puppy Dec 31 '13 at 13:44
  • @DeadMG well, he asked for it and I answered, I never said it's the best solution for his problem. – Sebastian Dec 31 '13 at 13:46