tags:

views:

114

answers:

4

I'm trying to create a contiguous block of memory in one function call that has the first part of the memory as pointer arrays to the other blocks. Basically, I'm trying to do:

int **CreateInt2D(size_t rows, size_t cols)
{
    int **p, **p1, **end;
    p = (int **)SafeMalloc(rows * sizeof(int *));
    cols *= sizeof(int);
    for (end = p + rows, p1 = p; p1 < end; ++p1)
        *p1 = (int *)SafeMalloc(cols);
    return(p);
}

void *SafeMalloc(size_t size)
{
    void *vp;

    if ((vp = malloc(size)) == NULL) {
        fputs("Out of mem", stderr);
        exit(EXIT_FAILURE);
    }
    return(vp);
}

But with one block. This is as far as I've gotten:

int *Create2D(size_t rows, size_t cols) {
 int **memBlock;
 int **arrayPtr;
 int loopCount;
    memBlock = (int **)malloc(rows * sizeof(int *) + rows * cols * sizeof(int));
    if (arrayPtr == NULL) {
        printf("Failed to allocate space, exiting..."); 
        exit(EXIT_FAILURE);
    }
    for (loopCount = 1; loopCount <= (int)rows; loopCount++) {
        arrayPtr = memBlock + (loopCount * sizeof(int *));
        //I don't think this part is right.  do I need something like arrayPtr[loopCount] = ....
    }
 return(memBlock);
}
A: 

I'm not too clear about what you're trying to do, but your last piece of code is buggy. You test arrayPtr against NULL but never assign it. In the for() loop you assign to arrayPtr but don't actually do anything with it.

If you are looking for a 2D array that uses a single block of memory then what's wrong with:

int* array = (int*)malloc(rows * count * sizeof(int));
int* someCellPtr = &array[y * rows + x];

?

Andrew Grant
A: 

if you want to 2D array with one alloc, you can either use calloc:

int** p2DArray = (int**)calloc(rows,cols * sizeof(int));

or just malloc:

int** p2DArray = (int**)malloc(rows * cols * sizeof(int));

this allows normal indexing:

int nCellValue = p2DArray[row][col];
int* pCell = &p2DArray[row][col];
Necrolis
+1  A: 

Something like this

 int **Create2D(size_t rows, size_t cols) 
 {
    size_t cb = (rows * sizeof(int *)) + (rows * cols * sizeof(int));
    int * pmem = (int *)SafeMalloc(cb);

    int ** prows = (int **)pmem; 
    int * pcol = (int *)&prows[rows]; // point pcol after the last row pointer

    for (int ii = 0; ii < rows; ++ii)
    {
       prows[ii] = pcol;
       pcol += cols;
    }

    return prows;
}
John Knoeller
I think I get your answer, but I'm having trouble with the idea of allocating memory for row pointers and cols. So with that block of memory, cb, you can just typecast the pmem portion to portion it out? Like the first part being pointers to pointers, then pcol pointing to the the last row pointer, then initializing the cols and have the pointer to pointer prows point to the pcol? Something like that?
Crystal
yeah. You allocate the total, then use pointer math to get a pcol pointer to the first address _after_ the part that you want to assign to prows, then walk the pcol pointer and use it to initialize the prow array. the end result is one allocation, but with the same layout as your original code.
John Knoeller
@Crystal: check the code again, I had a bug in the loop. sorry.
John Knoeller
+1  A: 

It seems that you do not have a clear picture of exactly what you want to achieve. Document it! It will clear up your mind and besides if you do not understand it, nobody else will, and code like that is a nightmare to maintain (applies even to your own when time passes by).

To create a function that allocates a contiguous block of memory, you have to call SafeMalloc only once with the total amount of memory that will be used.

/*
 * Memory layout example for 2 rows and 3 cols
 *
 *                      1 1 1 1 1 1 1 1 1 1
 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * |P|P|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|C|
 * |1|2|1|1|1|2|2|2|3|3|3|1|1|1|2|2|2|3|3|3|
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 * P1 is a pointer coloum data for row 1, points to memory start + offset 2 (assuming sizeof(int) == sizeof(int *))
 * P2 is for row 2, points to memory start + offset 11
 * C1 is coloumn 1 data, etc
 */
int **CreateInt2D(size_t rows, size_t cols)
{
        int **memory_start, **p1, *col_data;
        size_t total_memory_to_allocate;

        total_memory_to_allocate = rows * sizeof(int *) + rows * cols * sizeof(int);
        memory_start = (int **) SafeMalloc(total_memory_to_allocate);

        for (col_data = (int *)(memory_start + rows), p1 = memory_start;
             p1 < (int **)col_data;
             ++p1, col_data += cols * sizeof(int))
                *p1 = col_data;

        return memory_start;
}

This example is based on keeping as close to your original as possible, John Knoeller's answer by using array subscription is probably a better way of doing it.

hlovdal