tags:

views:

82

answers:

5

I have an array declared as a member of a struct in C. The array is declared as:

char        mValue[MAXROWS][MAXCOLUMNS]; 

where MAXROWS and MAXROWS are 300. Is there a better way to do this? I mean, should I declare these as pointers instead?

Thanks!

+1  A: 

Another technique is to create a linear array and then convert it to 2d:

char *p = malloc(ROWS * COLUMNS);

// To access x, y
// This is in row-major ordr
*(p + (x * COLUMNS) + y);
R Samuel Klatchko
but how should I declare the array in the struct?
Juli
@Juli - when doing it manually like this, you define it as `char *` - `struct foo { char *arr; int p; };`
R Samuel Klatchko
+1  A: 

As the previous poster suggested, a good way is to create a linear array and then "convert it to 2D". Many times, caching the 2D pointers greatly increases the speed of programs that use this array, like so:

mystruct *p = (mystruct*)calloc(ROWS * COLUMNS, sizeof(mystruct));
mystruct **p2 = (mystruct**)calloc(ROWS, sizeof(mystruct*));
for (int i = 0; i < ROWS; i++)
    p2[i] = p + i*COLUMNS;

Then, you can simply access a 2D element with:

p2[row][column] = foo;
Reinderien
A: 

If the array needs to have a dynamic size, then you either need to make it a pointer or make the array the last member of the struct and play games when allocating the structure size.

Relevant comp.lang.c FAQ entries:

jamesdlin
+1  A: 

If all your rows are the same size, you should use a 1D array with the rows stored in sequence:

ABCDE
FGHIJ   --->  ABCDEFGHIJKLMNO
KLMNO

The element at row i, column j will be at index i * ROW_LENGTH + j in the 1D array.

You can allocate the array using malloc(ROW_LENGTH * NUM_ROWS).

nornagon
A: 

I find that, for this kind of code, its better to create helper functions for accessing the elements. Depending on your profiling data, it may make sense to turn these into macros, but be extra careful.

#include <stdio.h>  /* For printf */

/* This is the bit that would go in a header, like char2darray.h */
#include <stdlib.h> /* For calloc */
#include <assert.h> /* For assert */

struct Char2DArray
{
   int rows;
   int columns;
   char *values;
};

/* This is the bit that would go in a source file, like char2darray.c */

void C2DA_initialize(struct Char2DArray *array, int rows, int columns)
{
    assert(array != 0);
    array->values = calloc(rows * columns, sizeof(char));
    array->rows = rows;
    array->columns = columns;
}

void C2DA_set(struct Char2DArray *array, int row, int column, int value)
{
    assert(array != 0);
    assert(array->values != 0);
    assert(row < array->rows);
    assert(row >= 0);
    assert(column < array->columns);
    assert(column >= 0);

    array->values[(row * array->rows) + column] = value;
}

char C2DA_get(struct Char2DArray *array, int row, int column)
{
    assert(array != 0);
    assert(array->values != 0);
    assert(row < array->rows);
    assert(row >= 0);
    assert(column < array->columns);
    assert(column >= 0);

    return array->values[(row * array->rows) + column];
}

void C2DA_free(struct Char2DArray *array)
{
    free(array->values);
    array->values = 0;
}

/* Here's a main.c to use it */
int main()
{
    struct Char2DArray a;
    C2DA_initialize(&a, 16, 16);
    unsigned char c = 0;
    int x, y;
    for (x=0; x<16; x++) {
        for (y=0; y<16; y++) {
            C2DA_set(&a, x, y, (char)c);
            c++;
        }
    }
    printf("Character with hex value 0x55 is %c\n", C2DA_get(&a, 5, 5));
    C2DA_free(&a);
    return 0;
}
jwhitlock