Welcome to C Programming Tutorial 7, Arrays in C Part 2!
C Tutorial 6 was an introduction to arrays in C.
This time, we’re going to go into a little bit more detail about arrays after a quick review.
Let’s do this!
Arrays in C Programming Part 2
Review of Array Basics
An array in C programming is a group of sequential locations in memory that hold one data type such as integers, floats, or chars. An array in C can only hold one data type, so don’t try to create an array that mixes integers with floats, for example.
There are a few different ways to declare an array in C.
We can initialize an array with values if we already know what the array should contain. For example, letters[] is an array of four characters:
char letters[4] = {A,B,C,D}; /*declares and initializes an array of 4 characters.*/
Often though, we don’t know ahead of time what the array is going to contain, so we can’t initialize it. For example, who_knows is an array of fifty integers, but we don’t know what their exact value is yet.
int who_knows[50]; /*declares an array of 50 integers, which will take on values later as the program runs */
Array indexing starts at 0, not 1. This is a VERY important thing to remember because forgetting it can cause hard-to-find errors. People — even those with C programming experience, make this mistake all the time. Figure 1 is from the first C tutorial on arrays, but here it is again just to drive the point home.
Figure 1: Like a character from a bad horror flick, it’s back! Here is a graphical representation of array indexing in C. The first element in the array Num[] is indexed at position 0.
Arrays and for loops are best friends that go way, way back. You’ll use arrays with for loops all the time.
In an effort to not regurgitate everything from the last C tutorial, I’ll stop the review here. If you want a more in depth review on the basics of arrays in C programming see C Programming Tutorial 6: Intro to Arrays in C.
Designated Initializers – Another Way to Initialize Arrays in C
With C99 came a new capability called designated initializers.
This feature allows the programmer to pick and choose which elements to initialize. For example, suppose that you just want to initialize the last element in an array. Using traditional C initialization syntax, you also have to initialize every element preceding the last one:
int repetitive_and_boring[7] = {0,0,0,0,0,0,339};
With this method, you can use an index in brackets in the initialization list to specify a particular element of the array:
int better_way[7] = {[6] = 339}; /* initializes last element of better_way[] to 339 */
The rest of the elements in our example above are simply set to 0.
And here’s another cool thing about designated initializers – you can initialize more than one element if you wish, as in the example below.
int pretty_slick[10] = {[0]=1, [4]=2, [8]=3}; /* initializes elements 0, 4, and 8 to 1, 2, and 3 */
We can also write something like the following code fragment:
int days[12] = {31,28,[4]=31,30,31,[1]=28};
for clarity, the complete C program prints the number of days in each month (well, some of them) and may look something like this:
#include <stdio.h> int main(void) { int days[12] = {31,28,[4]=31,30,31,[1]=29}; for (int i = 0; i < 12; i++) printf("%2d %d\n", i + 1, days[i]); return 0; }
The output of the above code looks something like this:
1 31 2 29 3 0 4 0 5 31 6 30 7 31 8 0 9 0 10 0 11 0 12 0
There are a few interesting things to note about the output.
First, if the code follows a designated initializer with more values, like the sequence [4] = 31, 30, 31, these values are used to initialize the subsequent elements. In other words, after initializing days[4] to 31, the code initializes days[5] and days[6] to 30 and 31, respectively.
Second, if the code initializes a certain element to a value more than once, the last initialization is the one that wins. For example, the start of the initialization list initializes days[1] to 28, but the last initialization [1] = 29 overrides it later, so the output is 29, not 28.
Finally, the rest of the elements are automatically set to 0.
Before we move on, I have a word of warning for all Arduino and C++ enthusiasts.
Neither C++ nor the Arduino IDE support this as of the time of this writing.
However, C PIC programmers should be safe.
Become the Maker you were born to be. Try Arduino Academy for FREE!
Multidimensional Arrays in C
Pretend for a moment that you want to make a home-brew weather station. You’re an ambitious person and in this for the long haul, so you decide to track monthly rainfall over a period of five years.
First, you think about using an array with 60 elements, but perhaps it’s more elegant (and smart) if you keep each year’s data separate. Another alternative is to use five arrays, each with 12 elements, but that is clumsy and could get really nutso if you decide to track 20 years’ worth of rainfall (remember, you’re in this for the long haul).
The smarter, slicker approach is to use an array of arrays. The master array would have five elements, one for each year. Each of those elements, in turn, would be a 12-element array — one for each month. Here is how to declare such an array:
float rain[5][12]; /* array of 5 arrays of 12 floats */
So how do we interpret this?
One way to do so is to first look at the inner portion (the [5] part). It tells us that rain[] is an array with five elements. But what the heck are those elements?
Now have a peek at the remaining part of the declaration (the [12] part). This tells us that each element is of type float[12], that is, each of the five elements of rain[] is, in itself, an array of 12 floats.
Toward that end, rain[0], being the first element of rain[], is an array of 12 values. So are rain[1], rain[2], etc. So, if rain[0] is an array, its first element is rain[0][0], its second element is rain[0][1] and so on. In short, rain[] is a five-element array of 12-element arrays of floats, rain[0] is an array of 12 floats, and rain[0][0] is a float.
To access, say, the value in row 3, column 4, use rain[3][4] (Remember, array indexing starts at 0, so row 3 is the fourth row, with row 0 being the first row).
If this is confusing (which is was to me when I first learned about multidimensional arrays) take a look at figure 2.
Figure 2: You can visualize this array as a two-dimensional array consisting of five rows, each of 12 columns. By changing the second subscript, you move along a row, month by month. By changing the first subscript, you move vertically along a column, year by year.
Remember, internally, this array is stored sequentially in memory, beginning with the first 12-element array, followed by the second 12-element array, and so on.
Everything we know about two-dimensional arrays applies to three-dimensional arrays and above, though I don’t recommend going more than three dimensions as it becomes unwieldy after that.
You can declare a three-dimensional array this way:
int three_dee[10][15][20];
To aid in visualization, think of a one-dimensional array as a row of data, a two-dimensional array as a table of data, and a three-dimensional array as a stack of data tables. For example, you can visualize the three-dee[] array as 10 two-dimensional arrays (each 15×20) stacked atop each other.
The other way to think of three-dee[] is as an array of arrays of arrays. So, it is a 10-element array, each element of which is a 15-element array. Each 15-element array then has elements that are 20-element arrays. Or, you can simply think of arrays in terms of the number of indices needed.
How to Initialize a Multidimensional Array
Initializing a two-dimensional array builds on the technique for initializing a one-dimensional array.
We’ll stick with two dimensions for the purposes of demonstration and clarity. Going back to our rain tracking example, suppose we already have five years’ worth of rainfall data we want to load into the program. In this case, we need to initialize our two-dimensional array rain[] with the data we have. To do so, we need to do something like this:
const float rain[12][5] = { {4.3, 5.3, 6.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6}, /*rainfall data year 1*/ {6.5, 8.5, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3}, /*rainfall data year 2*/ {9.1, 7.5, 6.7, 4.3, 3.1, 0.8, 0.2, 1.2, 1.1, 2.5, 6.1, 8.4}, /*rainfall data year 3*/ {5.2, 9.9, 6.4, 3.3, 1.2, 2.8, 0.4, 0.0, 0.6, 1.6, 5.3 ,6.2}, /*you get it now*/ {1.6, 5.7, 6.8, 3.4, 3.5, 1.2, 0.9, 0.4, 1.6, 1.6, 3.6, 7.2} };
A few notes on initializing multidimensional arrays are in order.
First, since the array holds data that should not be modified, we’re using the const modifier when declaring the array. After all, these values represent rain fall from the past and we’re not going to travel back in time and change the weather.
Second, the initialization uses five lists of numbers, each of which are enclosed by braces. All five lists are enclosed by one outer set of braces. You could omit the interior braces and just retain the two outermost braces. As long as you have the right number of entries, the effect is the same. However, this tends to be confusing, especially if you come back later to modify the program, so I don’t recommend doing this.
The data in the first interior set of braces is assigned to the first row of the array, the data in the second interior set goes to the second row, and so on.
Finally, the rules about mismatches between data and array sizes apply to each row (see C Programming Tutorial 6 for a review on this). That is, if the first inner set of braces encloses 10 numbers, only the first 10 elements of the first row are affected. The last two elements in that row are then initialized by default to zero. If there are too many numbers, it is an error; the numbers do not move to the next row.
An Array of Information
This wraps up our treatment of arrays in C programming for now.
You’ll see and use arrays a lot if you do any C programming, program microcontrollers, or are an Arduino enthusiast. Don’t be afraid of them and don’t forget to pair them with your for loops! The two are a perfect match for each other.
Drop me a comment and let me know what you thought of this tutorial. Or, tell me about your latest C programming or microcontroller-driven project. I love to hear about that stuff.
Until next time, keep making!
Become the Maker you were born to be. Try Arduino Academy for FREE!
Electronics Tips & Tutorials Sent Directly to Your Inbox
Submit your email & you'll get:
- Exclusive content that I don't put on the blog
- The checklist 10 mistakes all electronics enthusiasts make (& how to avoid them)
- And more!
kiet giang melbourne says
Have you ever thought about creating an ebook or guest authoring on other sites?
I have a blog based on the same subjects you discuss and
would love to have you share some stories/information.
I know my visitors would value your work. If you are even remotely interested, feel free
to shoot me an e-mail.
Brian says
Thanks, I’m flattered! Yes, thought about it and would love to do a guest post. I’ll email you.
jhwqeas says
Hey very interesting blog!
Lindsey says
I couldn’t refrain from commenting. Well written!
Brian says
Thanks!