indexing elements of a 2D array by pointer for transpose

P

pc_whocares

My forehead is flat from pounding.

I am building a DLL in VS2005 C++ for use in another software
development platform.

I am required to pass my array data in/out of the function via a
pointer, in this case, to double.

The simplest way for me to transpose the array is via addressing its
individual elements in the conventional form such as

array2dt[i,j] = array2d[j,i];

where both variables appear in the call list as

long redimSTr(..., double *array2d, double *array2dt)

I realize that the algorithm looks like it will likely only work for a
square matrix, but since array2dt is coming back completely unchanged,
I suspect that there is something else fundamentally wrong with my
logic, specifically, the way to directly address individual elements
of a multi dimensional array represented by a pointer in a function.

As you may suspect, please don't assume I'll just catch a hint.
'splain to me, Lucy!

tanks

pc
 
G

Gianni Mariani

pc_whocares said:
My forehead is flat from pounding. ....
As you may suspect, please don't assume I'll just catch a hint.
'splain to me, Lucy!

Without more code, no-one will be able to help you.
 
P

pc_whocares

My forehead is flat from pounding.

I am building a DLL in VS2005 C++ for use in another software
development platform.

I am required to pass my array data in/out of the function via a
pointer, in this case, to double.

The simplest way for me to transpose the array is via addressing its
individual elements in the conventional form such as

array2dt[i,j] = array2d[j,i];

where both variables appear in the call list as

long redimSTr(..., double *array2d, double *array2dt)

I realize that the algorithm looks like it will likely only work for a
square matrix, but since array2dt is coming back completely unchanged,
I suspect that there is something else fundamentally wrong with my
logic, specifically, the way to directly address individual elements
of a multi dimensional array represented by a pointer in a function.

As you may suspect, please don't assume I'll just catch a hint.
'splain to me, Lucy!

tanks

pc

Thanks for your replies. Let me try again.

I need a way to manipulate a 2D array in a subroutine. What's the
magic thing that will allow me to go from a pointer and base type to a
2D array? I am obviously a bare novice here.

It seems that one cannot dynamically create a 2D array.

tanks

pc


// redim.cpp : Defines the entry point for the DLL application.
//
// Use the defined keyword DLLEXPORT in front of C/C++ functions
// that are meant to be exported for use in calling context
//
#include <stdlib.h>
#include "stdafx.h"

#ifdef WIN32
#ifdef __cplusplus
#define DLLEXPORT extern "C" __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllexport)
#endif
#else
#define DLLEXPORT
#endif

typedef double* dblArrayPtr;

DLLEXPORT long redimSTr(long n, long m, long arraySize, double SF,
double *array, double *array2d)

{
long i;
long j;

dblArrayPtr tmpArray;
// both errors next executable line
// -- apparently can't dynamically create 2D array
// Error 1 error C2540: non-constant
// expression as array bound
// Error 2 error C2440: '=' :
// cannot convert from 'double (*)[1]' to 'dblArrayPtr'
tmpArray = new double[n][m];

// from calling context array2d is m x n
// next for loop simply copies data from
// 1D "array" to 2D "array2d" and scales it
for (i = 0; i < arraySize; i++, array++, array2d++)
{
*array2d = *array * SF;
}

// intention here is to put scaled data into
// an array that I can address by row, column
tmpArray = array2d;

// perform transpose.. will only work for square matrix,
// but that's the least of my worries
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
tmpArray[i,j] = array2d[j,i];
}
}

// put transposed data back so I can access
// it from calling function
array = tmpArray;
// clean up
delete [] tmpArray;
// arraySize is unused upon return
return(arraySize);
}
 
P

pc_whocares

pc_whocares said:
My forehead is flat from pounding.
I am building a DLL in VS2005 C++ for use in another software
development platform.
I am required to pass my array data in/out of the function via a
pointer, in this case, to double.
The simplest way for me to transpose the array is via addressing its
individual elements in the conventional form such as
array2dt[i,j] = array2d[j,i];
where both variables appear in the call list as
long redimSTr(..., double *array2d, double *array2dt)
I realize that the algorithm looks like it will likely only work for a
square matrix, but since array2dt is coming back completely unchanged,
I suspect that there is something else fundamentally wrong with my
logic, specifically, the way to directly address individual elements
of a multi dimensional array represented by a pointer in a function.
As you may suspect, please don't assume I'll just catch a hint.
'splain to me, Lucy!

You need to know the size of each matrix dimension, that is it's width and
height. There are two ways to map a 2D matrix into a single-dimensional
array: row-major and column-major. Row major is probably the most common
way, at least in my experience:

If your 2D matrix has W columns, that is each row has W elements, then the
matrix location row Y column X can be mapped to array[Y*W+X].

This, in fact, is exactly what the compiler will do if you define a 2D
array:

double matrix[10][2];

Using row-major convention, this declares a matrix with ten rows and two
columns, or, in conventional notation, a 2x10 array. Any reference to
matrix[Y][X] gets translated by the compiler into, essentially,
matrix'[Y*2+X], where "matrix'" is the start of the array, or, in C++ terms,
&matrix[0][0]+(Y*2+X)

I presume that your matrix is organized in row-major order, that's the most
common case. If your matrix is organized in column-major order, this
essentially exchanges rows and columns in the above discussion.

Therefore, presuming that your matrixes are given in row-major order, and
your array2d matrix has H rows and W columns, and subsequently your array2dt
matrix has W rows and H columns, you will have to essentially write some
code that puts array2d[Y*W+X] into array2dt[X*H+Y]. The actual code to do
that will be your homework assignment.

application_pgp-signature_part
1KDownload

Ahhhh. Yes. Working on it.
 
R

red floyd

My forehead is flat from pounding.
I am building a DLL in VS2005 C++ for use in another software
development platform.
I am required to pass my array data in/out of the function via a
pointer, in this case, to double.
The simplest way for me to transpose the array is via addressing its
individual elements in the conventional form such as
    array2dt[i,j] = array2d[j,i];
where both variables appear in the call list as
   long redimSTr(..., double *array2d, double *array2dt)
I realize that the algorithm looks like it will likely only work for a
square matrix, but since array2dt is coming back completely unchanged,
I suspect that there is something else fundamentally wrong with my
logic, specifically, the way to directly address individual elements
of a multi dimensional array represented by a pointer in a function.
As you may suspect, please don't assume I'll just catch a hint.
'splain to me, Lucy!

pc

Thanks for your replies.  Let me try again.

I need a way to manipulate a 2D array in a subroutine.  What's the
magic thing that will allow me to go from a pointer and base type to a
2D array?  I am obviously a bare novice here.

It seems that one cannot dynamically create a 2D array.

tanks

pc

// redim.cpp : Defines the entry point for the DLL application.
//
// Use the defined keyword DLLEXPORT in front of C/C++ functions
// that are meant to be exported for use in calling context
//
#include <stdlib.h>
#include "stdafx.h"

#ifdef WIN32
#ifdef __cplusplus
#define DLLEXPORT extern "C" __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllexport)
#endif
#else
#define DLLEXPORT
#endif

typedef double* dblArrayPtr;

DLLEXPORT long redimSTr(long n, long m, long arraySize, double SF,
double *array, double *array2d)

{
        long i;
        long j;

        dblArrayPtr tmpArray;
        // both errors next executable line
        //      -- apparently can't dynamically create 2D array
        // Error        1       error C2540: non-constant
        //      expression as array bound
        // Error        2       error C2440: '=' :
        //      cannot convert from 'double (*)[1]' to 'dblArrayPtr'
        tmpArray = new double[n][m];

        // from calling context array2d is m x n
        // next for loop simply copies data from
        // 1D "array" to 2D "array2d" and scales it
        for (i = 0; i < arraySize; i++, array++, array2d++)
        {
                *array2d = *array * SF;
        }

        // intention here is to put scaled data into
        // an array that I can address by row, column
        tmpArray = array2d;

        // perform transpose.. will only work for square matrix,
        // but that's the least of my worries
        for (i = 0; i < n; i++)
        {
                for (j = 0; j < m; j++)
                {
                        tmpArray[i,j] = array2d[j,i];

this line does not do what you think it does. It actually does
tmpArray[(i,j)] = array2d[(i,j)]

                }
        }

        // put transposed data back so I can access
        //      it from calling function
        array = tmpArray;
        // clean up
        delete [] tmpArray;
        // arraySize is unused upon return
        return(arraySize);

}
 
J

James Kanze

I am required to pass my array data in/out of the function
via a pointer, in this case, to double.
The simplest way for me to transpose the array is via
addressing its individual elements in the conventional form
such as
array2dt[i,j] = array2d[j,i];

Just a nit, but what is this line supposed to be doing. (I'm
pretty sure that it doesn't do what you expect.)

[...]
I need a way to manipulate a 2D array in a subroutine. What's
the magic thing that will allow me to go from a pointer and
base type to a 2D array? I am obviously a bare novice here.

OK. For starters, neither C nor C++ have multiple dimensioned
arrays---what they do have is arrays of any arbitrary type,
including arrays of arrays. This conditions both the syntax,
and some of the restrictions involved.

For more precision here, I'll introduce a somewhat formal
concept out of the standard: that of an incomplete type. In
C++, you can have incomplete types; the compiler knows that it
is a type, and probably a bit more, but it doesn't know
everything about the type. In particular, with regards to what
interests us here, the compiler does not know the size (number
of bytes) of the type. This is important, because in order to
lay out an array, and calculate indexes into it, the compiler
must know the size. So you can't have an array of an incomplete
type.
It seems that one cannot dynamically create a 2D array.

Sort of. Technically, you obviously can't because no such thing
exists. Practically, you can create an array of arrays, which
will behave in many respects like a 2D array, BUT... An array
whose size is not known to the compiler is an incomplete type,
so you can't create an array of such arrays. Thus, an
expression like "new double[ n ][ 10 ]" is fine, since this
creates a double[] of double[10]. (I'll use typename[] for an
array of unknown dimensions, an incomplete type, and
typename[n], where n is a compile time constant, for an array of
known dimension n, which is a complete type.) On the other
hand, "new double[j]" doesn't work, because that attempts to
create a "double[] of double[]", and array of the incomplete
type double[].

Note too that in the first case (the one that works), the new
expression returns a pointer to the first element of the array.
The first element of the array has type double[10], so we need a
pointer to double[10] (and not to just double). Which results
in the somewhat awkward syntax:
double (*array1)[ 10 ] = new double[ n ][ 10 ] ;

And if you've understood the above, you know why most C++
programmers will "flatten" the array, using a one dimensional
array of n*m, and calculating the index themselves. Generally
wrapping all of the logic in a class.

Finally, since you don't have multiple dimensional arrays,
there's no syntax to index them. If you have an array of
arrays, you have to index the outer array, which returns the
inner array, which you then index, e.g.: array[j].
// redim.cpp : Defines the entry point for the DLL application.
//
// Use the defined keyword DLLEXPORT in front of C/C++ functions
// that are meant to be exported for use in calling context
//
#include <stdlib.h>
#include "stdafx.h"
#ifdef WIN32
#ifdef __cplusplus
#define DLLEXPORT extern "C" __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllexport)
#endif
#else
#define DLLEXPORT
#endif

A couple of comments: first, for what few C++ features you're
using, if the function must be called from C, it's probably not
worth the bother of compiling it with C++. Unless you use
classes and/or some sort of smart pointers (which I would
recommend), just use malloc/free and compile in C. Second: if
you do use C++ features, and compile in C++, you'll need the
extern "C" everywhere, not just in Windows. Also, I presume
that the above is copy/pasted from the header somewhere; "#ifdef
__cplusplus" doesn't make sense in a source file, which will be
compiled as either C or C++, but not as both. For that matter,
you should probably include the header here, so that if there is
any difference between your function definition and the external
declaration, the compiler will tell you about it.
typedef double* dblArrayPtr;
DLLEXPORT long redimSTr(long n, long m, long arraySize, double SF,
double *array, double *array2d)
{
long i;
long j;
dblArrayPtr tmpArray;
// both errors next executable line
// -- apparently can't dynamically create 2D array
// Error 1 error C2540: non-constant
// expression as array bound
// Error 2 error C2440: '=' :
// cannot convert from 'double (*)[1]' to 'dblArrayPtr'
tmpArray = new double[n][m];

I discussed both problems above. All but the first dimension
must be compiler constants, and the return type is a pointer to
an array of double, not a pointer to double.

I'd just use:
std::vector< double > tmpArray( n * m ) ;
Most likely, wrapped in a class which allowed the [][] syntax
for indexing.
// from calling context array2d is m x n
// next for loop simply copies data from
// 1D "array" to 2D "array2d" and scales it
for (i = 0; i < arraySize; i++, array++, array2d++)
{
*array2d = *array * SF;
}

This could easily be done with std::transform. One thing at a
time, so I won't go into that here, but it's something that you
really should learn fairly quickly. (If I were teaching C++,
you'd probably learn to use std::transform before you learned
how to manipulate C-style arrays.)
// intention here is to put scaled data into
// an array that I can address by row, column
tmpArray = array2d;
// perform transpose.. will only work for square matrix,
// but that's the least of my worries
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
tmpArray[i,j] = array2d[j,i];

That's single indexing. The comma in the [i,j] is a comma
operator; the semantics are to evaluate the first expression
(for side effects), then throw away its value and evaluate the
second expression. And now that you are aware of its existance,
forget it---it's something that should never be used. What you
probably wanted to write is:

tmpArray[ i ][ j ] = array2d[ j ][ i ] ;

Except that for the reasons explained above, this won't work.

Also, I presume that there is a:
assert( n * m == arraySize ) ;
at the start of the function, which you forgot. (For that
matter, why pass arraySize at all, since you can easily
calculate it from n and m?)

Supposing that the transformation from column major ([j,i]) to
row major ([i,j]) is intentional, you really have to write
something like:
tmpArray[ m * i + j ] = array2d[ n * j + i ] ;
(or something along those lines).

Alternatively, you can write two small wrapper classes which
support column major and row major accessing. (The column major
is a bit tricky, as it will require some sort of proxy.)
// put transposed data back so I can access
// it from calling function
array = tmpArray;

All that does is assign your pointer to the argument pointer,
which is a local variable, and will disappear when you return
from the function.

You can use std::copy for this, but looking at your code, I
don't think you really need tmpArray at all. Once you've
generated array2D, you don't need the values in array any more,
so you can do the second transformation directly into array.

(But I'm wondering what this function is really supposed to do?
Basically, it transforms array into array2D by scaling, and then
puts a permutated copy of the transformed array2D into the
original array. That doesn't really make sense for a single
function.)
// clean up
delete [] tmpArray;
// arraySize is unused upon return

So why return it?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top