Russian Qt Forum

Программирование => С/C++ => Тема начата: Martiro от Июль 20, 2011, 11:18



Название: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 11:18
Есть 3 массива, из них один - двумерный, + int.
Как правильно написать вызов и саму процедуру по их заполнению?
Похожая тема (http://www.prog.org.ru/topic_1230_0.html) не помогла. ???
Пытаюсь сделать так:
Код:
MainClass::MainClass()
{
   ...
   double EF[9];
   double V[6];
   ...
   long int kt1 = LGL / h1 + 1;
   double BL1[kt1 + 2][2];
   ...
   INTdBds (LGL, h1, EF, &V, &BL1, &kt1 );
   ...
}

void MainClass::INTdBds (double S, double h0, double NU, double *REZ, double *B, long int *i)
{
   ...
   *i = 2;
   ...
   *B[*i-1][ 0] = x1[0];
   *B[*i-1][ 1] = y1[0];
   *REZ[0] = x1[0];
   *REZ[1] = y1[0];
   *REZ[2] = z1[0];
   *REZ[3] = Zd[0];
}
Компилятор ругает:
Цитировать
no matching function for call to 'MainClass::INTdBds (double&, double&, double [9], double(*)[6], double(*)[(((unsigned int)(((int)kt1)+1))][2], long int*)'
candidates are: void MainClass::INTdBds(double, double, double*, double**, double**, long int*)
Совсем я запутался с этими указателями...


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: kambala от Июль 20, 2011, 12:25
третий параметр ожидается double, а ты туда подставляешь массив;
чтоб передать указатель на двумерный массив, в сигнатуре функции поменяй на double B[][2] или double **B;

при передаче массива в качестве параметра писать перед ним & необязательно;
при обращении к элементам массива, даже если он и передан в виде указателя, ставить перед ними * не нужно


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: shirushizo от Июль 20, 2011, 12:38
Ваша процедура:
Код:
void MainClass::INTdBds(double S, double ho, double *NU, double *REZ, double **B, long int &i)
   ...
   i = 2;
   ...
   B[i-1][ 0] = x1[0];
   B[i-1][ 1] = y1[0];
   REZ[0] = x1[0];
   REZ[1] = y1[0];
   REZ[2] = z1[0];
   REZ[3] = Zd[0];
}

Вызов:
Код:
INTdBds (LGL, h1, EF, V, BL1, kt1 );

Массив  - указатель на первый элемент (m == &m[0]) и в функции обычно передается как указатель, т.е. адрес первого элемента. Передавая параметры по ссылке мы также передаем адрес, но работаем с параметром как с обычной переменной, т.е. разадресация не нужна (i = 2; вместо *i = 2;).


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 13:19
shirushizo, вот теперь всё понятно стало.  ;D
Спасибо огромное!


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: LisandreL от Июль 20, 2011, 13:29
Передавая параметры по ссылке мы также передаем адрес, но работаем с параметром как с обычной переменной, т.е. разадресация не нужна (i = 2; вместо *i = 2;).
Недоправили: B[*i-1] => B[i-1]


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 13:42
...хотя поторопился я.
Пишу:
Цитировать
void MainClass::INTdBds(double S, double ho, double *NU, double *REZ, double **B, long int &i)
и вызываю: INTdBds (LGL, h1, EF, V, BL1, kt1 );
Пишет опять:
Цитировать
no matching function for call to 'MainClass::INTdBds (double&, double&, double [9], double[6], double[(((unsigned int)(((int)kt1)+1))][2], long int&)'
candidates are: void MainClass::INTdBds(double, double, double*, double*, double**, long int&)
Когда правлю на
Цитировать
void MainClass::INTdBds(double S, double ho, double *NU, double *REZ, double B[][2], long int &i)
Все собирается, но есть подозрение что в
Цитировать
MainClass::MainClass()
{
   ...
   INTdBds (LGL, h1, EF, V, BL1, kt1 );
   ...
}
BL1 - не заполнится... Или я не прав?


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: shirushizo от Июль 20, 2011, 14:02
LisandreL, проглядел :).
Martiro, да в случае, double B[][2] будет передано значение, т.е. копия массива, а не указатель. Массив BL1 не изменится.

выдели память ручками:
Код:
double *EF= new double[9];
double *V=new double[6];

long int kt1 = LGL / h1 + 1;
double **BL1=new double[kt1 + 2];

for(int j=0;j<kt1 + 2; ++j) BL1[j]=new double[2];
и пробуй вариант:
Код:
void MainClass::INTdBds(double S, double ho, double *NU, double *REZ, double **B, long int &i)


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Igors от Июль 20, 2011, 14:04
BL1 - не заполнится... Или я не прав?
У Вас данные организованы настолько безобразно, что трудно что-то понять/сказать. Вы не хотите использовать stl, контейнеры - хорошо, но тогда создайте структуру и засуньте в нее все потроха, напр

Код
C++ (Qt)
struct MYData {
 double EF[9];
 double V[6];
 int kt1;
 double * BL1;
};
 
MyData data;
data.kt1 = LGL / h1 + 1;
data.BL1 = new double[(data.kt1 + 2) * 2];
  ...
 INTdBds (LGL, h1, &data);
 ...
 delete [] data.BL1;
 
А то бегать с разбросанными массивами можно очень долго


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: kambala от Июль 20, 2011, 14:07
Martiro, да в случае, double B[][2] будет передано значение, т.е. копия массива, а не указатель. Массив BL1 не изменится.
массивы никогда не передаются по значению


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 14:43
Я прошу прощения за это "безобразие". Позже переделаю. А пока, для экономии места, написал так.
И спрашиваю для того чтобы увидеть советы от людей лучше меня разбирающихся в Си. Поэтому заранее прошу прощения за неграмотность в некоторых вопросах.
Вы не хотите использовать stl, контейнеры - хорошо...
Так научите, подскажите! Однако, здесь использование сторонних библиотек не желательно.

Далее по теме:
Как после этого вытащить значения из BL1?

Создал массив на подобии того, как Вы советовали (http://www.prog.org.ru/index.php?topic=18870.msg127139#msg127139):
Код
C++ (Qt)
double * BL1 = new double[(kt1 + 2)*2];
пытаюсь заполнить например так:
Код
C++ (Qt)
BL1[0][0] = 1.0;
компилятор ругается:
Цитировать
invalid types 'double[int]' for array subscript
Оно и понятно. Массив создался одномерный. Как сделать двумерный?


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: kambala от Июль 20, 2011, 14:55
Вы не хотите использовать stl, контейнеры - хорошо...
Так научите, подскажите!
вряд ли на этом форуме будут учить как пользоваться stl или контейнерами. для этого есть куча самых разных книг и статей в интернете.
Код
C++ (Qt)
double * BL1 = new double[(kt1 + 2)*2];
пытаюсь заполнить например так:
Код
C++ (Qt)
BL1[0][0] = 1.0;
компилятор ругается:
Цитировать
invalid types 'double[int]' for array subscript
Оно и понятно. Массив создался одномерный. Как сделать двумерный?
Код
C++ (Qt)
int rows = kt1 + 2;
double **BL1 = new double *[rows];
for (int i = 0; i < rows; ++i)
   BL1[i] = new double [2];


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: m_ax от Июль 20, 2011, 15:00
Я прошу прощения за это "безобразие". Позже переделаю. А пока, для экономии места, написал так.
И спрашиваю для того чтобы увидеть советы от людей лучше меня разбирающихся в Си. Поэтому заранее прошу прощения за неграмотность в некоторых вопросах.
Вы не хотите использовать stl, контейнеры - хорошо...
Так научите, подскажите!

Далее по теме:
Как после этого вытащить значения из BL1?

Создал массив на подобии того, как Вы советовали (http://www.prog.org.ru/index.php?topic=18870.msg127139#msg127139):
Код
C++ (Qt)
double * BL1 = new double[(kt1 + 2)*2];
пытаюсь заполнить например так:
Код
C++ (Qt)
BL1[0][0] = 1.0;
компилятор ругается:
Цитировать
invalid types 'double[int]' for array subscript
Оно и понятно. Массив создался одномерный. Как сделать двумерный?
Укуси меня пчела))

Код:
Оно и понятно. Массив создался одномерный. Как сделать двумерный?
Код
C++ (Qt)
int rows = 3;
int columns = 3;
double **Arr = new double*[rows];
   for (int i = 0; i < rows; ++i)
       Arr[i] = new double[columns];
 
kambala меня опередил))

А вообще, лучше использовать уже готовые контэйнеры.
В качестве двумерного массива могу посоветовать такую реализацию:
Код
C++ (Qt)
#ifndef ARRAY2D_H
#define ARRAY2D_H
 
#include <stdexcept>
 
template <class T>
class Array2D
{
public:
   typedef size_t size_type;
   Array2D();
   Array2D(size_type rows, size_type columns, const T &initValue = T());
   Array2D(const Array2D<T> &other);
   ~Array2D();
   T &operator() (size_type row, size_type column) throw(std::out_of_range);
   const T &operator() (size_type row, size_type column) const throw(std::out_of_range);
   Array2D &operator=(const Array2D<T> &array);
   void resize(size_type rows, size_type columns);
   bool swapRows(size_type i, size_type j);
   size_type columns() const { return m_columns; }
   size_type rows() const { return m_rows; }
private:
   T **m_arr;
   size_type m_rows;
   size_type m_columns;
};
//-----------------------------------------------------------------------------
 
template <class T>
Array2D<T>::Array2D()
   : m_arr(0), m_rows(0), m_columns(0)
{
}
//-----------------------------------------------------------------------------
 
template <class T>
Array2D<T>::Array2D(size_type rows, size_type columns, const T &initValue)
   : m_rows(rows), m_columns(columns)
{
   m_arr = new T*[m_rows];
   for (size_type i = 0; i < m_rows; ++i)
       m_arr[i] = new T[m_columns];
 
   for (size_type i = 0; i < m_rows; ++i) {
       for (size_type j = 0; j < m_columns; ++j) {
           m_arr[i][j] = initValue;
       }
   }
}
//-----------------------------------------------------------------------------
 
template <class T>
Array2D<T>::Array2D(const Array2D<T> &other)
{
   m_rows = other.rows();
   m_columns = other.columns();
 
   m_arr = new T*[m_rows];
   for (size_type i = 0; i < m_rows; ++i)
       m_arr[i] = new T[m_columns];
 
   for (size_type i = 0; i < m_rows; ++i) {
       for (size_type j = 0; j < m_columns; ++j) {
           m_arr[i][j] = other(i, j);
       }
   }
}
//-----------------------------------------------------------------------------
 
template <class T>
Array2D<T>::~Array2D()
{
   for (size_type i = 0; i < m_rows; ++i)
       delete []m_arr[i];
   delete []m_arr;
}
//-----------------------------------------------------------------------------
 
template <class T>
Array2D<T> &Array2D<T>::operator=(const Array2D<T> &array)
{
   if (this == &array) {
       return *this;
   }
   if (m_rows != array.rows() || m_columns != array.columns()) {
       for (size_type i = 0; i < m_rows; ++i)
           delete []m_arr[i];
       delete []m_arr;
 
       m_rows = array.rows();
       m_columns = array.columns();
 
       m_arr = new T*[m_rows];
       for (size_type i = 0; i < m_rows; ++i)
           m_arr[i] = new T[m_columns];
   }
 
   for (size_type i = 0; i < m_rows; ++i) {
       for (size_type j = 0; j < m_columns; ++j) {
           m_arr[i][j] = array(i, j);
       }
   }
   return *this;
}
//-----------------------------------------------------------------------------
 
template <class T>
T &Array2D<T>::operator ()(size_type row, size_type column) throw(std::out_of_range)
{
   if ((row >= m_rows) || (column >= m_columns))
       throw std::out_of_range("Array2D: out of range!");
 
   return m_arr[row][column];
}
//-----------------------------------------------------------------------------
 
template <class T>
const T &Array2D<T>::operator ()(size_type row, size_type column) const throw(std::out_of_range)
{
   if ((row >= m_rows) || (column >= m_columns))
       throw std::out_of_range("Array2D: out of range!");
 
   return m_arr[row][column];
}
//-----------------------------------------------------------------------------
 
template <class T>
void Array2D<T>::resize(size_type rows, size_type columns)
{
   if (rows != m_rows || columns != m_columns) {
       T **newArr = new T*[rows];
       for (size_type i = 0; i < rows; ++i)
           newArr[i] = new T[columns];
 
       for (size_type i = 0; i < rows; ++i) {
           for (size_type j = 0; j < columns; ++j) {
               newArr[i][j] = T();
           }
       }
 
       size_type r = (m_rows > rows) ? rows : m_rows;
       size_type c = (m_columns > columns) ? columns : m_columns;
 
       for (size_type i = 0; i < r; ++i) {
           for (size_type j = 0; j < c; ++j) {
               newArr[i][j] = m_arr[i][j];
           }
       }
 
       for (size_type i = 0; i < m_rows; ++i)
           delete []m_arr[i];
       delete []m_arr;
       m_arr = newArr;
 
       m_columns = columns;
       m_rows = rows;
   }
}
//-----------------------------------------------------------------------------
 
template <class T>
bool Array2D<T>::swapRows(size_type i, size_type j)
{
   if ((i >= m_rows) || (j >= m_rows))
       return false;
 
   if (i == j)
       return true;
 
   T *a = m_arr[i];
   m_arr[i] = m_arr[j];
   m_arr[j] = a;
   return true;
}
//-----------------------------------------------------------------------------
 
#endif // ARRAY2D_H
 


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 15:13
Код
C++ (Qt)
int rows = kt1 + 2;
double **BL1 = new double *[rows];
for (int i = 0; i < rows; ++i)
   BL1[i] = new double [2];
Спасибо. Теперь собирается. Только теперь при
Код
C++ (Qt)
BL1[0][0] = 1.0;
вылетает на Segmentation fault.


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 15:16
m_ax, спасибо за классы! Если сейчас ничего не получится, буду их прикручивать. ;D


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: kambala от Июль 20, 2011, 15:20
ищи ошибку у себя - может где-то обращаешься за границу массива. и не забудь освободить память в конце работы массива.


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Igors от Июль 20, 2011, 17:54
Оно и понятно. Массив создался одномерный. Как сделать двумерный?
"Физически" нет 2-мерных, на самом деле все это дела адресной арифметики. Лучше сказать
"как мне сделать так чтобы можно было обращаться"
Код:
BL[0][0] = 1.0;
Способов много, напр

Код
C++ (Qt)
typedef double TPair[2];
TPair * BL = new TPair[kt + 1];
BL[0][0] = 1.0;
 
Да и так уж нужен именно 2-мерный? Спокойно можно все делать с одномерным
Код
C++ (Qt)
double * BL = new double[(kt + 1) * 2];
BL[i * 2 + 0] = 1.0;  // BL[i][0]
BL[i * 2 + 1] = 1.0;  // BL[i][1]
 

Позже переделаю. А пока, для экономии места, написал так.
Хм... нет ничего более постоянного чем временное :) Попробуйте снести все написанное к чертовой бабушке и написать "капитально" с продуманными структурами данных. Это совсем не так страшно как на первый взгляд. А цепляясь за имеющийся код Вы намного больше времени потеряете, да и не очень приятно то старье латать. Живите красиво/шикарно  :)


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: Martiro от Июль 20, 2011, 20:49
Проблема вся в том, что изначально приходится переписывать код написанный на VB. А нет ничего хуже, чем копаться в чужом коде. Да еще и написанном на другом языке с другими возможностями и правилами. Написал бы всё сам изначально, но слишком сложная мат. часть...  :(


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: shirushizo от Июль 21, 2011, 09:09
массивы никогда не передаются по значению
Пардон, тупанул, просто сижу по локоть в отладке проекта на бейсике, прошу простить  :-[


Название: Re: Как передать в функцию указатель на (двумерный) массив?
Отправлено: lenny от Август 02, 2011, 08:01
Передача двумерного массива в функцию.
В качестве бонуса получаем информацию о количестве элементов:
Код:
template <class T, ptrdiff_t i, ptrdiff_t j>
void f(T (&mas)[i][j])
{
   //mas - массив, i и j - размерность массива
}

int main()
{
    int m[12][27];

    f(m);

    return 0;
}
До компиляции двумерные массивы все-таки существуют.