I would like to define int array in which first dimension is choosen dynamically but second is static --
something like int array[][8]. Unfortunatelly I can not allocate such array dynamically. int ary[][8] = new int[11][8]; Produces error:
error: initializer fails to determine size of ‘array’
6 | int array[][8] = new int[11][8];
| ^~~~~~~~~~~~~~
2d.cpp:6:20: error: array must be initialized with a brace-enclosed initializer
or when I try following code:
int array[][8] = new int*[11];
array[0] = new int[8];
I get
2d2.cpp:6:22: error: initializer fails to determine size of ‘array’
6 | int array[][8] = new int*[11];
| ^~~~~~~~~~~~
2d2.cpp:6:22: error: array must be initialized with a brace-enclosed initializer
2d2.cpp:7:25: error: incompatible types in assignment of ‘int*’ to ‘int [8]’
7 | array[0] = new int[8];
Is that even possible in c++?
Just use std::vector and std::array:
#include <vector>
#include <array>
#include <iostream>
int main()
{
using MyArray = std::vector<std::array<int, 8>>;
MyArray arr {11};
for (int i {0}; i < 8; ++i)
arr[i][i] = i;
for (const auto& v : arr) {
for (auto x : v) {
std::cout << x << " ";
}
std::cout << std::endl;
}
}
Live On Coliru
I will answer my own question:
int (*array)[8] = new int[11][8];
I forgot how bad C++ rules for creating type definitions -- especially including pointers, arrays and function pointers -- are. I added missing parentheses around array and now it is fine.
Related
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
I am having trouble with a function that takes a pointer to a fixed array. I have a simple pointer and the compiler will not allow me to static_cast it to the pointer-to-array type.
Here's some example code:
int main()
{
typedef int (*Arr3)[3];
int a[3] = {1,2,3};
int* p = &a[0];
Arr3 b = static_cast<Arr3>(p);
}
Error message:
prog.cpp:11:10: error: static_cast from 'int *' to 'Arr3' (aka 'int (*)[3]') is not allowed
Arr3 b = static_cast<Arr3>(p);
^~~~~~~~~~~~~~~~~~~~
1 error generated.
I am pretty sure I could use a reinterpret_cast, but is that really my only option here? Or am I missing something?
You can't exactly static_cast here, but there is a trick that’s more type-safe than reinterpret_cast:
#include <iostream>
using std::cout;
typedef int (*arr3p)[3];
typedef int arr3[3];
inline arr3& to_arr3(arr3 p)
{
return *(arr3p)(p);
}
inline arr3p to_arr3p(arr3 p)
{
return (arr3p)(p);
}
int main() {
arr3 a = {1, 2, 3};
int *p = &a[0];
arr3p foo = &to_arr3(p);
cout << (*foo)[0] << ", ";
arr3p bar = to_arr3p(p);
cout << (*bar)[1] << ", ";
arr3& baz = to_arr3(p);
cout << baz[2] << std::endl;
return 0;
}
I believe your cast is incorrect
Arr3 b = static_cast<Arr3>(p);
should be
Arr3 b = static_cast<Arr3>(&a);
In fact, the cast is unnecessary. Simply
Arr3 b = &a;
will do.
One-dimension array is compatible with pointer, but that's not true for multi-dimension array. For example,
int *p = (int*)1;
int (*s)[3] = (int (*)[3])2;
printf("%d,%d\n", sizeof(int*), sizeof(int (*)[3]));
printf("%d,%d\n", ++p,++s);
The output is:
8,8
5,14
They are both pointer type, so their size is 8 bytes int 64-bit machine.++s, this array pointer will advance 3 elements, but ++p, p will only advance 1 element. When we declare pointer array, we must specify size in every dimension except 1th dimension. The compiler needs to known that information to compute pointer arithmetic operation.
Below is a small script that prints the sums of the numbers 1 to n, for n = 1,...,20.
#include <iostream>
#include <array>
using namespace std;
int test(int n)
{
array<int,n> myArray;
for (int iii = 0; iii < n; iii++)
myArray[iii] = iii+1;
int nSum;
for (int iii = 0; iii < n; iii++)
nSum += myArray[iii];
return nSum;
}
int main()
{
for (int n = 1; n <= 20; n++)
cout << test(n) << endl;
return 0;
}
Of course, this won't compile:
Main.cpp: In function ‘int test(long unsigned int)’:
Main.cpp:9:13: error: ‘n’ is not a constant expression
array<int,n> myArray;
^
Main.cpp:9:13: note: in template argument for type ‘long unsigned int’
Main.cpp:9:22: error: invalid type in declaration before ‘;’ token
array<int,n> myArray;
^
Main.cpp:11:26: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (int iii = 0; iii < n; iii++)
^
Main.cpp:12:14: error: invalid types ‘int[int]’ for array subscript
myArray[iii] = iii+1;
^
Main.cpp:16:26: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
for (int iii = 0; iii < n; iii++)
^
Main.cpp:17:22: error: invalid types ‘int[int]’ for array subscript
nSum += myArray[iii];
^
make: *** [Main.o] Error 1
The problem seems to be (among other things) that n isn't a constant expression, and I get why that is a problem, but I have no idea how to solve it.
I know how to instantiate "regular" arrays with the new function, but I don't understand how it is possible with the array class.
How do I make the test function treat n as a constant?
You have basically two options.
As you already mentioned, std::array needs a compile-time size. So make it known at compile-time! This can be done by converting it to a template parameter.
Change
int test(int n)
{
.
.
.
}
to
template<int n>
int test()
{
.
.
.
}
The problem is that it then has to be called with test<n>() instead of test(n) and this again requires the n in the caller code to be known at compile-time, too, which is not the case with a for-loop. If you know your loop's upper bound during compile-time (like in your current code snippet), it can be done, but it's a bit complicated. And if it's not known, i.e. a user input, you can't use this solution at all.
So this is not a good option here.
Don't use std::array but a container type which doesn't require the size at compile-time but during runtime. A heap-allocated raw array (new int[n]), as you mentioned, is an option, but it's not very C++-ish. Use std::vector instead!
For this, simply change
array<int,n> myArray;
to
vector<int> myArray(n);
PS. In the future, there probably will be std::dynarray (proposed container type) which fits exactly that purpose a bit better than std::vector currently does. It's reflecting the purpose of new int[n] where n is known at runtime but constant during the lifetime of the array, filling the gap between std::array and std::vector. Yet in almost all cases std::vector will do just fine!
You can use a vector instead;
#include <vector>
vector<int> myArray (n); // n zero-initialized elements
use the operator[] like you are using the array.
So I am new to c++ and I have written this piece of c++ code.
#include <iostream>
using namespace std;
int** mat_mult(int mat1[2][2], int mat2[2][2]){
int mat3[2][2] = {{0,0},{0,0}};
for(int i(0);i<2;i++){
for(int j(0);j<2;j++){
for(int k(0);k<2;k++){
mat3[i][j] += mat1[i][k]*mat2[k][j];
}
}
}
return mat3;
}
int** mat_pow(int mat[2][2], int n){
int mat1[2][2] = {{1,0},{0,1}};
while(n){
if(n%2==1){
mat1 = mat_mult(mat, mat1);
}
mat = mat_mult(mat,mat);
n >>= 1;
}
return mat1;
}
int specialFib(int n){
int mat[2][2] = {{0,1},{2,1}};
mat = mat_pow(mat,n);
return (mat[0][0]*2 + mat[0][1]);
}
int main(){
cout << specialFib(3) << endl;
return 0;
}
But compiling this gives me this error,
prog.cpp: In function 'int** mat_mult(int (*)[2], int (*)[2])':
prog.cpp:13: error: cannot convert 'int (*)[2]' to 'int**' in return
prog.cpp: In function 'int** mat_pow(int (*)[2], int)':
prog.cpp:20: error: incompatible types in assignment of 'int**' to 'int [2][2]'
prog.cpp:22: error: cannot convert 'int**' to 'int (*)[2]' in assignment
prog.cpp:25: error: cannot convert 'int (*)[2]' to 'int**' in return
prog.cpp: In function 'int specialFib(int)':
prog.cpp:30: error: incompatible types in assignment of 'int**' to 'int [2][2]'
I tried to find any solution, but no luck. :(
int **mat3 = {{0,0},{0,0}};
This makes mat3 a pointer to a pointer to an integer. You can initialize it to any pointer to a pointer to an integer you want. But {{0,0},{0,0}} is an array, not a pointer to a pointer to an integer.
Perhaps you want:
int mat3[2][2] ...
If you want to dynamically allocate your 2d array then your code should look like that:
int** mat3 = new int*[2];
for(int i = 0; i < 2; ++i)
mat3[i] = new int[2];
and then deallocation:
for(int i = 0; i < 2; ++i) {
delete [] mat3[i];
}
delete [] mat3;
also you must manually initialize its values
as in other answers, I would never use such dynamic arrays, but vector of vectors
You tagged this question C++ so use C++!
You can either use std::array<std::array<int,Xsize>, Ysixe>> if you know both sizes at compile time or std::vector<std::vector<int>> otherwise.
In C++, arrays are very special collection facilities. You should definitely read more about standard container classes and then write everything new from scratch -- Trust me, it will save time! :)
Objects of standard container classes can be returned from a function in the same easy way as primitive types (like int or double).
std::vector<std::vector<int> > GetInts()
{
// ...
return v;
}
Your problem will simply disappear.
Pointers and arrays imply low-level memory management; that is certainly not beginners stuff!
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.