tags:

views:

208

answers:

7

Hi there,

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!

+2  A: 

*(*(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.

Pavel Radzivilovsky
"Even though an array is a pointer, 2D array is not a pointer to pointer". It must: If an array is a pointer, a 2d array is a pointer to a pointer (because a 2d array is an array of arrays). The bug in this is that an array is not a pointer: Then, a 2d array also is not a pointer to a pointer. Also, a 2d array *can* be dereferenced twice - i.e `**matrix` is entirely possible.
Johannes Schaub - litb
For the second "replacement declaration", it should look like `double (*myMatrix)[100] = (double(*)[100])fromVector;` but as you also note the 100 constant is in the way here. So you could use the proposed arithmetic, but it looks like a more complicated way to do just `*(myMatrix + i)` (there is no need to get row and col first, just to add them together later), as proposed by @partial and myself.
Johannes Schaub - litb
A: 

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;
}
Partial
I believe this is not what they wanted. They wanted to index a square of size m*n, not the first m*n elements of the top row.
Pavel Radzivilovsky
@Pavel, well if `m` and `n` are 100 respectively (i suspect they are the row and column size?), then this code will index the whole square correctly.
Johannes Schaub - litb
+1  A: 

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).

Johannes Schaub - litb
+1  A: 

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

VirusEcks
what 'Pavel Radzivilovsky' said was right too .. 2D arrays differ from normal arrys . on msdn (i guess) but can't find the correct link
VirusEcks
A: 

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 );
}
Dominic.wig
A: 

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.

jilles de wit
A: 

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.

igguk