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.
Related
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.
What is the problem with my for-loop? It is inside a helper function but the error "Member reference base type 'int [13]' is not a structure or union" is happening across my code. The 'int [13] changes to int[10] when I am using a 10 integer array, so I assume it is a problem there. Here are two examples:
int newisbn13[13];
newisbn13[0] = 9;
newisbn13[1] = 7;
newisbn13[2] = 8;
for (int p = 3; p < newisbn13.length() - 1; p++)
{
newisbn13[p] = isbn10[p-3];
}
ERROR: Member reference base type 'int [13]' is not a structure or union
Also:
int calc_check_digit_13(int input[], int size) {
int sum = 0;
for (int i = 0; i < input.length(); i++)
{
int tempnum = 0;
if (i % 2 == 0)
{
tempnum = input[i];
}
else if (i % 2 == 1)
{
tempnum = input[i] * 3;
}
sum = tempnum + sum;
}
etc. etc. etc.
}
ERROR: Member reference base type 'int *' is not a structure or union
What is causing this error throughout my code? Thank you for your help.
newisbn13 is an array and in contrast to other languages like C# or Java it does not know its size.
You need to use sizeof(newisbn13) instead.
Or since c++17 you can use std::size(newisbn13).
However this will not work for calc_check_digit_13. Because input will decay to a pointer and neither sizeof nor std::size will work there. But probably the parameter size is what you want to use.
for (int i = 0; i < size; i++) {...}
For your first block of code, you make a call to a non-existent member function of type int. In C++, int is a primitive type and has no member functions or member variables.
For the second block, you're calling the same function but on a pointer to an array of ints, so the type is int * and not int[13], but its pretty much the exact same problem.
As churill pointed out, you can use sizeof(int[]) or std::size(int[]) to find the number of elements in the array. If you need a container for integers, I would recommend using std::vector<int> to manage your ints. This template class has tons of quality-of-life methods such as size() that can assist with what you might want to do.
This question already has answers here:
how to pass 2 dimensional array if both dimensions are unknown at compile time
(5 answers)
Closed 6 years ago.
I get the following error when compiling: error: invalid types ‘size_t {aka long unsigned int}[size_t {aka long unsigned int}]’ for array subscript interactionMatrix[i][k]=interaction;
Here ist the code:
void Tree::computeInteractionScore(size_t* interactionMatrix){
size_t num_independent_variables = data->getNumCols() - no_split_variables->size();
for (size_t i = 0; i < num_independent_variables; ++i) {
for (size_t k = 0; i < num_independent_variables; ++k) {
size_t interaction = 0;
if(k!=i){
// interaction = computeInteraction(i,k);
}
interactionMatrix[i][k]=interaction;
}
}
}
interactionMatrix is declared as follow:
size_t num_independent_variables = data->getNumCols() - no_split_variables->size();
size_t interactionMatrix[num_independent_variables][num_independent_variables];
for (size_t i = 0; i < num_trees; ++i) {
trees[i]->computeInteractionScore(&interactionMatrix);
}
First problem is that:
size_t interactionMatrix[num_independent_variables][num_independent_variables];
is VLA (Variable Length Array) because size_t is non const, so it is non standard extension which by default is enabled under g++. As far as I remember it also allocates memory on stack, so you might end up with stack overflow if your array is too big. I would suggest you to change it to dynamically allocated array (or better a vector of vectors). For example
size_t **interactionMatrix;
interactionMatrix = new int*[num_independent_variables];
for (int i = 0; i < num_independent_variables; i++)
interactionMatrix[i] = new int[num_independent_variables];
then your current function parameter type will need to be change to size_t**. But then you will need to write your own deallocation code, and to be safe use std::unique_ptr with custom deleter for arrays.
better is to switch to :
std::vector<std::vector<size_t>> interactionMatrix(num_independent_variables, std::vector<size_t>(num_independent_variables));
and change accordingly function signature.
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
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!