Почему мое многомерное динамическое распределение в C не работает? - PullRequest
2 голосов
/ 26 июля 2010

Я пытался выяснить проблему с моим размещением и использованием многомерного динамически размещаемого массива в 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 ]

6 голосов
/ 26 июля 2010

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

1 голос
/ 27 июля 2010

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

1 голос
/ 26 июля 2010

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

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

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));
  }
}

См.-faq для деталей по этой самой проблеме: http://c -faq.com / aryptr / dynmuldimary.html

0 голосов
/ 27 июля 2010

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

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

0 голосов
/ 27 июля 2010

Что должно быть cdr?3D массив double (что я предполагаю, основываясь на вашем фрагменте)?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];
...