Allocating Arrays of Dynamic Size

In the previous section you allocated a block of memory and used it. However, it was a very small block of memory—only the size needed to store an integer. You could have allocated the same amount of memory statically by simply defining a regular integer variable in the program. And, although the amount of memory was determined at runtime, it was still of a fixed size (the size required to store an integer).

Memory management gets a lot more interesting if you determine the amount of memory to request from the pool at runtime, and if the requested amount is larger. In this section you will allocate room for an array of integers. To make it clear that the size of the array is dynamic, this program will ask the user to choose the size at runtime (during the execution of the program).

Before you implement the example, let's review the relationship between arrays and pointers that we introduced in the previous chapter.

The forthcoming example requires an array whose size is not known when the program is written and therefore cannot be inserted between the brackets in the array definition:

int a[???]; // How many elements?

How can you solve this problem? Recall the discussion in the previous chapter where you learned that the combination of the array's name and the array subscription operator (the square brackets) can be replaced with pointer arithmetic using the array's base address. For example, both a[0] and *x (where x is a pointer containing a's address) refer to the array's first element. Using pointer arithmetic from there, a[1] is equivalent to *(x + 1), a[2] to *(x + 2), and so on.

What helps you here is that this also works in reverse. Given a base address of a chunk of memory stored in a pointer variable (which is exactly what malloc() returns), you can use the array subscription operator on the pointer variable's name and treat the chunk of memory exactly like an array. So, if you define x as a block of memory large enough to store 10 integers:

int *x = malloc(10 * sizeof(int));

then you're allowed to treat x like an array:

x[1] = 45;
x[2] = 8;

The following example uses this concept.

To allocate a dynamic array

1.
Create a new file or project in your text editor or IDE.

2.
Type the standard beginning lines of code (Script 10.3):

/* array.c - Script 10.3 */
#include <stdio.h>
#include <stdlib.h>

Script 10.3. A dynamically allocated block of memory can be used like an array.


3.
Begin the main function:

int main (void) {

4.
Define an integer pointer variable and two integers:

int *x = NULL;
int i, count;

The x pointer will be used for working with the dynamic memory. The i variable will be used in a loop (as you've seen many times by now), and count will store the number of items in the array, which will be determined by the user.

5.
Prompt the user for the size of the array, storing the user's reply in the count variable:

printf("Number of items? ");
scanf("%d", &count);

The first line creates a prompt (Figure 10.4). The submitted value is then stored in the count variable.

Figure 10.4. The number of elements to be stored in an array will be determined by the input the user enters at this prompt.


You can also, if you want, add some checks to this process so that a valid integer value is entered. This concept was covered back in Chapter 5, “Standard Input and Output.”

6.
Request a block of memory large enough to hold this number of integers:

x = malloc(count * sizeof(int));

To determine how much memory is required, multiply the amount of memory needed for one integer by the number of integers the user wishes to store. This gives the total size of the block to allocate.

7.
In a loop, store a random number in every element of the array:

for (i = 0; i < count; i++) {
    x[i] = rand();
}

This loop runs from 0 to count iterations to access every memory block. Within the loop itself, the rand() function is used to assign a random value to that array's element.

Notice how this code uses the array subscription operator on the pointer variable holding the memory block's base address (x[i]). In essence, you are treating the block of memory like an array, even though you never explicitly defined an array.

8.
In another loop, print the array's elements:

Example.
for (i = 0; i < count; i++) {
   printf("The value of array element
 %d is %d.
", i, x[i]);
}

9.
Return the block to the pool using the free() function:

free(x);
x = NULL;

10.
Add two getchar() calls to pause execution on Windows:

getchar();
getchar();

Because this example takes user input, the extra call to getchar() may be required.

You can also add one of the techniques for discarding extraneous input, if you desire.

11.
Complete the main function:

    return 0;
}

12.
Save the file as array.c, compile, and debug as necessary.

13.
Run the application (Figure 10.5).

Figure 10.5. An array of varying length—determined by the user-submitted number—is populated with random values, then printed.


Enter any number when asked for it by the program.

14.
Run the application again, using a different numeric value (Figure 10.6).

Figure 10.6. Since there is no set array size in this example, the only limitation is the amount of available memory.


You can repeat this as many times as you want with different values. A different amount of memory is requested and returned each time.

✓ Tips

  • You could have used pointer arithmetic on the memory block's base address instead of the array subscription notation. Both pointer arithmetic and array subscription will work.

  • Another example involving the rand() function takes place in Chapter 12, “File Input and Output.” At that time you'll also see how to generate numbers that are more random.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset