int main()
{
int j;
std::cin >> i >> j;
int (**ptr)[1];
ptr = new (int*[i][1]);//error
for (int index = 0;index < i;++index)
ptr[index] = new (int[j][1]);
}
I have a compiler error.
Then, how can I allocate int(**)[]?
Problem.
Original code except that I've added the missing #include directive – to avoid wrong guesses about your code, and irrelevant issues being discussed, please do include everything in posted code:
#include <iostream>
int main()
{
int j;
std::cin >> i >> j;
int (**ptr)[1];
ptr = new (int*[i][1]);//error
for (int index = 0;index < i;++index)
ptr[index] = new (int[j][1]);
}
Compiling with MinGW g++ 5.1.0:
C:\my\forums\so\116> g++ --version | find "++"
g++ (tdm64-1) 5.1.0
C:\my\forums\so\116> g++ original.cpp
original.cpp: In function 'int main()':
original.cpp:5:17: error: 'i' was not declared in this scope
std::cin >> i >> j;
^
original.cpp:9:35: error: ISO C++ forbids variable length array [-Wvla]
ptr[index] = new (int[j][1]);
^
original.cpp:9:36: error: non-constant array new length must be specified without parentheses around the type-id [-Wvla]
ptr[index] = new (int[j][1]);
^
C:\my\forums\so\116> _
That compiler detected the following problems:
Missing declaration of variable i.
Inadvertent use of C99 variable length array, VLA, due to syntactical error.
Compiling with Visual C++ 2015 update 2:
C:\my\forums\so\116> cl /nologo- 2>&1 | find "++"
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86
C:\my\forums\so\116> cl original.cpp
original.cpp
original.cpp(5): error C2065: 'i': undeclared identifier
original.cpp(7): error C2065: 'i': undeclared identifier
original.cpp(7): error C2440: '=': cannot convert from 'int *(*)[1]' to 'int (**)[1]'
original.cpp(7): note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
original.cpp(8): error C2065: 'i': undeclared identifier
C:\my\forums\so\116> _
This compiler doesn't support C99 VLAs, and so instead diagnoses
Incompatible types in pointer assignment.
Apparently this is the error message the OP is concerned about, but the OP reported it as
” cannot cast int ()[] to int(**)[]
which is meaningless because one can indeed cast between data pointer types.
So,
The error description in the question is incorrect.
The code has issues (lacking include, lacking variable declaration) in addition to the error singled out by the OP.
It's unclear what the code is meant to do, except in a very abstract sense that allowed advice such as “use a std::vector”.
However, the code snippet
for (int index = 0;index < i;++index)
ptr[index] = new (int[j][1]);
strongly indicates that this is an attempt to do a dynamic size matrix (2D array) of int values, with dimensions specified by the user, and I assume that in the following.
Fix of the original code.
It often helps to name things. In this case, for clarity, we can name the int* type as Int_array_ptr. That indicates the intended usage: not as a pointer to a single int, but as a pointer to the first item of an array of int, i.e. as a pointer to the array.
#include <iostream>
int main()
{
int n_rows;
int n_columns;
std::cin >> n_rows >> n_columns;
using Int_array_ptr = int*;
Int_array_ptr* matrix;
matrix = new Int_array_ptr[n_rows]; // An array of `n_rows` pointers.
for( int i = 0; i < n_rows; ++i )
{
matrix[i] = new int[n_columns](); // The `()` adds zero-initialization.
}
// At this point one can use it like `matrix[row][column] = 42`.
}
The resulting structure is called a jagged array, because it permits the column vectors to be of different lengths (here they're all the same length).
How to do a matrix in general.
A good alternative to matrix-as-jagged-array is to use a single contiguous 1D array as storage, and just provide 2D indexing into this array.
A good to way to manage an array's storage is to use a std::vector.
And a good way to encapsulate an indexing operation plus other array stuff (or most any set of related operations on a common state) is to define a class.
So, this strongly suggests to define a class that provides a 2D indexing operation on a single 1D array whose storage is managed by a std::vector.
The indexing would ideally be via operator[], but as a member operation it can only take 1 argument. And it's a bit of a bother to write e.g. matrix[Location(3,58)] instead of the ideal matrix[3,58] (which would be parsed as use of a comma expression). So, typically operator(), the function call operator, is used instead of [].
It's possible to instead support the notation matrix[3][58], but let's choose the conceptually simpler implementation of operator():
#include <iostream>
#include <vector>
#include <stdlib.h> // EXIT_FAILURE
using namespace std;
class Matrix
{
private:
vector<int> items_;
int n_columns_;
auto index_of( int const row, int const col ) const
-> int
{ return row*n_columns_ + col; }
public:
auto operator()( int const row, int const col )
-> int&
{ return items_[index_of( row, col )]; }
auto operator()( int const row, int const col ) const
-> int
{ return items_[index_of( row, col )]; }
Matrix( int const n_rows, int const n_columns )
: items_( n_rows*n_columns )
, n_columns_( n_columns )
{}
};
auto main() -> int
{
int n_rows;
int n_columns;
std::cin >> n_rows >> n_columns;
if( cin.fail() ) { return EXIT_FAILURE; }
Matrix matrix( n_rows, n_columns );
// At this point one can use it like `matrix( row, column ) = 42`.
}
This is far more code than the original, but
it's reusable code, which saves work,
it's more robust code, with the difficult things (memory management) automated, and
it can even be more efficient, because it manages with a single dynamic allocation.
Seems like you want to allocate 2-D array. So the allocation should be done as:
int i, j; // Initialize some value to i, j.
....
int **ptr = new int*[i];
for(int k = 0; k < i; k++) {
ptr[k] = new int[j];
}
This will make a 2-D array that has i rows and j columns.
You are trying to allocate an array of int (*)[1] objects. You've already noticed that syntax like new int(*)[1] doesn't work because it is parsed as new int followed by the function call operator, so you have to use the new(T) form.
Also, int *[i][1] is not right, because int * is pointer-to-int. Much like you did in int (**ptr)[1], you have to use parentheses to break the * from the int.
So the right syntax for this would be new( int (*[i])[1] ). But unfortunately, the new(T) form is not allowed to contain non-constant expressions inside the parentheses!
Technical information: There is a dedicated grammar (C++14 [dcl.name]/1) for the cases sizeof(T), alignof(T), new(T) and typeid(T) and casts; and it only permits square brackets to be empty or contain a constant-expression inside the square brackets. There is another separate grammar for the new T case ([expr.new]/1) (which knows about [] but not (), and allows non-constant expressions), and both of these are separate to the grammar for parsing declarators in other situations.
So the only solution to this (while retaining the type of ptr) is to use a typedef:
typedef int Arr1[1];
ptr = new Arr1 *[i];
Each row is:
ptr[index] = new int[j][1]; // or "new Arr1[j];"
you have allocate an pointer array, and then each element(pointer) points to an array like
int i = 20, j = 40;
int** ptr = new int*[i];
for (int a = 0; a < i; a++) {
ptr[a] = new int[j];
// ...
delete [] ptr[a];
}
delete [] ptr;
EDIT
back to your code
when you define a type E as int[1];
int j, i;
std::cin >> i >> j;
typedef int E[1];
E **ptr; // int (**ptr)[1];
ptr = new E*[i]; // ptr = new (int*[i][1]);//error
for (int index = 0;index < i;++index)
ptr[index] = new E[j]; // ptr[index] = new (int[j][1]);
so just a pointer to pointer of integer, not like what you said
Related
Error message in text:
I'm studying the book C++ Primer and encountering a problem listed below when coding an answer for one exercise:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int i = 3;
const int ci = 3;
size_t si = 3;
const size_t csi = 3;
int ia[i];
int cia[ci];
int sia[si];
int csia[csi];
int another_a[] = {1,2,3};
int *pi = begin(ia); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [i])
int *pci = begin(cia);
int *psi = begin(sia); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [si])
int *pcsi = begin(csia);
int *p_ano = begin(another_a);
vector<int> v = {1,3,4};
const int m = v.size();
const size_t n = v.size();
int ma[m];
int na[n];
int *pm = begin(ma); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [m])
int *pn = begin(na); // error here
// no instance of overloaded function "begin" matches the argument list --
// argument types are: (int [n])
system("pause");
return 0;
}
I can understand that the first two errors are because that those two arrays are not defined using an constant variable.
But why the last two, even if I have converted the size of the vector into a constant variable, the compiler still reports an error?
I'm quite confused about this, I would appreciate a lot for your kindly answer or discussion no matter it works or not.
First and foremost, you are using a compiler extension, but more on that later.
The standard begin overload which works for you is a template that accepts a reference to an array with a size that is a constant expression. In a nutshell, constant expressions are those expressions that a compiler can evaluate and know the value of during compilation.
A constant integer initialized with a constant expression like const int ci = 3;, can be used wherever a constant expression is required. So ci is, for all intents an purposes, a constant expression itself (equal to 3).
Modern C++ has a way to make such varaibles stand out as intended constant expressions, it's the constexpr specifier. So you could define ci like this:
constexpr int ci = 3;
It's exactly like your original code. But the same will not work for const int m = v.size();. Because constexpr requires a true constant expression as an initializer, unlike const. For a const variable is not necessarily a constant expression. It can just be a run-time variable that you cannot modify. And this is the case with m.
Because m is not a constant expression, what you defined is a variable length array. A C feature that is sometimes introduced as an extension by C++ compilers. And it doesn't gel with the std::begin template, which expects the array extent to be a constant expression.
Declaring arrays with non constant indexes isn't standard c++.
If you need dynamically sized arrays use std::vector.
Declaring a variable as const doesn't make it a compile time constant (required to declare a fixed sized array) it just means you can't modify it after it is declared.
I'm trying to define a multidimensional array using my constant field as its dimension, but I'm getting a compilation error saying that the expression is not constant. Is there any other way to do this so I can use a constant field defined in constructor initialization list as an array dimension?
Translation for English-speaking majority:
class FunctionWave2D : public DisallowedDomainPoints
{
protected:
double th;
double l; a
double d, dd;
const int number_sqrt; //here's the constant
double **second_derivatives;
protected:
bool elasticTenstionOnly;
public:
FunctionWave2D(int number, double elasticModulus, double dampingFactor, double oscillationDampingFactor, double length)
:DisallowedDomainPoints(number * LAYER_COUNT),
th(elasticModulus), d(dampingFactor), dd(oscillationDampingFactor),
elasticTensionOnly(false),
l(length/(sqrt(number)-1)),
number_sqrt(sqrt(number))
{
second_derivatives = new double[number_sqrt][number_sqrt][LAYER_COUNT];
//(...)
In C++, the term "constant expression" specifically refers to an expression whose value is known at compile-time. It's not the same as a const variable. For example, 137 is a constant expression, but in this code:
int function(int x) {
const int k = x;
}
The value of k is not a constant expression, since its value can't be determined at compile-time.
In your case, you have a data member declared as
const int ilosc_sqrt; //here's the constant
Even though this is marked const, its value is not known at compile-time. It is initialized in the initializer list as
ilosc_sqrt(sqrt(ilosc))
This value can't be determined until the program is actually run, hence the error. (Note that the new C++11 constexpr keyword is designed, among other things, to make constant expressions a lot easier to identify in source code and to make it possible to do more advance compile-time computations with constants.)
To fix this, you will either need to split up your initialization into smaller steps:
drugie_pochodne = new double**[ilosc_sqrt];
for (int i = 0; i < ilosc_sqrt; i++) {
drugie_pochodne[i] = new double*[ilosc_sqrt];
for (int j = 0; j < ilosc_sqrt; j++) {
drugie_pochodne[j] = new double[ILOSC_WARSTW];
}
}
Or use a library like Boost.MultiArray, which supports a cleaner initialization syntax.
Hope this helps!
An array bound has to be a compile-time constant. A non-static const data member is not a compile-time constant; it gets its value at runtime, when the object is constructed.
So, basically, if you need to set the size of that array at runtime you'll have to build up all the pieces with operator new[]. Essentially,
int **data_2d = new int*[runtime_size];
for (int i = 0; i < runtime_size; ++i)
data_2d[i] = new int[runtime_size];
The extension to a 3d-array is straightforward.
I am new to the pointer usage and encountered a compiling error gcc
Here is my code:
class Pt
{
public:
int Ph;
};
Pt *Pa;
Pa = new T[N];
for(int i=0;i < N; i++)
Pa[i].Ph=0;`
and the error message:
error: expected type-specifier before ‘T’
error: cannot convert ‘int*’ to ‘Pt*’ in assignment
What I am trying to do is to declare a class which contains an int which is 0 initially ,and provide a mem space to N of that class.
Thanks for the time reading my questions,any help will be very appreciated.
Without a user-defined constructor, you can value-initialize an object like so:
Pt a = Pt();
a is an object of type Pt with its int member set to 0.
To declare an array, use:
Pt* Pa = new Pt[N]();
The N objects in the array are value-initialized, so the following for loop is no longer necessary.
To write C++ code, just do
std::vector<Pt> Pa(N);
You did not declare any type called T; probably you have other errors/warnings before that complain about that.
You have multiple mistakes
1) Pa[i] would hold a pointer to pt. so consider writing Pa[i]->Ph
2) What you want to do here is not clear:
Pa = new T[N];
Try something like this:
class Pt
{
public:
Pt() : Ph(0)
{ ; }
int Ph;
};
#define CAPCITY 15U
int main(void)
{
Pt Pa[CAPACITY];
for (unsigned i = 0; i < CAPACITY; ++i)
{
std::cout << "Pa[" << i << "].Ph = " << Pa[i].Ph << endl;
}
return EXIT_SUCCESS;
}
The initializer list of class Pt handles setting the field Ph to zero when the class is constructed by the array.
BTW, you don't need to use new for each variable instance, unlike other languages.
I highly recommend using more letters for your class and variable names and try to use something meaningful. Two letters are faster to type, but if that is your justification, take a keyboarding class.
my code:
#include <iostream>
using namespace std;
int main() {
int n=5;
int a[n][n];
a[1][1]=5;
return 0;
}
I got this error when trying to watch the expression a[1][1] in eclipse on line 6:
Failed to execute MI command:
-data-evaluate-expression a[1][1] Error message from debugger back end:
Cannot perform pointer math on
incomplete types, try casting to a
known type, or void *.
i guess it's returned from gdb? however, i don't know why i can't watch that value? Isn't "a" is a normal multi-dimensional array?
For some odd reasons this isn't valid C++ unless you make it
const int n = 5;
Otherwise the array size is formally unknown until runtime.
C++ doesn't suppose variable length array (VLA). So your code is not standard conformant code.
It will not compile if you compile it with g++ -pedantic. The array size must be constant expression. But in your code, its not.
So write:
const int n=5; //now this becomes constant!
int a[n][n]; //the size should be constant expression.
Lets try the above code, as its completely Standard conformant code now.
why not better do it a dynamic 2d array? In that case you do not have to make the n constant, and you can determine the size dynamically.
int **arr, n;
arr = new int * [n]; // allocate the 1st dimension. each location will hole one array
for (i=0; i<n; i++)
{
arr[i] = new int [n]; // allocate the 2nd dimension of one single n element array
// and assign it to the above allocated locations.
}
Now you can access the aray as arr[i][j]
To free to the reverse
for (i=0; i<n; i++)
{
delete [] arr[i]; // first delete all the 2nd dimenstion (arr[i])
}
delete [] arr; // then delete the location arays which held the address of the above (arr)
In boost/utility/swap.hpp I have found this piece of code:
template<class T, std::size_t N>
void swap_impl(T (& left)[N], T (& right)[N])
{
for (std::size_t i = 0; i < N; ++i)
{
::boost_swap_impl::swap_impl(left[i], right[i]);
}
}
What are left and right? Are they references to arrays? Is this code allowed by C++ ISO standard 2003 or later?
A reference to an array of type T and length N.
This is a natural extension of C's pointer-to-array syntax, and is supported by C++03.
You could use cdecl.org to try to parse these complex type declarations.
What are left and right? Are they references to arrays? Is this code allowed by C++ ISO standard 2003 or later?
Yes. They're references to arrays.
That means, you can call swap_impl as:
int a[10]; //array
int b[10];
//...
swap_impl(a,b); //correct
But you cannot call swap_impl as:
int *a = new int[10]; //pointer
int *b = new int[10];
//...
swap_impl(a,b); //compilation error
Also note that you cannot do even this:
int a[10];
int b[11];
//...
swap_impl(a,b); //compilation error - a and b are arrays of different size!
Important point:
- Not only arguments must be arrays, but the arrays must be of same size!
This is the way to declare a reference to an array of T (of size N) named left and right. The code is legal C++.
This allows you to pass in:
int ones[5] = { 1,1,1,1,1 };
int twos[5] = { 2,2,2,2,2 };
swap_impl(ones, twos);
Then template type inference will know that you have T = int and N = 5 and do the in-place swap. If you mismatch the types or the size, you get a handy compilation failure.
Yes this is standard C++ allowed from very early on (its basically C with the addition of a reference).
Using typedefs makes it easier to read:
int main()
{
typedef int (&MyArray)[4];
int data[4];
MyArray dataRef = data;
}
It sort of mirrors the function typedef
typedef int (*MyFunc)();