I have a problem with two dimensional arrays :( I feel very stupid and Visual C does not help me :( and I also think that my mistake is very stupid but still I can't find it :( I have this code:
double matrix[100][100]; //which is full with a matrix 3x4
double nVector[10000]; // for negative doubles
//I wanted to see if there are negative doubles in each row and column
//and I want this to happen with function
And this is my function:
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*(*(myMatrix+i)) < 0){
*(myNegArray+position) = *(*(myMatrix+i));
position++;
}
return myNegArray;
}
//for double*nVector I'm passing nVector
//for double*fromVector I'm passing *matrix
Visual C tells me that I have an error C2100: illegal indirection here: *(*(myMatrix+i)) I hope someone can help me (happy)
Thanks in advance!
*(*(myMatrix+i)) is wrong. This is a common mistake.
2D matrix does not create an array of pointers which you can access this way. It is a different structure. Even though an array is a pointer, 2D array is not a pointer to pointer, and it cannot be dereferrenced twice. Nor you have any other way to access element at coordinates (x,y) without knowing the layout in memory, because pointers to every line are nowhere to be found. For instance, char **argv parameter of main() is not a 2D array. This is an array of pointers to arrays, which is something else.
There're two ways to fix it.
One is replace
double *myMatrix = fromVector;
by
double *myMatrix[100] = (appropriate cast)fromVector;
and index it as myMatrix[i/n][i%n]
But then remember that 100 is a constant expression, and it cannot be passed as a parameter. Alternatively, you can implement the indexing operation yourself:
Pass additional parameter: matrix line size (100)
Instead of *(*(myMatrix+i)), write:
int row = i/n;
int col = i%n;
*(myMatrix+row*line_size+col) is your element.
first you might wanna start a small struct like
struct tmp {
bool negative;
double value;
};
and make your own way up to the
tmp *myvars [100][100];
.
instead try using that struct and try the std::vectors instead of arrays if that's possible then try using pointers on decalring the variable "1 time only" when declaring the variable as i said above
then pass arguments
( tmp *mystructpointer )
mystructpointer->.......
access your matrix directly ... peice of cake :D
If you are passing *matrix, you are actually passing a double[100] (an array of 100 doubles), that happens to be passed as a pointer to its first element. If you advance further than those 100 doubles using i added to that pointer, you advance into the next array of 100 doubles, since the 100 arrays of 100 doubles are stored next to each other.
Background: A multi-dimensional array is an array whose element type is itself an array. An array like double a[100][100]; can be declared equivalently as typedef double aT[100]; aT a[100];. If you use an array like a pointer, a temporary pointer is created to the array's first element (which might be an array). The * operator is such an operation, and doing *a creates a pointer of type double(*)[100] (which is a pointer to an array of 100 doubles), and dereferences it. So what you end up with *matrix is a double[100]. Passing it to the negativeVector function will create a pointer to its first element, which is of type double*.
Your pointer parameters point to the start of each of two arrays of 100 doubles each. So you should rewrite the function as
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*(myMatrix + i) < 0){
*(myNegArray + position) = *(myMatrix + i);
position++;
}
return myNegArray;
}
Notice that since your i iterates beyond the first of the 100 arrays stored in the 2d array, you will formally not be correct with this. But as it happens those arrays must be allocated next to each other, it will work in practice (and in fact, is recommended as a good enough work around for passing multi-dimensional arrays around as pointers to their first scalar element).
I have no clue why you are copying the arrays twice (once in the parameters of the function and a second time by declaring some new arrays)... You should also think of using the STL... std::vector will make the your life way easier ;)
double* negativeVector(double*nVector, double*fromVector, int m, int n){
int position = 0;
double *myNegArray = nVector;
double *myMatrix = fromVector;
for(int i = 0; i < m*n; i++)
if(*((myMatrix+i)) < 0){
*(myNegArray+position) = *((myMatrix+i));
position++;
}
return myNegArray;
}
is that homework? some templates - just for fun ;-)
double matrix[100][100];
double nVector[10000];
template< const int m, const int n >
double* negativeVector( double* myNegArray, const double (&myMatrix)[m][n] )
{
int position = 0;
for( int i = 0; i < m; ++i )
{
for( int j = 0; j < n; ++j )
{
const double value = myMatrix[ i ][ j ];
if ( value < 0 )
{
myNegArray[ position ] = value;
++position;
}
}
}
return myNegArray;
}
int main()
{
//...initialize matrix here...
negativeVector( nVector, matrix );
}
Perhaps rewrite this using std::vector to increase readability? (#):
#include <vector>
std::vector< std::vector<double> > matrix; //which is full with a matrix 3x4
std::vector<double> row;
row.resize(100,0);
matrix.resize(100,row);
std::vector<double> nVector; // for negative doubles, no size, we'll "push_back"
//I wanted to see if there are negative doubles in each row and column
//and I want this to happen with function
This is the stl enabled version of the function:
//I'm returning void because nvector contains the result,
//so I don't feel the need to return anything. vectors contain their
//own size so n and m are also not needed. Alsom pass in references
void negativeVector(std::vector<double>& nVector,
std::vector< std::vector<double> >& fromVector){
nVector.clear();
int i,j;
for(i = 0; i < fromVector.size(); i++) {
for(j = 0; j < fromVector[i].size(); j++) {
if(fromVector[i][j] < 0){
nVector.push_back(fromVector[i][j]);
}
}
}
}
call with:
negativeVector(nVector, matrix);
Once the function completes, nVector contains all negative numbers in matrix.
Read more about std::vector here.
(#) for people like me who are too lazy/stupid to comprehend code containing pointers.
Take a look at C++ Faq site:
How do I allocate multidimensional arrays using new?
link
And read until point [16.20] summarize all the answers you are getting and at the end you get a very useful Matrix template class.
Have a good read.
Related
Don't kill me: I'm a C++ noob.
Here's the code:
const int lengthA = 3;
const int lengthB = 4;
int main() {
double matrix[lengthA][lengthB];
double temp[lengthB];
for (int i = 0; i < lengthB; i++) {
temp[i] = i;
}
matrix[1] = temp;
}
How can I assign an array to a fixed index of a matrix that can contain it? Should I iterate each item on each (sequential) position? I hope I can simple past chunk of memory...
You don't directly assign raw arrays but rather copy their contents or deal with pointers to arrays
int main() {
double* matrix[lengthA]; // Array of pointers, each item may point to another array
double temp[lengthB]; // Caveat: you should use a different array per each row
for (int i = 0; i < lengthB; i++) {
temp[i] = i;
}
matrix[1] = temp;
}
Keep in mind that this is not a modern C++ way of doing things (where you could be better off using std::array or std::vector)
You can not, arrays are not assignable.
Here are three possible way to solve it:
Use std::array (or std::vector) instead
Copy the elements from one array to the other (either through std::copy, std::copy_n or std::memcpy)
Make matrix an array of pointers instead
I recommend std::array (or std::vector) first, copying second, and using pointers only as a last resort.
You can use double *matrix[lengthB]; instead of double matrix[lengthA][lengthB];
Hey everyone I am relearning C++ by doing some hacker rank challenges and am getting a segment fault error. The program should take in the dimensions for the matrix and compute both diagonals, then add them together. I am pretty sure the error is in how the 2d array is passed to the computeMainDiagonal and computeSecondaryDiagonal functions. Thanks for the help !
int ComputeMatrixMainDiagonal(int matrixDimensions, int* matrix){
int rowIndent = 0;
int diagonalValue;
for(int i = 0;i < matrixDimensions;i++){
diagonalValue =+ (&matrix)[i][rowIndent];
rowIndent++;
}
return diagonalValue;
}
int ComputeMatrixSecondaryDiagonal(int matrixDimensions, int* matrix){
int rowIndent = matrixDimensions;
int diagonalValue;
for(int i = matrixDimensions;i > 0;i--){
diagonalValue =+ (&matrix)[i][rowIndent];
rowIndent--;
}
return diagonalValue;
}
int main() {
int matrixDimension;
int differenceAcrossSumsOfDiagonal;
int matrixMainDiagonal;
int matrixSecondaryDiagonal;
int * matrixPointer;
cin >> matrixDimension; //get matrix dimensions
int matrix[matrixDimension][matrixDimension]; //declare new matrix
for(int index = 0; index < matrixDimension;index++ ){ //populate matrix
for(int i = 0; i < matrixDimension;i++){
cin >> matrix[index][i];
}
}
matrixMainDiagonal = ComputeMatrixMainDiagonal(matrixDimension,&matrix[matrixDimension][matrixDimension]);
matrixSecondaryDiagonal = ComputeMatrixSecondaryDiagonal(matrixDimension,&matrix[matrixDimension][matrixDimension]);
differenceAcrossSumsOfDiagonal = (matrixMainDiagonal + matrixSecondaryDiagonal);
cout << differenceAcrossSumsOfDiagonal;
return 0;
}
Your segmentation fault likely occurs because &matrix[matrixDimension][matrixDimension] does not mean what you think it means. Your question title suggests that you think this is a way to pass the array by value (though why you would want to do so escapes me), but pass-by-value vs. pass-by-reference is a matter of how the function is declared, not of how it is called.
The expression &matrix[matrixDimension][matrixDimension] would be the address of the matrixDimensionth element of the matrixDimensionth row of the matrix. This is outside the bounds of the matrix, as the maximum index for an array is one less than the array dimension. Even if you wrote &matrix[matrixDimension - 1][matrixDimension - 1], however, it would not be what you want. You want the address of the first element of the array, which is &matrix[0][0] or simply matrix, though these are inequivalent on account of having different type (corresponding to different senses of what the elements of matrix are).
I am quite new to programming,so I really need help. I need to wrtie a function which produce 2d arrays with random values. here is my code:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
float randArray(int row, int column);
int main()
{
int r = 10, c = 8;
float fckMmd = randArray(r,c);
///printing the array:
for (int row=0; row<r; row++){
for (int column=0; column<c; column++){
cout << fckMmd[row][column] << " ";
}
cout << endl;
}
}
float randArray(int row, int column){
srand(time(NULL));
float *randArr;
randArr = new int [row][column];
for(int k=0; k<row; k++){
for(int kk=0; kk<column; kk++){
randArr[k][kk] = rand();
}
}
return randArr;
}
But I get the error mentioned above. Where is the problem? help me please
randArr is a float * but you try to allocate a 2d array in it. A 2d array is not the same thing as a pointer. Your function only returns 1 float as well. I suggest you use vectors (also so you don't leak memory). Furthermore you should only call srand ONCE, not every time, and be aware rand() returns an integer, not a floating point value.
std::vector<std::vector<float>> randArray(int row, int column)
{
std::vector<std::vector<float>> randArr(row);
for (auto& v : randArr)
{
v.resize(column);
}
for(int k=0; k<row; k++)
{
for(int kk=0; kk<column; kk++)
{
randArr[k][kk] = static_cast<float>(rand());
}
}
return randArr;
}
It's because fckMmd is only a float and not a pointer or array.
First:
float *randArr;
declares a pointer to float. You then do
randArr = new int [row][column];
which allocates memory for a 2D array of ints (incompatible types, technically you allocate memory for a pointer to arrays of type int[column]), hence the error.
You're better using a std::vector instead, or, if you want a manually-managed dynamically allocated 2D array, use float **randArr; instead, and allocate
float** randArr;
randArr = new float* [rows];
for(int i = 0; i < row; ++i)
randArr[i] = new float[col];
or
float (*randArr)[col]; // pointer to array float[col]
randArr = new float[row][col];
Other issues: most of the time, srand must be used only once in the program. It is a good idea to call it in main() and not bury it into a function, since you may end up calling the function multiple times.
Last issue: if you want speed, you're better off using a single flat array (or std::vector) and map from 2D to 1D and vice versa, since your data will be guaranteed to be contiguous and you'll have very few cache misses.
This question already has answers here:
Representing a 2D array as a 1D array [duplicate]
(5 answers)
Closed 9 years ago.
I have a jagged 2D array, the rows aren't all the same length:
int sizes[100];
//init sizes
unsigned char *p = [100];
for(unsigned int i = 0; i < 10; i++)
{
p[i] = (unsigned char*)malloc(sizeof(char)*sizes[i]);
for(unsigned int j = 0; j < sizes[i]; j++)
p[i] = j;
}
I use the array like this:
p[x][y]
How can I simulate this array to 1D?
I assume that if you want to access your "2D array" as a one D matrix, you expect that as you increment your index by 1, you access the next element in the array (and will automatically go to the next line when you run off the edge). The right way to do this is by changing the way you allocate the array. I'll try to show how this is done - this is just C, not C++. It's probably more appropriate since you were using malloc anyway. I am also thinking that you have a pretty serious error in your code, in that you are creating a char * pointer p, yet expect to use it in
p[x][y];
for which you would need a char **, obviously. Let's try to make code that would do what you want:
int sizes[100];
//init sizes
unsigned char *p[100]; // without the == sign we create an array of 100 pointers
unsigned char *bigP; // the master pointer
int totalLength = 0;
int ii;
for(ii=0; ii<100; ii++) totalLength += sizes[ii];
bigP = malloc(sizeof(char) * totalLength);
int offset = 0;
// make pointers p point to places along this big memory block:
for(ii = 0; ii < 100; ii++) {
p[ii] = bigP + offset;
offset += sizes[ii];
}
Now you can either address your array with
p[x][y];
or with
bigP[z];
where z can go from 0 to the maximum number of elements. Of course, in the process you don't know (when you are using the "1D" paradigm) in what row/column of the jagged array you are - you can't know that if you are truly in one dimension.
The key here is that the memory is allocated as a single contiguous block, and the pointers p are pointing to places in that block. This means you MUST NOT FREE p. You must only ever free bigP.
I hope this makes sense.
If you're looking for a way to map a two dimensional array onto a one dimensional space, then try...
int sizes[width*height];
void setPoint(int x, int y, int val) {
sizes[x*width + y] = val;
}
Notably the x*width + y indexing will give you the appropriate element in the one dimensional array.
Unless it is homework just download boost and use Boost.Matrix.
I originally asked using nested std::array to create an multidimensional array without knowing dimensions or extents until runtime but this had The XY Problem of trying to accomplish it with std::array.
The questions One-line initialiser for Boost.MultiArray and How do I make a multidimensional array of undetermined size a member of a class in c++? and their answers give some helpful information how to use Boost::MultiArray to avoid needing to know the extents of the dimensions at runtime, but fail to demonstrate how to have a class member that can store an array (created at runtime) whose dimensions and extents are not known until runtime.
Just avoid multidimensional arrays:
template<typename T>
class Matrix
{
public:
Matrix(unsigned m, unsigned n)
: n(n), data(m * n)
{}
T& operator ()(unsigned i, unsigned j) {
return data[ i * n + j ];
}
private:
unsigned n;
std::vector<T> data;
};
int main()
{
Matrix<int> m(3, 5);
m(0, 0) = 0;
// ...
return 0;
}
A 3D access (in a proper 3D matrix) would be:
T& operator ()(unsigned i, unsigned j, unsigned k) {
// Please optimize this (See #Alexandre C)
return data[ i*m*n + j*n + k ];
}
Getting arbitrary dimensions and extent would follow the scheme and add overloads (and dimensional/extent information) and/or take advantage of variadic templates.
Having a lot of dimensions you may avoid above (even in C++11) and replace the arguments by a std::vector. Eg: T& operator(std::vector indices).
Each dimension (besides the last) would have an extend stored in a vector n (as the first dimension in the 2D example above).
Yes. with a single pointer member.
A n multidimensional array is actually a pointer. so you can alocate a dynamic n array and with casting, and put this array in the member pointer.
In your class should be something like this
int * holder;
void setHolder(int* anyArray){
holder = anyArray;
}
use:
int *** multy = new int[2][1][56];
yourClass.setHolder((int*)multy);
You can solve the problem in at least two ways, depending on your preferences. First of all - you don't need the Boost library, and you can do it yourself.
class array{
unsigned int dimNumber;
vector<unsigned int> dimSizes;
float *array;
array(const unsigned int dimNumber, ...){
va_list arguments;
va_start(arguments,dimNumber);
this->dimNumber = dimNumber;
unsigned int totalSize = 1;
for(unsigned int i=0;i<dimNumber;i++)
{
dimSizes.push_back(va_arg(arguments,double));
totalSize *= dimSizes[dimSizes.size()-1];
}
va_end(arguments);
array = new float[totalSize];
};
float getElement(unsigned int dimNumber, ...){
va_list arguments;
va_start(arguments,dimNumber);
unsgned int elementPos = 0, dimAdd = 1;
for(unsigned int i=0;i<dimNumber;i++)
{
unsigned int val = va_arg(arguments,double);
elementPos += dimAdd * val;
dimAdd *= dimsizes[i];
}
return array[elementPos]
};
};
Setting an element value would be the same, you will just have to specify the new value. Of course you can use any type you want, not just float... and of course remember to delete[] the array in the destructor.
I haven't tested the code (just wrote it straight down here from memory), so there can be some problems with calculating the position, but I'm sure you'll fix them if you encounter them. This code should give you the general idea.
The second way would be to create a dimension class, which would store a vector<dimension*> which would store sub-dimensions. But that's a bit complicated and too long to write down here.
Instead of a multidimensional array you could use a 1D-array with an equal amount of indices. I could not test this code, but I hope it will work or give you an idea of how to solve your problem. You should remember that arrays, which do not have a constant length from the time of being compiled, should be allocated via malloc() or your code might not run on other computers.
(Maybe you should create a class array for the code below)
#include <malloc.h>
int* IndexOffset; //Array which contains how many indices need to be skipped per dimension
int DimAmount; //Amount of dimensions
int SizeOfArray = 1; //Amount of indices of the array
void AllocateArray(int* output, //pointer to the array which will be allocated
int* dimLengths, //Amount of indices for each dimension: {1D, 2D, 3D,..., nD}
int dimCount){ //Length of the array above
DimAmount = dimCount;
int* IndexOffset = (int*) malloc(sizeof(int) * dimCount);
int temp = 1;
for(int i = 0; i < dimCount; i++){
temp = temp * dimLengths[i];
IndexOffset[i] = temp;
}
for(int i = 0; i < dimCount; i++){
SizeOfArray = SizeOfArray * dimLengths[i];
}
output = (int*)malloc(sizeof(int) * SizeOfArray);
}
To get an index use this:
int getArrayIndex(int* coordinates //Coordinates of the wished index as an array (like dimLengths)
){
int index;
int temp = coordinates[0];
for(int i = 1; i < DimAmount; i++){
temp = temp + IndexOffset[i-1] * coordinates[i];
}
index = temp;
return index;
}
Remember to free() your array as soon as you do not need it anymore:
for(int i = 0; i < SizeOfArray; i++){
free(output[i]);
}
free(output);