开发者

Declaring a 2-dimensional array of unknown size, C

开发者 https://www.devze.com 2023-01-04 12:09 出处:网络
I have an array declared as a member of a struct in C. The array is declared as: charmValue[MAXROWS][MAXCOLUMNS];

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 the开发者_运维百科re a better way to do this? I mean, should I declare these as pointers instead?

Thanks!


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;


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).


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


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


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:

  • I came across some code that declared a structure like this...
  • How can I dynamically allocate a multidimensional array?


I found that changing my approach was very useful when faced with a similar problem.

A vector of vectors filled the same task, avoided memory allocation obstacles, and kept the same familiar shorthand. There may be other pitfalls, but I have not encountered them yet.

//Declaration of mValues, undefined size:
std::vector< std::vector<char> > mValues; 

//Filling of mValues:
    int max_x = 100 ;
    int max_y = 100 ;
    char char_foo = 'a';
    for ( int x = 0; x <= max_x; ++x ) {
        vector<char> temp;
        for ( int y = 0; y <= max_y; ++y ) {
             temp.push_back( char_foo );
        }
        mValues.push_back( temp );
    }

// Referencing with familiar index notation:
    mValues[a][b]; //The a-th row's b-th element

If you are struggling with arrays, but strongly desire the familiar indexing language, I have found this to be a good alternative.

Note that indexing order A then B is going to be critical for memory usage when recalling this data. Failure to call the information in an A,B order will be deeply problematic if performance is an issue.

0

精彩评论

暂无评论...
验证码 换一张
取 消