Почему мое многомерное динамическое размещение в C не работает?
-
29-09-2020 - |
Вопрос
Я пытался выяснить проблему с моим распределением и использованием многомерного динамически распределяемого массива в 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;
}
Несколько замечаний:
- Не приводить возвращаемое значение
malloc()
. Начиная с C89, вам не нужно (void указатели неявно преобразуются в тип целевого указателя), и если вы забыли включить stdlib.h или иным образом не имеете прототипадля области действияmalloc()
приведение подавляет полезную диагностику «несовместимый тип для назначения». - Используйте оператор
sizeof
для выделяемого объекта, а не выражение типа.Это защищает вас в случае изменения типа целевого объекта;это также помогает с читабельностью, я думаю.
Это должно работать;у вас должен быть трехмерный массив двойного эквивалента
double cdr[NUM_REGIONS][numRatings][remQuarters];