На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Выделение памяти , Помогите разобраться
    Добрый день!
    Есть кусок чужой библиотеки, которую хочу скомпилировать под VS. Сломал уже всю голову.
    Проблемный код:
    ExpandedWrap disabled
      typedef real Grid[NBINS];
      #define Array(type, var, n1, n2) type (*var)[n2] = alloca((n1)*(n2)*sizeof(type)) // Видимо это эквивалентно Array(type, var, n1, n2) type var[n1][n2]
      Array(Grid, margsum, NCOMP, NDIM); // Так компилируется: Array(Grid, margsum, NCOMP, 3/*NDIM*/);


    Проблема в том, что NDIM не константа и VS ругается. Пробовал выделять память динамически:
    ExpandedWrap disabled
      Grid ***margsum = malloc(NCOMP * NDIM * NBINS * sizeof(real));


    Этот вариант компилируется, но программа падает на строке:
    ExpandedWrap disabled
      Grid *m = &margsum[0][0];
      ...
      m[dim][bin[dim]] += wfun; <- ТУТ


    Подскажите, пожалуйста, как корректно выделить память динамически. Заранее благодарен.
    Сообщение отредактировано: SGregory -
      Цитата SGregory @
      Проблема в том, что NDIM не константа и VS ругается
      Этот (библиотечный) код использует C99. У тебя какой язык? На Плюсах это проще вообще не так делать.
      Цитата SGregory @
      Пробовал выделять память динамически:
      ExpandedWrap disabled
        Grid ***margsum = malloc(NCOMP * NDIM * NBINS * sizeof(real));


      Этот вариант компилируется, но программа падает на строке:
      ...
      Естественно. Эта структура данных неэквивалентна исходной. Массив указателей далеко не то же самое, что массив массивов. Первый хранит указатели, и sizeof(*margsum) будет равен размеру указателя; второй хранит массивы, и соответственно sizeof(*margsum) будет равен размеру массива. Вся адресная арифметика меняется, потому [] индексируют чушь.

      Добавлено
      Тебе что конкретно надо? Если сохранить исходный формат данных, то это одно, если это не обязательно, то проще иначе.
        Qraizer, дело в том что библиотека не моя, поэтому сильно корежить очень не хочется, понимаю прекрасно, что через new/delete существенно проще.
        Нужно путем минимальных изменений заставить работать :) Т.е. идеально сохранить исходный формат данных. Буду благодарен, если поможете :)
        Сообщение отредактировано: SGregory -
          Цитата SGregory @
          Подскажите, пожалуйста, как корректно выделить память динамически. Заранее благодарен.


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

          ExpandedWrap disabled
            MyElement **p = new MyElement*[X];
            p[0] = new MyElement[Y];
            p[1] = new MyElement[Y];


          и в обратном порядке правильно удалить из памяти. Это если тебе матрицу надо.
            ter_nk_, спасибо. Но мне необходим С код, т.к. библиотека написана на чистом С и влезать в ее внутренности не хочется.
              Ты в библиотечную функцию подсовываешь указатель на выделенную память, сделано это с помощью библиотечной функции или нет, ей же не важно, ей нужны ячейки памяти данные писать. Если ты используешь VS то ты должен работать с памятью с помощью С++ функций, это new delete, а malloc это С. Сами new delete реализованны с помощью malloc и т.д. Не нужно думать об этом.
                ter_nk_, нет совсем так, это внутренность библиотеки. Она не адаптирована под VS, я ее пытаюсь заставить работать.
                  в VS есть alloca, только называется она _alloca

                  _alloca

                  Может тебе поможет?
                    Цитата ter_nk_ @
                    Сами new delete реализованны с помощью malloc и т.д.
                    В VS это так, но в общем случае это необязательно.
                    SGregory, самый топорный вариант описал ter_nk_:
                    ExpandedWrap disabled
                      Grid ***margsum = malloc(n1 * sizeof(*margsum));
                      int i, j;
                       
                      for (i=0; i<n1; ++i)
                      {
                        margsum[i] = malloc(n2 * sizeof(**margsum));
                        for (j=0; j<n2; ++j)
                          margsum[i][j] = malloc(NBINS * sizeof(***margsum));
                      }
                       
                      /* ... */
                       
                      for (i=0; i<n1; ++i)
                      {
                        for (j=0; j<n2; ++j)
                          free(margsum[i][j]);
                        free(margsum[i]);
                      }
                      free(margsum);
                    Этот вариант позволит работать с margsum как и раньше, с тремя измерениями массива, но структура данных в памяти будет представлена совсем по-другому: исходная структура была массивом массивов массивов real, каждое измерение которого суть статический массив; в этой же структуре данных каждое измерение суть динамический массив, и margsum является массивом указателей на указатели на указатели на real. В целом это не проблема, кроме как где-то в коде важно, чтобы margsum был представлен линейным и непрерывным блоком памяти.
                    Сообщение отредактировано: Qraizer -
                      Спасибо! Попробую уже завтра. О результатах напишу.
                        P.S. Исходную структуру данных в C90 при переменном n2 сохранить сложно, т.к. это означает, что чтобы сохранить статичность массива, нужно каждый раз объявлять новый тип этого статического массива, зависящего от размера n2. Ведь
                        ExpandedWrap disabled
                          int a1[123];
                          int a2[321];
                        имеют разные типы: a1 имеет тип int[123], а a2 – int[321]. Размер массива входит составной частью в синопсис его типа.
                        Сообщение отредактировано: Qraizer -
                          Qraizer, действительно, не работает, хотя компилирует.
                          Видимо придется разбираться со внутренностями библиотеки. В любом случае спасибо!
                            Цитата Qraizer @
                            P.S. Исходную структуру данных в C90 при переменном n2 сохранить сложно

                            Да и вообще, для таких вещей, как мне кажется, было бы проще делать всё указателями.

                            Что то на вроде:

                            ExpandedWrap disabled
                              typedef struct Array {
                                  void **array;
                                  int sizeX;
                                  int sizeY;
                              } Array;



                            ну, соответственно, выделение:

                            ExpandedWrap disabled
                              Array *Arrays_Create(int sizeItem, int x, int y){
                               
                                  Array *array = (Array*)malloc(sizeof(Array));
                                  array->array = malloc(sizeof(void**));
                               
                                  int i1;
                                  int i2;
                                  for(i1=0;i1<y;i1++) {
                                      array->array[i1] = (void*)malloc(sizeof(void*));
                                      for(i2=0;i2<x;i2++){
                                          array->array[i1][i2] = (void*)malloc(sizeItem);
                                      }
                                  }
                               
                                  array->sizeX=x;
                                  array->sizeY=y;
                               
                                  return array;
                              }
                               
                              void Arrays_Delete(Array* array){
                                  int i1;
                                  int i2;
                                  for(i1=array->sizeY-1;i1>=0;i1--){
                                      for(i2=array->sizeX-1;i2>=0;i2--){
                                          free(array[i1][i2])
                                      }
                                      free(array->array[i1]);
                                  }
                                  free(array);
                              }


                            В старых сях, во многих местах подобное использовалось. Вся ответственность за соответствия типов целиком и полностью ложиться на вас, зато, получаете довольно мощный (для сей старого стандарта) набор функциональности. Используя массивы в стеке вы делаете оптимизацию, за которую и платите совместимостью.

                            У меня даже остались образцы кроссплатформенных велописедов-коллекций на старых сях :D
                            Сообщение отредактировано: VisualProg -
                              Цитата SGregory @
                              Qraizer, действительно, не работает, хотя компилирует.
                              Видимо придется разбираться со внутренностями библиотеки.
                              Значит действительно ей важно, чтобы весь массив лежал одним линейным регионом. Это тоже можно, как у тебя вначале было одним malloc()-ом, только тип нужно просто *margsum. Но индексировать придётся иначе – считать вручную. Можно написать макрос, который будет переводить n1, n2 и NBINS в индекс в этом линейном векторе. Можно соорудить себе вспомогательный массивы указателей на начала каждого второго и третьего измерений.
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0,0521 ]   [ 16 queries used ]   [ Generated: 29.03.24, 06:46 GMT ]