You can't declare global arrays in C without giving them a specific numerical size. This is because global variables are static and the compiler can't allocate a variable amount of memory for a global array.
In C you've got to remember that an array is actually just a pointer. When you're asking for int *array = malloc(n * sizeof(int))
what you're telling the compiler is that you need n
lots of 4 byte blocks of int type reserved side by side in memory, where the value of array
is actually a pointer to the first 4 byte block.
When you are accessing elements of an array you are actually doing pointer arithmetic and dereferencing the pointer, but this is hidden in the array[i]
syntax. So, when array has int type, array[2]
translates as go to the location given by the array pointer (i.e. the head) now move 2 * 4 bytes along in memory and dereference the pointer to access the integer stored there.
So when you're creating a 2-d array as you've discussed, there really isn't a better way of doing it. Make sure you have a firm grip on what it actually is you're getting from the compiler. Pointers are (on 64-bit machines anyway) 8 bytes and ints are 4 bytes. So when you call int **M = malloc(sizeof(int*) * m
the compiler allocates you m blocks of width 8 bytes each, all of which have type int*.
From other programming languages it seems very over the top having to declare a pointer reference to a block of pointers, but getting passed the higher level idea of an array and considering them as a collection of pointers will really help you in the long run. When you need to pass these data types between functions you need to be able to have a firm idea of what you are actually manipulating; a pointer, a value, a pointer to a pointer? It will help you a lot in debugging code these ideas, as it is very easy to try and perform computations on pointers rather than values.
3 Useful Tips:
calloc(n, sizeof(int))
might be a better fit than calling malloc because calloc automatically initialises your entries to zero whereas malloc doesn't.
- when calling calloc/malloc, you want to check that your dynamic memory allocation has been successful; if it isn't successful, then malloc will return NULL.
- A good rule of thumb is that every time you call malloc you want to call free once you're done with the memory. This can help to prevent memory leaks.