0

I want to read in a file whose first line gives me the dimensions for the array. For example:

4 3

Then I want my program to assign rows = 4 and columns = 3. What is the proper way to allocate memory for this multidimensional array assuming that it holds integers?

Since the size of an integer is 4 bytes, am I right in assuming that it is:

int** multiArray;

... code to read in first line of file and assign value to rows and columns

multiArray = malloc(sizeof(int) * rows * columns));

Or in other words, is it correct to allocate 48 bytes of memory for my [4][3] integer array?

Jack
  • 131
  • 1
  • 3
  • 13
  • 1
    No. multiArray = malloc(sizeof(int *) * rows); then malloc each row separately. – Jiminion Jun 25 '14 at 03:52
  • 1
    @Jim Thanks! Do you have an example of what this would look like syntactically? If I follow your logic, I am thinking something like `for (i = 0; i < rows; i++) { multiArray[i] = malloc(sizeof(int) * columns)); }`. Is this correct or would I still need the size of an integer pointer? – Jack Jun 25 '14 at 04:01
  • you got it, that should work. You can also just alloc rows*cols integers, but then you'd have to manually index through a 1 dimensional pointer, which doesn't seem like what you want to do. What unxnut suggests would work too. – Jiminion Jun 25 '14 at 04:17

2 Answers2

1

One way could be:

int * array = ( int * ) malloc ( rows * columns * sizeof ( int ) );
int ** multiarray = ( int ** ) malloc ( rows * sizeof ( int * ) );
for ( int i = 0; i < rows; i++ )
    multiarray[i] = array + i * columns * sizeof ( int );
unxnut
  • 8,509
  • 3
  • 27
  • 41
  • [Don't cast malloc](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) – M.M Jun 25 '14 at 03:55
  • Interesting technique. Are there any downsides? Only thing I can think of is writing past arrays bounds might fail in a somewhat different way. – Jiminion Jun 25 '14 at 05:33
  • One downside is that it's slow to allocate everything and slower to free everything later. The other downside its that it's slower to use for large arrays. To read an integer you'd essentially be doing `tempPtr = multiarray[row]; value = tempPtr[column]` (2 pointer dereferences) rather than `value = multiarray[row * columns + column]` (one dereference); and for large arrays the cache miss is going to cost more than the calculation. The third disadvantage is that it costs more memory (an additional pointer per row). – Brendan Jun 25 '14 at 05:42
0

There's two main options:

  • Allocate each row separately
  • Allocate a single bloc containing all rows

If you want to sometimes extend individual rows then you have to use the first option. The second option forces you to have all rows the same length.

The only problem with the second option is that you cannot then use double-dereference syntax, since there is only a single dereference happening. You'd have to access in a different way, for example:

// global
int *multiArray;  
size_t multiArray_num_columns;
#define MARRAY(row, col) my_multiarray[(row) * multiArray_num_columns + (col)]

// in a function
multiArray_num_columns = columns;
multiArray = malloc(rows * columns * sizeof *multiArray);
MARRAY(3, 2) = 20;

There is a third option (which I don't like but some people do):

  • Allocate a single bloc, and put a table of pointers at the start of it

This gains you the double-dereference syntax but has no other benefits; its downside is that it's a lot more coding, and it may incur a runtime penalty (two dereferences can cost more than one dereference).


Update: here is the code for allocating each row separately (this gets asked a lot but I couldn't find a good duplicate!)

// global
int **multiArray;

// in function
multiArray = malloc( rows * sizeof *multiArray );
for (size_t row = 0; row < rows; ++row)
    multiArray[row] = malloc( columns * sizeof **multiArray );

You should check all of these results against NULL and exit if they failed.

Using the pattern ptr = malloc( NUM * sizeof *ptr ); guarantees to allocate the right amount of memory even if you later change the type of ptr.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    Thanks. I think I would rather allocate each row separately. Could you check the syntax in my reply to Jim to see if I am doing this correctly? – Jack Jun 25 '14 at 04:11
  • updated my post to cover this – M.M Jun 25 '14 at 04:31
  • 1
    Also, you may want to define MARRAY(r,c) as m[r+c*numrows]. It depends on how you are going to access the elements most of the time. The answer's representation gives good cache behavior when accessing the elements of a row in a sequence, while this definition gives good cache behavior when accessing the elements of a column in a sequence. For best performance you may want to keep around both the matrix *and* its transpose and have both macros available. – LaszloLadanyi Jun 25 '14 at 04:35