Ошибка сегментации при попытке объявить 5D массив в программе на C - PullRequest
0 голосов
/ 12 апреля 2019

Я конвертирую программу из fortran77 в язык программирования C. В программе fortran объявляется массив 5D, как показано ниже, и код компилируется и работает хорошо. Но когда я конвертирую тот же код в C с теми же значениями, код C компилируется, но это вызывает ошибку сегментации.

Если эта проблема вызвана различной стандартной компоновкой распределения памяти многомерных массивов между двумя языками, я попробовал все комбинации измерений при объявлении массива в C, и во всех случаях он также дает «Ошибка сегментации».

Я также устал от метода calloc, показанного ниже, и он работает, но я не знаю, как назначить значения глобально объявленному массиву.

Примечание. Ошибка сегментации находится на этапе объявления (т. Е. На этом программа останавливается)

Итак, в основном мои вопросы: - Почему это работает в Фортране, но не в С?, И, - Как решить эту проблему в C?

 ! Fortran77 Code
  parameter (i2maxbin=38)     
  parameter (imaxbin=20)       
  parameter (Nid=10)      
  real*8 dNdpt(Nid,i2maxbin,imaxbin,imaxbin,imaxbin)

 /* C Code */
  const int i2maxbin = 38;
  const int imaxbin = 20;
  const int nID = 10;
  double dNdpt[nID][i2maxbin][imaxbin][imaxbin][imaxbin];

 /* Declaring using calloc */
double (*dNdpt)[nID][i2maxbin][imaxbin][imaxbin][imaxbin] = 
calloc(sizeof(*dNdpt), 38);

for(int i = 0; i < nID; i++)
{
    for(int j = 0; j < i2maxbin; j++)
    {
        dNdpt[i][j][0][0][0] = 12.22673423;
    }        
}

When executing it gives me this error

error: assignment to expression with array type
         dNdpt[i][j][0][0][0] = 12.22673423;
                              ^

Ответы [ 3 ]

0 голосов
/ 12 апреля 2019

Вы решаете это, создавая массив в куче вместо стека.

double* dNdpt = malloc(sizeof(double)*nID*i2maxbin*imaxbin*imaxbin*imaxbin);

затем отследите, где вы находитесь в этом гигантском массиве, рассчитав индекс

более простой пример:

double* my2dim = malloc(sizeof(double)*10*20); // 10 rows 20 cols

my2dim[3][2] = 10.0 would be written *(my2dim + 3 * 20 + 2) = 10.0;
0 голосов
/ 14 апреля 2019

следующий предложенный код:

  1. помещает массив в область видимости файла, а не в стек *
  2. аккуратно компилирует
  3. избегает использования динамического выделения памяти /free'ing
  4. без проблем работает и выходит без сбоев
  5. избегает использования VLA

А теперь предложенный код:

#define i2maxbin  38
#define imaxbin   20
#define nID       10



double dNptr[nID][i2maxbin][imaxbin][imaxbin][imaxbin];


int main( void )
{
    for(int i = 0; i < nID; i++)
    {
        for(int j = 0; j < i2maxbin; j++)
        {
            dNptr[i][j][0][0][0] = 12.22673423;
        }
    }
}
0 голосов
/ 12 апреля 2019

Размер стека в C, а также в C ++ очень ограничен, как правило, допускается 1D-массив с максимальным размером 1e5, и если мы принимаем «двойной» размер как 8 байтов, то это переводит в максимальный объем памяти 8 * 1e5 байт.

Теперь давайте посмотрим на ваш 5D-массив, он пытается выделить 10 * 38 * 20 * 20 * 20 = 3 040 000 «двойных» единиц, которые при преобразовании в память составляют 24 320 000 байтов, что значительно превышает размер выделенного стека в C или C ++. Вот почему вы получаете SEG-FAULT.

Вы можете попытаться инициализировать массив глобально таким образом, чтобы он выделял кучную память, которая обычно больше, чем стековая память, даже тогда максимальный размер ограничен 8 * 7 * 1e5 байтами в максимуме (зависит от вашей машины).

...