Related
i am new to c++ and i am trying to create an Array from within a function with just the array size, [row][col], as the argument. I know you cannot return an array from a function in c++. I would allocate memory in these situations if i were to code in C. However, i am not sure what is the C++ way (:
I tried,
int** get2Darray(int row, int col){
int** randInts = new int[row][col]; //Invalid. Constant required.
return randInts;
}
Thanks.
EDIT: vector class does the trick, however, my program is heavily modular. I dont have access to the main program. My function should be called and a fresh array should be created and returned. Implementation should only be done inside this function
Either change int** randInts = new int[row][col]; into int* randInts = new int[row * col]; or define int** randInts as follows:
int** randInts = new int*[row];
for (int i = 0; i < row; ++i) {
randInts[i] = new int[col];
}
It's a C way, not a C++ way. In C++ you should use containers (e.g. a vector as suggested in the comments).
I have shown this using vector <vector<T> >, but you can also use Eigen matrix or boost::ublas::matrix
std::vector< std::vector<int> > foo(const int rows, const int cols)
{
std::vector< std::vector<int> > v;
v.resize(rows);
for (auto i = 0; i < rows; i++)
{
v[i].resize(cols);
}
return v;
}
This will return a matrix of desired dimensions, and all elements will be initialized to 0.
The std::move part invokes a behavior called move semantics. You can read up on it. It's basically a better way of returning objects across a function boundary.
For compatibility's sake, if you must have a native array, then do this :
std::vector< vector<int> > temp = foo(rows, cols);
int *v = &temp[0][0];
Now, you can implement the gymnastics to get the correct index inside of int *v. You don't need multiple indirection.
P.S. This implementation assumes that your compiler supports C++ 11.
I have come across some code which allocates a 2d array with following approach:
auto a = new int[10][10];
Is this a valid thing to do in C++? I have search through several C++ reference books, none of them has mentioned such approach.
Normally I would have done the allocation manually as follow:
int **a = new int *[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
If the first approach is valid, then which one is preferred?
The first example:
auto a = new int[10][10];
That allocates a multidimensional array or array of arrays as a contiguous block of memory.
The second example:
int** a = new int*[10];
for (int i = 0; i < 10; i++) {
a[i] = new int[10];
}
That is not a true multidimensional array. It is, in fact, an array of pointers and requires two indirections to access each element.
The expression new int[10][10] means to allocate an array of ten elements of type int[10], so yes, it is a valid thing to do.
The type of the pointer returned by new is int(*)[10]; one could declare a variable of such a type via int (*ptr)[10];.
For the sake of legibility, one probably shouldn't use that syntax, and should prefer to use auto as in your example, or use a typedef to simplify as in
using int10 = int[10]; // typedef int int10[10];
int10 *ptr;
In this case, for small arrays, it is more efficient to allocate them on the stack. Perhaps even using a convenience wrapper such as std::array<std::array<int, 10>, 10>. However, in general, it is valid to do something like the following:
auto arr = new int[a][b];
Where a is a std::size_t and b is a constexpr std::size_t. This results in more efficient allocation as there should only be one call to operator new[] with sizeof(int) * a * b as the argument, instead of the a calls to operator new[] with sizeof(int) * b as the argument. As stated by Galik in his answer, there is also the potential for faster access times, due to increased cache coherency (the entire array is contiguous in memory).
However, the only reason I can imagine one using something like this would be with a compile-time-sized matrix/tensor, where all of the dimensions are known at compile time, but it allocates on the heap if it exceeds the stack size.
In general, it is probably best to write your own RAII wrapper class like follows (you would also need to add various accessors for height/width, along with implementing a copy/move constructor and assignment, but the general idea is here:
template <typename T>
class Matrix {
public:
Matrix( std::size_t height, std::size_t width ) : m_height( height ), m_width( width )
{
m_data = new T[height * width]();
}
~Matrix() { delete m_data; m_data = nullptr; }
public:
T& operator()( std::size_t x, std::size_t y )
{
// Add bounds-checking here depending on your use-case
// by throwing a std::out_of_range if x/y are outside
// of the valid domain.
return m_data[x + y * m_width];
}
const T& operator()( std::size_t x, std::size_t y ) const
{
return m_data[x + y * m_width];
}
private:
std::size_t m_height;
std::size_t m_width;
T* m_data;
};
How would one access an entire row of a multidimensional array?
For example:
int logic[4][9] = {
{0,1,8,8,8,8,8,1,1},
{1,0,1,1,8,8,8,1,1},
{8,1,0,1,8,8,8,8,1},
{8,1,1,0,1,1,8,8,1}
};
// I want everything in row 2. So I try...
int temp[9] = logic[2];
My attempt throws the error:
array initialization needs curly braces
I know I can retrieve the row using a FOR loop, however I'm curious if there was a more obvious solution.
That's not how arrays/pointers work in C++.
That array is stored somewhere in memory. In order to reference the same data, you'll want a pointer that points to the the beginning of the array:
int* temp = logic[2];
Or if you need a copy of that array, you'll have to allocate more space.
Statically:
int temp[9];
for (int i = 0; i < 9; i++) {
temp[i] = logic[2][i];
}
Dynamically:
// allocate
int* temp = new int(9);
for (int i = 0; i < 9; i++) {
temp[i] = logic[2][i];
}
// when you're done with it, deallocate
delete [] temp;
Or since you're using C++, if you want to not worry about all this memory stuff and pointers, then you should use std::vector<int> for dynamically sized arrays and std::array<int> for statically sized arrays.
#include <array>
using namespace std;
array<array<int, 9>, 4> logic = {
{0,1,8,8,8,8,8,1,1},
{1,0,1,1,8,8,8,1,1},
{8,1,0,1,8,8,8,8,1},
{8,1,1,0,1,1,8,8,1}
}};
array<int, 9> temp = logic[2];
As well as decaying the array to a pointer, you can also bind it to a reference:
int (&temp)[9] = logic[2];
One advantage of this is it will allow you to use it C++11 range-based for loops:
for (auto t : temp) {
// stuff
}
A direct assignment won't work. C++ does not allow that. At best you'll be able to assign them to point to the same data - int *temp = logic[2]. You'll need a for loop or something like the below.
I believe this would work:
int temp[9];
memcpy(temp, logic[2], sizeof(temp));
But I'd generally suggest using std::vector or std::array instead.
const int ADJ_MATRIX[VERTEX_NUM][VERTEX_NUM]={
{0,1,1,0,0,0,0,0},
{1,0,0,1,1,0,0,0},
{1,0,0,0,0,1,1,0},
{0,1,0,0,0,0,0,1},
{0,1,0,0,0,0,0,1},
{0,0,1,0,0,0,1,0},
{0,0,1,0,0,1,0,0},
{0,0,0,1,1,0,0,0}
};
typedef struct {
int vertex;
int matrix[VERTEX_NUM][VERTEX_NUM];
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX;
}
The error occurs in this sentence:
graph->matrix = ADJ_MATRIX;
I am new to c++. please tell me why this problem occur and how to solve it?
I want to assign ADJ_MATRIX to the matrix in struct.
As was said, you can't assign arrays in C++. This is due to the compiler being a meanie, because the compiler can. It just won't let you do it...
... unless you trick it ;)
template <typename T, int N>
struct square_matrix {
T data[N][N];
};
square_matrix<int, 10> a;
square_matrix<int, 10> b;
a = b; // fine, and actually assigns the .data arrays
a.data = b.data; // not allowed, compiler won't let you assign arrays
The catch? Now the code needs some little things:
const square_matrix<int, VERTEX_NUM> ADJ_MATRIX={{
// blah blah
}}; // extra set of braces
typedef struct {
int vertex;
square_matrix<int, VERTEX_NUM> matrix;
int vNum;
int eNum;
}Graph;
void buildGraph(Graph *graph){
graph->vNum = VERTEX_NUM;
graph->eNum = EDGE_NUM;
graph->matrix = ADJ_MATRIX; // no change
}
And to access the cells, now we need to use graph->matrix.data[1][2]. This can be mitigated by overloading operator[] or operator() for square_matrix. However, this is now getting terribly close to the new std::array class, or the Boost equivalent boost::array, so it might be wise to consider those instead.
Unfortunately (or maybe fortunately, who knows...) you can't just assign one array to another in C++.
If you want to copy an array, you will need to either copy each of it's elements into a new array one by one, or use the memcpy() function:
for( int i = 0; i < VERTEX_NUM; i++ )
for( int j = 0; j < VERTEX_NUM; j++ )
graph->matrix[i][j] = ADJ_MATRIX[i][j];
or
memcpy( graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int) );
Arrays are not assignable. You can use memcpy:
memcpy(graph->matrix, ADJ_MATRIX, sizeof(graph->matrix));
You cannot assign an array to another array. You will need to copy the elements from the source to the destination index by index, or use memcpy to copy the data. Array assignment like this is not allowed
You are trying to assign your variable address of a constant data,
try using
memcpy(graph->matrix,ADJ_MATRIX,sizeof(ADJ_MATRIX));//using sizeof(graph->matrix) is safer.
You can't use an array in assignments. You may use cycles or memcpy instead
memcpy(graph->matrix, ADJ_MATRIX, VERTEX_NUM * VERTEX_NUM * sizeof(int));
or
for(int i = 0; i < VERTEX_NUM; ++i){
for(int j = 0; j < VERTEX_NUM; ++j){
graph->matrix[i][j] = ADJ_MATRIX[i][j];
}
}
The error is thrown, because int matrix[VERTEX_NUM][VERTEX_NUM] in a structure definition means that each structure will have a 2D array of integers of the predefined size and matrix is going to be pointing to its first element. The thing is that matrix cannot be assigned to an arbitrary address, because it's a const pointer i.e. its value (the address it's pointing to) cannot change.
You have 2 options here: you can either use memcpy or some stl algorithms to copy the ADJ_MATRIX into matrix directly or you can declare matrix as a pointer and do the assignment that is currently produces an error.
The latter can be done in the following way:
typedef struct {
int vertex;
const int (*matrix)[VERTEX_NUM];
int vNum;
int eNum;
}Graph;
Thus you can do graph->matrix = ADJ_MATRIX assignment, but you won't be able to modify the individual items in matrix due to constness. This means, graph->matrix[0][1] = 3; is not allowed, while you can read the elements freely.
I'm brand new to C++ and am having trouble trying to get a function (which takes an array) to return an array. The function is a very basic sorting algorithm for an array of integers of size 4. What i have is below:
int[] sortArrayAscending(int arrayToSort[3]) {
int sortedArray[3];
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
I think i'm getting really confused with the syntax i need to use (the function calls to min, lower, higher, max all work fine.
I would really appreciate some help.
Thank you
EDIT2: Thank you for all the comments. I have now solved it thanks to #Rook's and #Bob Yoplait's answers. The code is used is:
int* sortArrayAscending(int arrayToSort[4], int sortedArray[4]) {
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
int _tmain(int argc, _TCHAR* argv[])
{
int testNumbers[4] = {8,14,1,27};
int testSorted[4];
sortArrayAscending(testNumbers,testSorted);
for (int i = 0; i < 4; i++) {
cout << testSorted[i] << endl;
}
system("pause");
return 0;
}
Thank you for all your help - now time to lookup vectors!
PS I appreciate #Luchian Grigore's solution is most likely the best practise way of doing things, but that wasn't specifically my question
Me, I'd probably use std::array<int, 4> if I was using a modern C++ compiler. Deals nicely with bounds checking and memory management and returning from/passing into functions. You can also use existing STL sort mechanisms and functions upon it; no need to reinvent the wheel!
Now, in your case,
int sortedArray[3];
is a local variable and you should never return a reference to it directly. You could do something like :
int* sortedArray = new int[4];
// do stuff
return sortedArray;
(also note the size of the array, 4, not 3 in your case!) but in this case you have to remember to delete the array at some point in the future or your application will leak memory.
You can also pass in the array by reference, using an approach like
void sort_array(std::array<int, 4>& the_array);
or
void sort_array(int** the_array)
and in these cases you can modify the array in place, or copy the answer into the argument when you're done sorting.
EDIT: After your edit, you, your function returns a pointer to an array. Should work.
You can either return a pointer or a std::vector.
Note that in your code, you'd be running into undefined behavior, because sortedArray goes out of scope at the end of the method, and the memory is freed.
I'd do this instead:
std::vector<int> sortArrayAscending(int arrayToSort[4]) {
std::vector<int> sortedArray(4);
sortedArray.push_back( minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
sortedArray.push_back( lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
sortedArray.push_back( higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
sortedArray.push_back( maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]));
return sortedArray;
}
Actually, I wouldn't. I'd just use std::sort instead of creating my own function, but that's just me.
As this is C++, suggest using a std::vector<int> instead:
std::vector<int> sortArrayAscending(int arrayToSort[3]) {
std::vector<int> sortedArray(4); // Note 4, not 3.
sortedArray[0] = ...;
sortedArray[1] = ...;
sortedArray[2] = ...;
sortedArray[3] = ...;
return sortedArray;
}
Note there are several algorithms already available that will perform some of the tasks that you appear to be performing:
max_element()
min_element()
You are returning pointer to local variable, which leads to undefined behavior. sortedArray is statically allocated array with automatic storage duration, which means that memory where it resides is being freed once you leave the scope of the function.
You should allocate it dynamically by using new[] or even better: use std::vector instead. If you choose to allocate it by using new[], don't forget to free it by calling delete[] when you don't need this memory anymore.
Also note that int sortedArray[3]; declares an array of size of 3 elements indexed from 0 to 2. If you access 4th element of the array whose size is 3 (if you access the memory "past the last element of the array object"), the behavior is undefined as well.
Use Boost::Array (or std::array in C+11) that provides proper value semantic to C array.
boost::array<int,4> sortArrayAscending(boost::array<int,4>7 arrayToSort)
{
boost::array<int,4> sortedArray;
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
It is not like in Java
Either you pass sortedArray as a parameter to the func
int* sortArrayAscending(int* arrayToSort, int* sortedArray) {
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
void toto() {
int array[4]; // and fill values...
int sortedArray[4];
sortArrayAscending(array, sortedArray);
}
or
int* sortArrayAscending(int* arrayToSort) {
int* sortedArray = new int[4];
sortedArray[0] = minOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[1] = lowerMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[2] = higherMidOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
sortedArray[3] = maxOfFour(arrayToSort[0],arrayToSort[1],arrayToSort[2],arrayToSort[3]);
return sortedArray;
}
and then you need to delete the returned array in the second case.
Arrays are always passed by reference to any function in C++.
So, just pass your array to the function. Your original array would get sorted and you can then use it in your program. I believe there is no need to return the array explicitly.