Здравствуйте.
Пишу пользовательскую функцию к Маткад. Делается это через DLL. Интерфейс (ИМХО) реализован довольно коряво. Например, программисту доступны только два типа — COMPLEXSCALAR & COMPLEXARRAY. Есть еще строковый тип данных. А вот обычных вещественных и целочисленных не предусмотрено. Вот как это выглядит в заголовочном файле Маткада:
// complex scalar type
typedef struct tagCOMPLEXSCALAR {
double real;
double imag;
} COMPLEXSCALAR;
// complex array type
typedef struct tagCOMPLEXARRAY {
unsigned int rows;
unsigned int cols;
double **hReal; // hReal[cols][rows], == NULL when the real part is zero
double **hImag; // hImag[cols][rows], == NULL when the imaginary part is zero
} COMPLEXARRAY;
Вот как выглядит пользовательский модуль (данная функция меняет местами столбцы и строки) X — исходные данные , Y — результат:
LRESULT transposeFunction( LPCOMPLEXARRAY Y, LPCCOMPLEXARRAY X )
{
unsigned int i, j, k4;
// allocate space for the return array Y
if ( !MathcadArrayAllocate( Y, // allocate space for Y
X->cols, // with X cols
X->rows, // and X rows
X->hReal != NULL, // allocate the real part if X has a real part
X->hImag != NULL // allocate the imaginary part if X has
// an imaginary part
) )
return 2; // if allocation is insufficient
// return the error code
for ( i = 0; i < Y->cols; i++ )
{
if ( isUserInterrupted( ) )
{
MathcadArrayFree( Y );
return 3; // user interrupted
}
for ( j = 0; j < Y->rows; j++ )
{
if ( X->hReal != NULL )
Y->hReal[i][j] = X->hReal[j][i];
if ( X->hImag != NULL )
Y->hImag[i][j] = X->hImag[j][i];
}
}
return 0; // return 0 to indicate there was no error
}
Из текста видно, что программист вынужден каждый раз явно указывать мнимую и действительную части элемента массива, что в случае сложного алгоритма начинает сильно мешать. Я хотел было сделать промежуточный интерфейс, позволяющий работать только с действительной частью.
Однако заметил, что в объявлении типа не указываются размеры массива, а просто :
double **hReal;
Отсюда вопрос — а как же компилятор генерирует код, например такой:
Y->hReal[i][j] = 555;
ведь для этого как минимум надо знать величину второй размерности, т.е. Y->hReal[i][10]
PS: Маткад это знает, поскольку в структуре COMPLEXARRAY есть размеры матрицы, он передает это функции
во время выполнения.
Функция работает корректно. Пробовал другие фукнции, в которых разное число столбцов и строк — тоже все нормально.
Почитал Страуструпа — он пишет, что для адресации надо обязательно знать хотя бы второй размер, и предлагает такое решение (неудобно):
void print_mij (int* m, int dim1, int dim2)
{
for (int i=0; i<dim1; i++) {
for ( int j=0; j<dim2; j++)
cout << m(i*dim2+j) << '\t';
cout << '\n';
}
}
Здравствуйте, zzealot, Вы писали:
Z>Здравствуйте.
Z>...
Z>Z>// complex scalar type
Z>typedef struct tagCOMPLEXSCALAR {
Z> double real;
Z> double imag;
Z>} COMPLEXSCALAR;
Z>// complex array type
Z>typedef struct tagCOMPLEXARRAY {
Z> unsigned int rows;
Z> unsigned int cols;
Z> double **hReal; // hReal[cols][rows], == NULL when the real part is zero
Z> double **hImag; // hImag[cols][rows], == NULL when the imaginary part is zero
Z>} COMPLEXARRAY;
Z>
Z>...
Z>Однако заметил, что в объявлении типа не указываются размеры массива, а просто :
Z>double **hReal;
Z>Отсюда вопрос — а как же компилятор генерирует код, например такой:
Y->hReal[i][j] = 555;
Z>ведь для этого как минимум надо знать величину второй размерности, т.е. Y->hReal[i][10]
Вот это
double **hReal;
не вытянутый в линию двумерный массив, а массив указателей на линейные массивы из double;
а за этим
Y->hReal[i][j] = Z;
стоит что-то вроде
mov eax,Y
mov edx,[eax+ offset (hReal)]
mov ecx,[i]
mov edx,[edx+ecx*4]
mov ecx,[j]
mov edx,[edx+ecx*8]
lea eax,Z;
mov [edx],[eax]
mov [edx+4],[eax+4]
Здравствуйте, icWasya, Вы писали:
W>Вот это
W>W>double **hReal;
W>
W>не вытянутый в линию двумерный массив, а массив указателей на линейные массивы из double;
Точно ! И ведь мог бы сам догадаться, тем более что вызывается функция, которая выстраивает этот массив указателей:
// allocate space for the return array Y
if ( !MathcadArrayAllocate( Y, // allocate space for Y
X->cols, // with X cols
X->rows, // and X rows
X->hReal != NULL, // allocate the real part if X has a real part
X->hImag != NULL // allocate the imaginary part if X has
// an imaginary part
) )
Значит буду просто делать примерно так:
double** x;
x=xmath->hReal;
x[i][j]=555;
Спасибо
Здравствуйте, zzealot, Вы писали:
...
Z>Точно ! И ведь мог бы сам догадаться, тем более что вызывается функция, которая выстраивает этот массив указателей:
...
Z>Значит буду просто делать примерно так:
Z>double** x;
Z>x=xmath->hReal;
Z>x[i][j]=555;
Z>Спасибо
Ну а rows и cols нужны только для организации циклов по массивам
и контроля выхода за границы.