I have been trying to figure out the problem with my allocation and use of a multidimensional dynamically allocated array in C. I'd really appreciate any help.
I've tried two approaches. The first:
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));
}
}
And the second:
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;
}
Neither is working. In both cases, each cdr[i] ends up pointing to the same place. The first time I step into the 'i' loop, all cdr[i] (i.e. cdr[0], cdr[1], cdr[2], etc.) get set to the same value. Subsequent loops then don't change any of them.
I suspect there's something going on with operator precedence or I'm dereferencing wrong, but I haven't been able to figure it out.
Thanks.
UPDATE
I put together the following simplified code, which seems to work fine. But while the output is completely as expected, I'm still getting the same weird behaviour as I step through it in the debugger. I'm starting to think the fundamental problem with my code might be elsewhere, and I've just been diverted by issues with the debugger (or probably just with my misunderstanding of the output). Is there a known reason why a watch on 'cdr[0]', 'cdr[1]', etc. in Visual Studio wouldn't show what I'm expecting it to show?
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#define NUM_RE开发者_开发知识库GIONS 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;
}
Thanks again for all the feedback.
A long time ago at college I concluded that multidimensional arrays in C should be emulated with 1D arrays. First one needs to allocate a buffer big enough to hold all of the elements. For a 2D array that would be ncolumns*nrows*sizeof(element)
. Then one accesses the array elements by transforming multidimensional indices to 1D index. For a 2D array, accessing A(i,j) translates to bufA[i*ncolumns+j]
.
The problem is with your dereferencing. cdr[i][j]
won't do what you want. When you assign cdr[i]
, you're putting a pointer at that index. However, cdr[i][j]
doesn't dereference cdr[i]
. It assumes you have a rectangular block of memory and adds the appropriate value to cdr to determine where cdr[i][j]
lives. You're probably going to have to do the dereferencing manually with *
s.
I had a tough time figuring out exactly what problem you are seeing.
I tried the following for a multidimensional array of doubles and had no problems:
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));
}
}
See the c-faq for specifics on this very issue: http://c-faq.com/aryptr/dynmuldimary.html
What is cdr
supposed to be? A 3D array of double (which is what I'm assuming, based on your snippet)? A 2D array of pointer to double? Or a pointer to a 2D array of double?
Assuming the first:
#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;
}
A few things to note:
- Don't cast the return value of
malloc()
. As of C89, you don't need to (void pointers are implicitly converted to the target pointer type), and if you forget to include stdlib.h or otherwise don't have a prototype formalloc()
in scope, the cast will suppress a useful "incompatible type for assignment" diagnostic. - Use the
sizeof
operator on the object being allocated, not a type expression. This protects you in case the type of the target object changes; it also helps with readability, I think.
This should work; you should have a 3D array of double equivalent to
double cdr[NUM_REGIONS][numRatings][remQuarters];
It turns out that the code as written worked (though it did have room for style improvements, as several people pointed out). I tracked the real problem in my code to some file input that was too big for the buffer (which is a lesson for me in error checking).
The debugger gave some weird output that had me focusing on this part of the code. I still don't understand why my debugger is doing this when others aren't, but I'll deal with that another day.
精彩评论