Почему мое многомерное динамическое размещение в C не работает?

StackOverflow https://stackoverflow.com/questions/3338160

Вопрос

Я пытался выяснить проблему с моим распределением и использованием многомерного динамически распределяемого массива в C. Я был бы очень признателен за любую помощь.

Я пробовал два подхода.Первое:

cdr = (double ***) malloc(NUM_REGIONS * sizeof(double **));
for(i=0; i<NUM_REGIONS; i++){
   cdr[i] = (double **) malloc(numRatings * sizeof(double *));
   for(j=0; j<numRatings; j++){
       cdr[i][j] = (double *) malloc(remQuarters * sizeof(double));
   }
}  

И второе:

tempPtr1 = (double *) malloc(NUM_REGIONS * numRatings * remQuarters * sizeof(double) );
tempPtr2 = (double **) malloc (NUM_REGIONS * numRatings * sizeof(double *));
cdr = (double ***) malloc(NUM_REGIONS * sizeof(double **));
for(i=0; i< NUM_REGIONS; i++){
    cdr[i] = tempPtr2 + i;
    for(j=0; j < numRatings; j++) cdr[i][j] = tempPtr1 + i * NUM_REGIONS + j;
}

Ни один из них не работает.В обоих случаях каждый cdr[i] указывает на одно и то же место.При первом входе в цикл 'i' все cdr[i] (т.е. cdr[0], cdr[1], cdr[2] и т. д.) получают одно и то же значение.Последующие циклы не меняют ни один из них.

Я подозреваю, что что-то происходит с приоритетом операторов или я неправильно разыменовываю, но я не смог понять это.

Спасибо.

ОБНОВИТЬ

Я собрал следующий упрощенный код, который, кажется, работает нормально.Но хотя результат полностью соответствует ожиданиям, я все еще получаю такое же странное поведение, когда прохожу его в отладчике.Я начинаю думать, что основная проблема с моим кодом может быть где-то в другом месте, и меня просто отвлекли проблемы с отладчиком (или, возможно, просто мое непонимание вывода).Есть ли известная причина, по которой просмотр «cdr [0]», «cdr [1]» и т. Д. В Visual Studio не показывает то, что я ожидаю?

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"

#define NUM_REGIONS 50


void printArray(double *inVec, int len){
    int i;
    for(i=0; i<len; i++) printf("%f\t",inVec[i]);
    printf("\n");
}

int main(array<System::String ^> ^args){

    int numRatings = 25, remQuarters = 100, i, j, k;
    double ***cdr;
    char dummy;

    cdr = (double ***) malloc(NUM_REGIONS * sizeof(double **)); 
    for(i=0; i<NUM_REGIONS; i++){ 
        cdr[i] = (double **) malloc(numRatings * sizeof(double *)); 
        for(j=0; j<numRatings; j++){ 
            cdr[i][j] = (double *) malloc(remQuarters * sizeof(double)); 
        } 
    }

    for(i=0; i<NUM_REGIONS; i++){
        for(j=0; j<numRatings; j++){
            for(k=0; k<remQuarters; k++){
                cdr[i][j][k] = 100*i + 10*j +k;
            }
        }
    }

    for(i=0; i<5; i++) printf("%f\t",cdr[1][1][i]);
    printf("\n");
    for(i=0; i<5; i++) printf("%f\t",cdr[3][1][i]);
    printf("\n");
    for(i=0; i<5; i++) printf("%f\t",cdr[1][3][i]);
    printf("\n");
    for(i=0; i<5; i++) printf("%f\t",cdr[i][i][i]);
    printf("\n");
    printArray(cdr[1][1], 5);
    printArray(cdr[3][3], 5);

    scanf("%c", &dummy);
    return 0;
}

Еще раз спасибо за все отзывы.

Это было полезно?

Решение 5

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

Отладчик выдал какой-то странный вывод, заставивший меня сосредоточиться на этой части кода.Я до сих пор не понимаю, почему мой отладчик делает это, а другие нет, но я займусь этим в другой раз.

Другие советы

Давным-давно в колледже я пришел к выводу, что многомерные массивы в C следует эмулировать одномерными массивами.Сначала нужно выделить достаточно большой буфер, чтобы вместить все элементы.Для двумерного массива это будет ncolumns*nrows*sizeof(element). Затем доступ к элементам массива осуществляется путем преобразования многомерных индексов в одномерный индекс.Для двумерного массива доступ к A(i,j) преобразуется в bufA[i*ncolumns+j].

Проблема с вашим разыменованием.cdr[i][j] не будет делать то, что вы хотите.Когда вы присваиваете cdr[i], вы помещаете указатель на этот индекс.Однако cdr[i][j] не разыменовывает cdr[i]. Он предполагает, что у вас есть прямоугольный блок памяти, и добавляет соответствующее значение к cdr, чтобы определить, где находится cdr[i][j].Вероятно, вам придется выполнять разыменование вручную с помощью *.

Мне было трудно понять, какую именно проблему вы видите.

Я попробовал следующее для многомерного массива двойников и не имел проблем:

int i, j;
int rows = 5;
int columns = 10;
int z_axis = 5;
double ***cdr = malloc(rows * sizeof(double **));
for (i = 0; i < rows; i++)
{
  cdr[i] = malloc(columns * sizeof(double *));
  for (j = 0; j < columns; j++)
  {
    cdr[i][j] = malloc(z_axis * sizeof(double));
  }
}

Подробности по этому вопросу см. в c-faq: http://c-faq.com/aryptr/dynmuldimary.html.

Что должно быть cdr?Трехмерный массив двойных чисел (это то, что я предполагаю, основываясь на вашем фрагменте)?2D-массив указателя на удвоение?Или указатель на двумерный массив double?

Предположим первое:

#include <stdlib.h>

int main(void)
{
  double ***cdr = malloc(sizeof *cdr * NUM_REGIONS);
  if (cdr)
  {
    size_t i;
    for (i = 0; i < NUM_REGIONS; i++)
    {
      cdr[i] = malloc(sizeof *cdr[i] * numRatings);
      if (cdr[i])
      {
        cdr[i][j] = malloc(sizeof *cdr[i][j] * remQuarters);
      }
    }
  }
  return 0;
}

Несколько замечаний:

  1. Не приводить возвращаемое значение malloc(). Начиная с C89, вам не нужно (void указатели неявно преобразуются в тип целевого указателя), и если вы забыли включить stdlib.h или иным образом не имеете прототипадля области действия malloc() приведение подавляет полезную диагностику «несовместимый тип для назначения».
  2. Используйте оператор sizeof для выделяемого объекта, а не выражение типа.Это защищает вас в случае изменения типа целевого объекта;это также помогает с читабельностью, я думаю.

Это должно работать;у вас должен быть трехмерный массив двойного эквивалента

double cdr[NUM_REGIONS][numRatings][remQuarters];
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top