Pointers and Arrays Part II We will continue with our discussion on the relationship between pointers and arrays, and in particular, discuss how arrays with dynamical length can be created at run-time One-dimensional arrays defined dynamically at run time Consider the case in which you do not know the number of elements that an array in your program will have In other words, the length of the array will be determined at run-time after the program starts execution, and therefore, you do not have the luxury of defining the length of the array at the time you write your program C language provides a powerful way to create arrays of any length at run-time In order to create an array of a given type with any number of elements, you first need to declare a pointer to a variable of that type Let s go over this with an example: say you want to create an integer array of N elements (N to be determined by some input during run time, not at compilation time) You first need to declare an integer pointer: int* m; Next, you need to allocate memory for N integer elements C language standard library provides a function called malloc() that allows one to allocate memory for a given number of bytes Here is the function signature of malloc(): void *malloc(size_t size); What this function signature is saying is that malloc() takes an argument of type size_t and returns a void pointer to the first element of the allocated space Note that the return type is void rather than int or float etc This generic interface allows one to allocate space for any type However, you need to tell C compiler exactly what type you are expecting (We will see an example soon) The size argument tells malloc() how much space is needed Let s say you want to allocate memory for N integers, N to be determined at run time; the size that malloc() needs is N times the size of one integer in memory The size of any type in C language can be found by using the sizeof() operator For instance, if you want to find the size of an integer, then you need to operate sizeof() on int as follows: sizeof(int) At this time we have all the pieces necessary to allocate memory for an array dynamically Following our example, we allocate N integers as follows: malloc(n * sizeof(int)) Note that these N elements occupy consecutive memory locations Now, we need to relate this memory space to the integer pointer variable we declared earlier We want to explicitly state that we meant to create an integer array To do that
we need to cast the void pointer returned by malloc() function to integer pointer as follows: (int*) malloc(n * sizeof(int)) And finally, assign this to the integer variable m as follows: m = (int*) malloc(n * sizeof(int)); See Figure 1 below that summarizes these operations Note that the integer pointer variable m holds the address to the first element allocated by malloc() operator int* m Memory allocated by malloc() Figure 1 Allocating an array at run time Now that we have created an integer array of size N, we can refer to its elements by using array indices For instance: x = (m[0] + m[2] )/ 2; This expression assumes that the size or array m is larger than 3, so that referring to element 2 is meaningful Two-dimensional arrays defined dynamically
One can define arrays of any number of dimensions with variable length by using pointers and malloc() Here we will discuss 2-D arrays as an extension to our discussion in the previous section 2D arrays are somewhat more complicated to define The first thing to keep on mind is that the first index of a 2D array is really a pointer to a row of elements See Figure 2 below for a 2D array of size N by M Say this array variable is named a Then, a[i] will refer to the pointer that holds the address of row i, and a[i][j] will refer to the element at row i and column j 0 1 N-1 0 1 M-1 0 1 M-1 Figure 2 A 2D array of size N X M Here are the steps to allocate a 2D integer array of size N by M: 1 Create an array of integer pointers (see Figure 2; this step corresponds to creating the column of elements on the left) 2 For each integer pointer element of the array created in step 1 create an array of integers and assign the first element of the created integer array to the integer pointer element (Again, see Figure 2; this step corresponds to creating a row of elements from 0 to M-1) Now, let s show these steps programmatically Creating an array of integer pointers is as follows: int** m; // step 1 Note the double * in front of m That means you are declaring a pointer to a pointer Next, we allocate an array of integer pointers:
m = (int**) malloc(n * sizeof(int*)); // step 2 Note that the size of elements we create is the size of an integer pointer, not an integer What malloc() will return is a pointer to a pointer array, so we cast it to (int**) So far we have an array of N integer pointers Now we need to create actual storage for integers We need a total of N*M elements, so int* k = (int*) malloc(n*m*sizeof(int)); // step 3 This will allocate the actual integer storage and assign the space to an integer pointer Elements will have consecutive locations For instance, the last element of the first row will be followed by the first element of the second row in memory Now, we need to assign row pointers to actual storage We do that as follows: 1: for (i= 0; i < n; i++) // step 4 2: { 3: m[i] = k; 4: k = k + M; 5: } Let s go over this loop: the for-loop goes over each row to be assigned; in line 3 we assign the next row s pointer to the consecutive set of elements in memory In line 4 we advance the integer pointer k to point to the next row of elements See Figure 3 Important note: a 2D array is really a 1D array in terms of storage in memory, as you can see in step 3 above to allocate N by M elements We interpret this 1D space as a 2D array by assigning pointers separated by M elements as you can see in Figure 3 Now that we have the 2D array created, we can write statements like: x = m[0][2] * m[3][4] / m[1][2];
0 1 0 M-1 M ((N-1)XM) -1 (N-1)XM (NXM) -1 Figure 3 The schematic representation of a 2D MXN integer array created dynamically Note that the blue cells are the actual integer elements and the salmon-colored cells are the pointers to each row of elements