Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Можно ли передать указатель на часть массива?


Автор: chaoss 16.5.2008, 16:45
У меня есть большой трехмерный динамический массив:
Код

double*** A;
A=new double**[SIZE1];
for(int i=0;i<SIZE1;i++)
{
A[i]=new double*[SIZE2];
}
for(int i=0;i<SIZE1;i++)
{
for(int j=0;j<SIZE2;j++)
{
A[i][j]=new double[SIZE3];
}
}

Есть некоторая функция:
Код

void Function(double* arr)
{
...
}

Как видно, эта функция принимает указатель на массив. Функция определенным образом заполняет данный массив.
Требуется передать в эту функцию часть от большого массива А для того, чтобы функция изменила эту часть.
Например, надо взять элементы массива с индексами A[m][...][n], где m,n - фиксированы, а ... означает все допустимые индексы, кроме первого и последнего (то есть кроме 0 и SIZE2-1) и эти элементы передать в функцию. То есть помимо необходимости "вырезать" один слой встает необходимость от этого слоя "откусить" один элемент слева и один справа и это уже передать в функцию.

Сделать это с введением дополнительной переменной не сложно. Просто делается одномерный массив:
Код

double* temp;
temp=new double[SIZE2-2];

К этому массиву применяется функция, а затем цикл заполнения:
Код

for(int i=0;i<SIZE2-1;i++)
{
A[m][i+1][n]=temp[i];
}


Но для этого нужно выделять дополнительную память, тратить время (очень важное для расчета) на перегонку значений массивов. Нельзя ли все же сразу, как я описал выше, передать в функцию нужную часть массива?

Автор: Rififi 16.5.2008, 17:31
"часть  массива" передать нельзя.
можно передать специальную конструкцию, которая будет итерировать массив по определенным правилам (стандартного решения нет, нужно реализовывать самому)

Автор: JackYF 16.5.2008, 18:23
Почему бы не передать один указатель и просто использовать в функции нужную часть? smile

Автор: MAKCim 16.5.2008, 18:34
chaoss, 
линеализировать трехмерный массив

Добавлено через 55 секунд
Цитата(JackYF @  16.5.2008,  18:23 Найти цитируемый пост)
Почему бы не передать один указатель и просто использовать в функции нужную часть?

потому как сигнатура double *, а не double **

Автор: JackYF 16.5.2008, 19:11
Цитата(MAKCim @  16.5.2008,  17:34 Найти цитируемый пост)
потому как сигнатура double *, а не double ** 

Брр...

Код

void func(double*** arr, int m, int n)
{
  for (int i = 1; i < SIZE1 - 1; ++i)
  {
    std::cout << arr[m][i][n];
  }
}

ы?

Автор: MAKCim 16.5.2008, 19:31
JackYF, 
Цитата(chaoss @  16.5.2008,  16:45 Найти цитируемый пост)
Есть некоторая функция:

Цитата(chaoss @  16.5.2008,  16:45 Найти цитируемый пост)
Как видно, эта функция принимает указатель на массив


Автор: JackYF 17.5.2008, 10:34
MAKCim, понял. Ну, если нет возможности изменить функцию, тогда хуже smile

Автор: Dov 17.5.2008, 18:10
Цитата(chaoss @  16.5.2008,  15:45 Найти цитируемый пост)
К этому массиву применяется функция, а затем цикл заполнения:


chaoss, а как ты передаёшь размер массива в функцию? 

Если размер нужного массива указан в теле функции, то вызываешь так:
Код
Function(&A[m][0][n]);


Функция должна обработать этот массив до нужного размера.
Например так:
Код
void Function(double* arr)
{
// ...
    for(int i = 1; i < SIZE2 - 1; i++)
        arr[i * SIZE3] = 999;
//...    
}


Добавлено @ 18:19
Для наглядности приведу пример:
Код

#define SIZE1 3
#define SIZE2 5
#define SIZE3 4

void Function(double* arr)
{
//...
    for(int i = 1; i < SIZE2 - 1; i++)
        arr[i * SIZE3] = 999;
//...        
}

int main()
{
    double A[SIZE1][SIZE2][SIZE3] = {0};
    
    int m = 2;
    int n = 1;

    Function(&A[m][0][n]);

    for(int i = 0; i < SIZE1; i++)
    {
        for(int j = 0; j < SIZE2; j++)
        {
            for(int h = 0; h < SIZE3; h++)
            {
                cout << setw(5) << A[i][j][h];
            }
            cout << endl;
        }
        cout << endl;
    }    

    return 0;
}


Для динамического массива так же должно быть, имхо.

Автор: MAKCim 17.5.2008, 18:49
Цитата(Dov @  17.5.2008,  18:10 Найти цитируемый пост)
Для динамического массива так же должно быть, имхо.

нет

Автор: chaoss 17.5.2008, 20:02
Цитата(Dov @ 17.5.2008,  18:10)
chaoss, а как ты передаёшь размер массива в функцию? 

В функцию я передаю размер массива. Я не знаю, знакомы Вы с вычислительной математикой или нет, но там есть такой метод решения систем линейных уравнений, называется "прогонка". Моя функция как раз реализует этот алгоритм. 
Функция получает на вход три массива коэффициентов (одномерные массивы равного размера), размер массива, массив (в смысле указатель) куда должен записываться результат. На основе коэффициентов ищется решение, которое записывается по переданному указателю.
Особенность состоит в том, что мне надо применять этот алгоритм не ко всему массиву, а к вырезанному куску (без краев, если графически это представить), плюс к тому сам массив не одномерный, а трехмерный и мне надо из этого трехмерного массива вырезать одномерные линейные куски и применять к каждому из них алгоритм. Собственно стараюсь добиться максимальной скорости и минимальной необходимой памяти.

Автор: Dov 18.5.2008, 00:27
Цитата(MAKCim @ 17.5.2008,  17:49)
Цитата(Dov @  17.5.2008,  18:10 Найти цитируемый пост)
Для динамического массива так же должно быть, имхо.

нет

Что нет? 

Код

#define SIZE1 3
#define SIZE2 5
#define SIZE3 4

void Function(double* arr)
{
    for(int i = 1; i < SIZE2 - 1; i++)
        arr[i * SIZE3] = 999;    
}

int main()
{
    double (*A)[SIZE2][SIZE3];
    int value = 0;

    //Выделение памяти из кучи.
    A = new double[SIZE1][SIZE2][SIZE3];

   //Заполнение массива.
    for(int i = 0; i < SIZE1; i++)
        for(int j = 0; j < SIZE2; j++)
            for(int k = 0; k < SIZE3; k++)
                 A[i][j][k] = ++value;    
    
    int m = 2;
    int n = 1;

    Function(&A[m][0][n]);

    for(int i = 0; i < SIZE1; i++)
    {
        for(int j = 0; j < SIZE2; j++)
        {
            for(int h = 0; h < SIZE3; h++)
            {
                cout << setw(5) << A[i][j][h];
            }
            cout << endl;
        }
        cout << endl;
    }

    //Возврат памяти в кучу.
    delete [] A;

    return 0;
}

Автор: mes 18.5.2008, 01:30
Цитата(Dov @  18.5.2008,  00:27 Найти цитируемый пост)
Что нет? 

Цитата(chaoss @  16.5.2008,  16:45 Найти цитируемый пост)
надо взять элементы массива с индексами A[m][...][n], где m,n - фиксированы, а ... означает все допустимые индексы, 


часть массива A[m][...][n]  не линейна

Автор: Dov 18.5.2008, 08:21
Цитата(mes @  18.5.2008,  00:30 Найти цитируемый пост)
часть массива A[m][...][n]  не линейна


Это почему?  Смотри пример.

Автор: MAKCim 18.5.2008, 10:02
Цитата(Dov @  18.5.2008,  08:21 Найти цитируемый пост)
Это почему?  Смотри пример.

посмотри, как создается массив у mes 
кроме того, где в стандарте написано, что многомерные массивы должны линеализироваться именно таким образом?

Автор: Dov 18.5.2008, 12:17
Цитата(MAKCim @  18.5.2008,  09:02 Найти цитируемый пост)
посмотри, как создается массив у mes 

Ничего не вижу...  smile 

Цитата(MAKCim @  18.5.2008,  09:02 Найти цитируемый пост)
кроме того, где в стандарте написано, что многомерные массивы должны линеализироваться именно таким образом?

MAKCim, о стандарте в вопросе ничего не сказано. Кто хочет, пусть читает стандарты... smile 
Вот вопрос chaoss`а:
 Можно ли передать указатель на часть массива? 
Вот мой ответ:
Можно. (см. примеры).  smile 

Всё. Остальное - сплошная болтовня, имхо.  smile 

Автор: mes 18.5.2008, 12:58
Цитата(Dov @  18.5.2008,  12:17 Найти цитируемый пост)
 (см. примеры).

Цитата(Rififi @  16.5.2008,  17:31 Найти цитируемый пост)
"часть  массива" передать нельзя.
можно передать специальную конструкцию, которая будет итерировать массив по определенным правилам (стандартного решения нет, нужно реализовывать самому) 

Цитата(Dov @  18.5.2008,  00:27 Найти цитируемый пост)
void Function(double* arr)
{
    for(int i = 1; i < SIZE2 - 1; i++)
        arr[i * SIZE3] = 999;    
}

Dov, это как раз одна из тех конструкций итерации, о которой говорил Riffi

Цитата(chaoss @  17.5.2008,  20:02 Найти цитируемый пост)
В функцию я передаю размер массива...Функция получает на вход три массива коэффициентов (одномерные массивы равного размера)

Цитата(JackYF @  17.5.2008,  10:34 Найти цитируемый пост)
Ну, если нет возможности изменить функцию, тогда хуже

Dov, а на основе этих строчек как теперь с примером? чтоб функция ничего не знала о массиве и получала только его кусок ))

Автор: Dov 18.5.2008, 14:08
Цитата(mes @  18.5.2008,  11:58 Найти цитируемый пост)
Dov, а на основе этих строчек как теперь с примером? чтоб функция ничего не знала о массиве и получала только его кусок ))


mes, практически любая функция должна знать размер массива, переданный, как параметр или, как глобальная переменная или каким-то другим путём. Иначе функция не сможет правильно работать с этим массивом. 

А вообще, неплохо было бы взглянуть на эту функцию..  smile 

Автор: mes 18.5.2008, 14:46
Цитата(Dov @  18.5.2008,  14:08 Найти цитируемый пост)
практически любая функция должна знать размер массива, переданный, как параметр или,

дело в том что функция составлена для одного типа массива, а автор топика хочет применить к другому.. В том виде в каком автор описал, задача решения в лоб не имеет. Для обходного решения подходы в теме озвучены, но для более точного примера требуется более детальное представление о текущей задаче. Например непонятно всегда ли куски массива будут вырезаться из одного измерения или нет, а также доподлино неизвестана возможность перепроектировки функции. Так что без дальнейшей информации,
Цитата(Dov @  18.5.2008,  12:17 Найти цитируемый пост)
Остальное - сплошная болтовня, имхо.   smile   

Автор: MAKCim 18.5.2008, 16:55
Цитата(Dov @  18.5.2008,  12:17 Найти цитируемый пост)
MAKCim, о стандарте в вопросе ничего не сказано

хорошая отмазка  smile 

Автор: dizzy1984 19.5.2008, 10:59
Цитата(chaoss @  16.5.2008,  18:45 Найти цитируемый пост)
Но для этого нужно выделять дополнительную память, тратить время (очень важное для расчета) на перегонку значений массивов. Нельзя ли все же сразу, как я описал выше, передать в функцию нужную часть массива?

Существует 2 варианта решения проблемы :
1. Переписывается тело функции так, чтобы она реализовывала логику выборки непоследовательно расположенных в памяти элементов исходного массива.
2. Для каждого вызова функции создается отдельный массив с линейным расположением элементов.
Я бы посоветовал первый.
Цитата(MAKCim @  17.5.2008,  20:49 Найти цитируемый пост)
Цитата(Dov @  17.5.2008,  18:10 )    
Для динамического массива так же должно быть, имхо.
нет

Dov имеет в виду динамический массив с последовательным расположением элементов. Для него, действительно, будет так же.
Цитата(mes @  18.5.2008,  03:30 Найти цитируемый пост)
часть массива A[m][...][n]  не линейна

Она не линейна у топикстартера, у Dov'а она линейна.
Цитата(MAKCim @  18.5.2008,  12:02 Найти цитируемый пост)
посмотри, как создается массив у mes 
кроме того, где в стандарте написано, что многомерные массивы должны линеализироваться именно таким образом?

Где создается массив у mes я тоже не вкурил. Видимо, это простая невнимательность и имеется в виду chaoss.
А на счет стандарта, это по-моему, через чур. Есть конкретный пример компилятора для которого такой массив будет нелинейным? Такой компилятор необходим топистартеру?

Автор: mes 19.5.2008, 13:04
Цитата(dizzy1984 @  19.5.2008,  10:59 Найти цитируемый пост)
Где создается массив у mes я тоже не вкурил

у меня массив не создается 


Цитата(dizzy1984 @  19.5.2008,  10:59 Найти цитируемый пост)
Она не линейна у топикстартера, у Dov'а она линейна.

никто не спорит что весь массив линейный или нет.. рассматривается только избранная его часть, определенная в начале теме.
под словом линейно подразумевается также, что эллементы массива располагаются непосредстевенно друг за другом  и можно пройти массив посредством  ++ итерации, чего не может предоставить часть массива A[m][...][n] (как минимум нужно передавать шаг итерации), а именно ее хочет передать автор в функцию..



Автор: math64 19.5.2008, 14:48
Код

class Array {
double* data;
int size, step;
public:
Array(double* _data, int _size, int _step) { size = _size; step = _step; data = _data; }
double& get (int x) { return data[x*step]; }
int getSize() { return size; }
};
class Array3D {
double* data;
int sizeX, sizeY, sizeZ;
public:
Array3D(int _sizeX, int _sizeY, int _sizeZ) { sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; data = new data[sizeX*sizeY*sizeZ]; }
~Array3D() { delete data; }
double& get (int x, int y, int z) { return data[(x*sizeY+y)*sizeZ+z]; }
Array getColumnXY(int x, int y) { return Array(data+(x*sizeY+y)*sizeZ, sizeZ, 1); }
Array getColumnXZ(int x, int z) { return Array(data+x*sizeY*sizeZ+z, sizeY, sizeZ); }
Array getColumnYZ(int y, int z) { return Array(data+y*sizeZ+z, sizeX, sizeY*sizeZ); }
};
void function(Array a);

Array3D a3d(10,10,10);
a3d.get(5,5,5) = 1.0;
function(a3d.getColumnXZ(5,5));
double d = a3d.get(5,5,5);

Автор: JackYF 19.5.2008, 16:04
math64, уж легче boost::array взять, чем своё городить, нет? smile

Автор: dizzy1984 20.5.2008, 05:59
Цитата(mes @  19.5.2008,  15:04 Найти цитируемый пост)
никто не спорит что весь массив линейный или нет.. 

Ну значит мы по-разному поняли тему спора. Прочитав ответ от 18.5.2008, 03:30, где приводится цитата ответа MAKCim, я пришел к выводу что защищается его версия, в которой понятие "динамический" стало синонимом "непоследовательный в памяти", что не всегда верно.
Пока решения такие :
Rififi предложил переписать функцию
Dov предложил переписать функцию и изменить представление данных
math64 предложил переписать функцию и изменить представление данных

Автор: mes 20.5.2008, 09:18
Цитата(dizzy1984 @  20.5.2008,  05:59 Найти цитируемый пост)
в которой понятие "динамический" стало синонимом "непоследовательный в памяти", что не всегда верно

Непоследовательный в памяти динамический многомерный массив, а в приведенном приммере у Dov динамическая часть массива одномерна.

Цитата(dizzy1984 @  20.5.2008,  05:59 Найти цитируемый пост)
Пока решения такие :

math64 без слов и споров  сделал всю черную работу по представлению 3х-мерного массива линианизированным по любому измерению. Респект. ИМХО остальные предложения сводятся к одной из модификаций такого решения .


Автор: rrrFer 20.5.2008, 09:51
что за шаманство?
Цитата

У меня есть большой трехмерный динамический массив:

Цитата

Функция получает на вход три массива коэффициентов (одномерные массивы равного размера), размер массива, массив (в смысле указатель) куда должен записываться результат. На основе коэффициентов ищется решение, которое записывается по переданному указателю.

непонятно зачем в прогонке трехмерный массив?
если я правильно помню, то прогонка - это метод с трехдиагональной матрицей...трехдиагональная она не потому что трехмерная, а потому что у нее на диагонали и в соседних с диагональю клеточках не нули, тоесть как бы три дагоналиsmile ну а раз это матрица то естественно она двумерная
когда то я делал эти лабы, но они у меня не проименованы, тоесть есть программы, а какая что выполняет я уже не помню, ну так глянул, возможно это программа которая тебе нужна:
Код
 /*----------------------INCLUDES---------------------*/
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
/*-------------------procedures----------------------*/
void output(float A[5][5],int tn,int tm){
    int i,j;
    for(i=0;i<tn;i++){
        printf("|");
        for(j=0;j<tm;j++){
            if(A[i][j]>=0)
                printf(" ");
            if(A[i][j]<0)
                printf("");
            printf("%1.1f |",A[i][j]);
        }
        printf("\n");
    }
}    
void output(float A[5],int tn){
    int i;
    for(i=0;i<tn;i++){
        printf("|");
        if(A[i]>=0)
            printf(" ");
        if(A[i]<0)
            printf("");
        printf("%1.3f |",A[i]);
    }
}
void main(){
    float A[5][5]=
    {{1,-1,0,0,0},{2,10,-5,0,0},{0,-3,8,2,0},{0,0,1,-12,-7},{0,0,0,-5./6,1}},
    Y[5]={4,109,-30,-48,25./6},Z[5],B[5],a[5],K[5],V[5],C[5];
    int n=5,i;
    for(i=0;i<n;i++){
        Z[i]=0;C[i]=0;B[i]=0;a[i]=0;V[i]=0;K[i]=0;
    }
    K[0]=-A[0][1];
    K[n-1]=-A[n-1][n-2];
    V[0]=Y[0];
    V[n-1]=Y[n-1];
    for(i=0;i<n;i++){
        B[i]=A[i][i+1];
        a[i]=A[i][i-1];
        C[i]=-A[i][i];
    }
    for(i=1;i<n-1;i++){
        K[i]=B[i]/(C[i]-(a[i]*K[i-1]));
        V[i]=((a[i]*V[i-1])-Y[i])/(C[i]-(a[i]*K[i-1]));
    }
    Z[n-1]=(V[n-1]+K[n-1]*V[n-2])/(1-(K[n-1]*K[n-2]));
    for(i=n-2;i>=0;i--)
        Z[i]=K[i]*Z[i+1]+V[i];
    float s=0;
    printf("\n\nFind errors^\n");
    output(Z,n);
    for(int j=0;j<n;printf("\n%d: %3.5f",j+1,s-Y[j]),s=0,j++)
        for(i=0;i<n;i++)
            s+=A[j][i]*Z[i];
    getch();
}

ну конечно вполне может быть, что в этой программе есть ошибки, потому что помнится правил я их прям когда сдавал...
------
и насчет:
Цитата

Можно ли передать указатель на часть массива?

я думаю что УКАЗАТЕЛЬ надо передавать все же на его начало, и вместе с указателем передавать переменные, отвечающие за то - какую часть массива надо использовать. Думаю делать надо именно так хотя бы для улудшения читабельности.

Автор: baldina 20.5.2008, 13:20
JackYF, 
Цитата

math64, уж легче boost::array взять, чем своё городить, нет?  

boost::multi_array

Автор: JackYF 20.5.2008, 15:44
Цитата(baldina @  20.5.2008,  12:20 Найти цитируемый пост)
boost::multi_array 

Да, именно. Точное название лень было смотреть smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)