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


Автор: KIDD 18.5.2004, 06:50
Товарищи, помогите!

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

**
**
**
**
**
**
...
...

И еще похожий вопрос:

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

**...
****...
**...
****...
**...
...


Заранее спасибо

Автор: chipset 18.5.2004, 07:04
массив обьектов типа vertex
Добавлено @ 07:04
тьфу! массив обьектов типа vector smile.gif

Автор: dargaard 18.5.2004, 07:06
В C

Код

       int **t;
       int k;
       int I=10;
       int J=10;

       t = (int**) malloc(sizeof(int*) * I );
       for (k=0; k<I; k++) {
               *(t+k) =(int*) malloc(sizeof(int) * J);
       }

       t[1][1]=10;


СУВ.

Автор: chipset 18.5.2004, 07:10
второй вопрос, засунуть в качестве темплейта vector'y "vector". а у каждого "строчного" vector'a пусть будет обьекты X
сейчас dargaard ответит без использования С++ и вопрос будет полностью решен smile.gif

Автор: dargaard 18.5.2004, 07:11
chipset
злой тыsad.gif

Автор: chipset 18.5.2004, 07:15
нет я очень добрый, просто немного усталый... thumbs-up.gif
голова кипит, видишь векторы с вертексами путаю...

Автор: AndyY 18.5.2004, 09:06
для случая неопределенного кол-ва строк - согласен, хорошо будет список указателей.

Для варианта, когда нет данных о столбцах и о строках, (тем более когда их число может изменятся во время работы программы):
сложить все данные в map (самобалансирующеесе дерево, ключ - координаты).
Если данных много, а накладные расходы байт по 8 на элемент высоки, то в map сложить небольшие куски (скажем, по 10*10 элементов)

Но все это имеет смысл только при достаточно больших массивах данных.

Автор: gepard 18.5.2004, 09:21
Зайти в FAQ по С++, там есть вопрос про динам. массивы.

Автор: mr.DUDA 18.5.2004, 10:05
Можно и без векторов обойтись, если хранить размер массива на 4 байта раньше его начала. В Delphi есть очень удобные функции для работы с массивами (GetMem, FreeMem, Copy и пр.), и именно так они и реализованы. Вот переделанный вариант под С++, и пример -- как можно выделить и работать с массивом, в котором не известно ни количество строк, ни размер каждой отдельной строки:
Цитата
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

//////////////////////////////////////////////////////////////////////////
// удобные функции для работы с памятью -
// GetMem, FreeMem, Copy, Resize, GetLength

template <typename T> void GetMem(T *&ptr, int size)
{
   
int *psize=(int *)malloc(size*sizeof(T)+sizeof(int));
    *
psize = size;
   
ptr = (T*)(psize+1);
   
memset(ptr, 0, size+sizeof(int));
}

template <typename T> void FreeMem(T *&ptr)
{
   
if(!ptr) return;
   
int *psize = ((int *)ptr)-1;
   
free(psize);
   
ptr = NULL;
}

template <typename T> int GetLength(T ptr)
{
   
return ((ptr==NULL)?0: (*((int*)ptr-1)));
}

template <typename T> void Resize(T *&ptr, int size)
{
   
if(size==0)
    {
       
FreeMem(ptr);
       
return;
    }

    T
*old = ptr;
   
GetMem(ptr, size);
   
if(old != NULL)
    {
       
int prev_size = GetLength(old);
       
int len = (prev_size > size)?size:prev_size;
       
if(prev_size) memcpy(ptr, old, size*sizeof(T));
       
FreeMem(old);
    }
}

template <typename T> void Copy(T *&dest, const T *&src)
{
   
SetLength(dest, GetLength(src));
   
memcpy(dest, src, Length(dest)*sizeof(T));
}



//////////////////////////////////////////////////////////////////////////


// выделяет массив высотой в неизвестное кол-во строк,
// в каждой строке - случайное количество элементов

int **RandomAlloc()
{
   
// настраиваем генератор случайных чисел
   
time_t tm; time(&tm); srand(tm);
   
// обычный двумерный массив
   
int **arr = NULL;
   
// выделяем память под rand() строк, 10 - максимум
   
GetMem(arr, rand()%10+1);
   
// задаём случайное количество столбцов в каждой строке
   
for(int y=0; y<GetLength(arr); y++)
       
GetMem(arr[y], rand()%10+1);
   
return arr;
}

// функция, которая работает с полученным массивом
int main(int argc, char* argv[])
{
   
// выделяем массив
   
int **arr = RandomAlloc();
   
   
// изменяем размеры последней строки
   
Resize(arr[GetLength(arr)-1], 10);


    // заполняем его данными
   
for(int y=0; y<GetLength(arr); y++)
       
for(int x=0; x<GetLength(arr[y]); x++)
           
arr[y][x] = y;
       

   
// выводим на экран результирующий массив
   
for(y=0; y<GetLength(arr); y++)
    {
       
printf("\nString %d (%d elements):", y, GetLength(arr[y]));
       
for(int x=0; x<GetLength(arr[y]); x++)
           
printf(" %d", arr[y][x]);
    }

   
// вот и всё
   
printf("\n");

   
return 0;
}

Автор: Neo 20.5.2004, 00:55
Вот нам как раз на лекции такой пример давали, когда сведения о количестве строк и столбцов удобно хранить в нескольких байтах перед началом массива. Крайне удобно. Может кому понадобится такой исходник....
Цитата
  #include <stdio.h>
   #include <stdlib.h>
   #include <malloc.h>

   #define MAXVAL 1000

   void    *Malloc     ( size_t size );
   double **MakeMatr   ( size_t n, size_t m );
   void     DelMatr    ( double *Matr[] );
   size_t   GetN       ( double *Matr[] );
   size_t   GetM       ( double *Matr[] );
   void     RandomMatr ( double *Matr[] );
   void     OutMatr    ( char *name, double *Matr[] );

   void main( void )
   {
      int n = 5, m = 6;
      double **A;
      /* Выделение памяти */
      A = MakeMatr(n, m);
      /* Заполнение и распечатка */
      RandomMatr( A );
      OutMatr("A", A );
      /* Освобождение памяти */
      DelMatr(A);
   }

   void RandomMatr ( double *Matr[] )
   {
      int i, j, n = GetN(Matr), m = GetM(Matr);
      for(i = 0; i < n; i++)
         for(j = 0; j < m; j++)
            Matr[i][j] = random(MAXVAL) + 1;
   }

   void OutMatr( char *name, double *Matr[] )
   {
      int i, j, n = GetN(Matr), m = GetM(Matr);
      printf("\nMatrix %s\n---------------\n", name);
      for(i = 0; i < n; i++)
      {
         for(j = 0; j < m; j++)
            printf("%8.1lf  ", Matr[i][j]);
         printf("\n");
      }
   }

   void * Malloc( size_t size )
   {
      void *p = malloc(size);
      if( !p )
         { printf("Not enough memory!\n"); exit(1); }
      return p;
   }

   /* Конструктор матрицы*/
   double **MakeMatr( size_t n, size_t m )
   {
      double **Matr;  size_t i;
      Matr = (double**) Malloc( 2 * sizeof(size_t)
                                + n * sizeof(double *) );
      (size_t *)Matr += 2;
      for(i=0; i<n; i++)
         Matr[i] = (double *) Malloc( m * sizeof(double) );
      Matr[n] = NULL;
      *( (size_t *)Matr - 2 ) = n;
      *( (size_t *)Matr - 1 ) = m;
      return Matr;
   }

   size_t   GetN( double *Matr[] )
   {
      return *( (size_t *)Matr - 2 );
   }

   size_t   GetM( double *Matr[] )
   {
      return *( (size_t *)Matr - 1 );
   }

   /* Деструктор */
   void DelMatr( double *Matr[] )
   {
      size_t i, n = GetN(Matr);
      for(i = 0; i < n; i++) free(Matr[i]);
      free( (size_t *)Matr - 2 );
   }

Собственно отличия от исходника mr.DUDA никакого. Формально, как я понимаю. Разве что пара функций, которые определяют длину строки или столбца....

Автор: mr.DUDA 20.5.2004, 10:23
Цитата
Собственно отличия от исходника mr.DUDA никакого. Формально, как я понимаю. Разве что пара функций, которые определяют длину строки или столбца....

...и привязка к типу данных double (а у меня все функции - шаблоны, можно хранить в массивах произв. данные)

Автор: KIDD 20.5.2004, 15:07
А я похоже более легкий выход нашел, халявный правда, но выход : В Visual есть такой класс CArray ( и его производные - CObArray,CIntArray...), создав объект которого, можно в него загонять свои данные, причем цивильно, с помощью специальных функций.
Спасибо за ответы, всем!!!

Автор: mr.DUDA 20.5.2004, 16:08
Цитата
А я похоже более легкий выход нашел, халявный правда, но выход : В Visual есть такой класс CArray ( и его производные - CObArray,CIntArray...), создав объект которого, можно в него загонять свои данные, причем цивильно, с помощью специальных функций

Лёгкий путь не всегда самый верный. Насчёт CArray: я ещё год назад считал MFC'шные контейнеры удобными и самыми лучшими smile.gif ... Поверь мне, тип vector из библиотеки STL гораздо проще и удобнее чем CArray. Подробный туториал, как организовать динамические массивы, списки и пр., есть в нашем FAQ по С++, здесь:
http://forum.vingrad.ru/index.php?showtopic=16860

Автор: KIDD 20.5.2004, 16:28
mr. DUDA!

Меня интересует, можно ли в vector запихать свой объект.

Цитата

CMyPoint point;

vector < CMyPoint > array;

point.a=100;

array.push_back(point);// Ну предположим мы туда его поместили, а еcли там функции есть которыми я хочу воспользоваться это так->

array[0].function;??? да?



А чем плохи СArray и кампания?

У меня ксати возникли с ними проблемы:


Вроде все правильно делаю

Цитата

CArray <CMyPoint,CMyPoint> array; //->это лежит в классе документ

/////
CMyPoint point;//->делаем во View

point.a=100;
pDoc->array.Add( point);


А Выдает ошибку:

Цитата


error C2664: 'CArray<TYPE,ARG_TYPE>::Add' : cannot convert parameter 1 from 'CMyPoint' to 'CMyPoint'
        with
        [
            TYPE=CMyPoint,
            ARG_TYPE=CMyPoint
        ]



????????



Автор: mr.DUDA 20.5.2004, 16:36
KIDD, отвечаю по порядку:

1) запихать в вектор свой объект можно, подробности - в статье в FAQ

2) CArray и компания плохи тем, что:

а) тормознутые по сравнению с STL,
б) привязаны к MFC,
в) неудобные в использовании (один только POSITION чего стоит sad.gif ),
г) кроме CList, CArray и CMap в MFC больше ничего нету !
д) мелкософт сама отказалась от своих контейнеров (как и от MFC в целом) и стала продвигать собственные "расширения" STL - класс hash_map, например
е) в Инете можно найти кучу разных вариантов STL (с одним синтаксисом, но разной реализацией), и некоторые из них внутри себя супер-навёрнутые и быстродействующие - например, STLPort

3) чтобы твой пример с CArray скомпилился, нужно добавить в класс CMyPoint реализацию конструктора копирования либо оператора "=". А если пользоваться vector, то таких проблем нету ! Кстати, конструктор копирования в MFC-шных контейнерах - эта проблема когда-то возникла и у меня, и необходимость "руками" прописывать присвоения всех по порядку полей одного объекта полям другого - просто бесила...

Автор: KIDD 20.5.2004, 16:46
Не знаю, что я накосячил, но ща применил vector:
Цитата

///CDoc
#include < list>
#include < vector>
using namespace std;

vector <CMyPoint> array;

///View

CMyPoint point2;

pDoc->array.push_back(point2);
pDoc->array[0].point=point;



Выдает ошибку
Цитата

error C2558: class 'CMyPoint' : no copy constructor available or copy constructor is declared 'explicit'



Че ему не нравится; Класс (CMyPoint::CObject) наипростейший,урезал его полностью, оставив два пустых констр-деструктора и переменную CPoint point.

Автор: Sined 20.5.2004, 16:54
Сорри, но тв пишешь
Цитата
pDoc->array[0].point=point;

В силу опять таки своей ограниченности я не вижу у тебя СMyPoint с именем point.
Cкорее всего, он Не принадлежит к классу CMyPoint и для не НЕ определен copy_constructor

может в CMyPoint надо вставить

CMyPoint& operator=(CPoint&);
с следущим синтаксисом
CMyPoint& СMyPoint::operator=(CPoint& p)
{
point=p;
return *this;
}


Автор: DENNN 20.5.2004, 16:55
to mr.DUDA
Цитата
и необходимость "руками" прописывать присвоения всех по порядку полей одного объекта полям другого - просто бесила..

А зделать нечто вроде такого не судьба?


Код

CMyClass
{
public:
int a;
double b;
char szName[15];
//.. и т.д.
void CopyToAnother(CMyClass& target)
{
memcpy (&target,*this,sizeof(this);
}

Автор: Sined 20.5.2004, 17:12
Если мне не изменяет память this все-таки указатель, т.е. 4 байтовое число.и sizeof(this) должно вернуть 4, хотя это личное мнение кролика.

Автор: KIDD 20.5.2004, 17:23
Sined!


По фиг как писать -

Цитата

pDoc->array[0].point=point;//point - это переменная класса CMyPoint , а не объект!!!, a array[0] - первый объект (класса CMyPoint) в массиве.


либо
Цитата

point2.point=point;
pDoc->array.push_back(point2);

Автор: DENNN 20.5.2004, 18:46
Цитата
т.е. 4 байтовое число.и sizeof(this) должно вернуть 4,

Сорри, но можно написать и так:

Код
sizeof(CMyClass)

Автор: Sined 20.5.2004, 19:10
Цитата
По фиг как писать -


Цитата

pDoc->array[0].point=point;//point - это переменная класса CMyPoint , а не объект!!!, a array[0] - первый объект (класса CMyPoint) в массиве.

Это вопрос или утверждение?
Если утверждение, то тогда приводи весь текст, где написано, что point--переменна класса CMyPoint;
Если вопрос, то, видимо, не пофиг, если компилер ругается.

Автор: mr.DUDA 20.5.2004, 19:35
отвечаю KIDD'у и DENNN'у:
Цитата
Че ему не нравится; Класс (CMyPoint::CObject) наипростейший,урезал его полностью, оставив два пустых констр-деструктора и переменную CPoint point.

конструктор копирования необходим для классов, имеющих в своём составе поля, которые нельзя присвоить оператором "=". Компилятор сам сгенерирует конструктор копирования для класса CMyPoint, если все поля входящие в класс CMyPoint, можно присвоить оператором "=". Иначе (как и получилось у KIDD'а из-за переменной CPoint), требуется написать свой собственный конструктор копирования, в котором реализовать все сложные и не очень сложные процедуры присваивания полей одного объекта (p) другому (this)

Цитата
А зделать нечто вроде такого не судьба?

не судьба для сложных объектов (имеющих в составе указатели и ссылки)

Автор: KIDD 20.5.2004, 22:29
Ok,извиняюсь, я погорячился, Sined!

Цитата

class CMyPoint : public CObject
{
public:
CMyPoint();
virtual ~CMyPoint();
CPoint point;

};

/////////////
vector <CMyPoint> array;
/////////////////////

CMyPoint point2;

point2.point=point;//значение переменной point(которая справа) берется от координаты мыши(OnMouseLDown)
pDoc->array.push_back(point2);



Выдает ошибку
error C2558: class 'CMyPoint' : no copy constructor available or copy constructor is declared 'explicit'


Что неправильно????

Автор: Sined 21.5.2004, 11:32
Вроде бы mr.DUDA ответил, что для сложных классов(CPoint )может тоже входит. Надо явно определять к.конструктор. Хотя по стандарту вроде бы любой класс поддерживает побитовое копирование и твой пример должен сработать. Если нет, то может сработать следующий пример.
CMyPoint::CMyPoint()
:point()
{

}



CMyPoint& СMyPoint::operator=(CPoint& p)
{
point=p;
return *this;
}


т.е. разделить конструктор и присвоение.



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