Note: This chapter is a bit harder than the previous ones. If you feel a little discouraged, stick with it. The best stuff is yet to come!
In lesson 4.7 -- Structs, you learned that you can use a struct to aggregate many different data types into one identifier. This is great for the case where we want to model a single object that has many different properties. However, this is not so great for the case where we want to track many related instances of something.
Fortunately, structs are not the only aggregate data type in C++. An array is an aggregate data type that lets us access many variables of the same type through a single identifier.
Consider the case where you want to record the test scores for 30 students in a class. Without arrays, you would have to allocate 30 almost-identical variables!
1 2 3 4 5 6 |
// allocate 30 integer variables (each with a different name) int testScoreStudent1{}; int testScoreStudent2{}; int testScoreStudent3{}; // ... int testScoreStudent30{}; |
Arrays give us a much easier way to do this. The following array definition is essentially equivalent:
1 |
int testScore[30]{}; // allocate 30 integer variables in a fixed array |
In an array variable declaration, we use square brackets ([]) to tell the compiler both that this is an array variable (instead of a normal variable), as well as how many variables to allocate (called the array length).
In the above example, we declare a fixed array named testScore, with a length of 30. A fixed array (also called a fixed length array or fixed size array) is an array where the length is known at compile time. When testScore is instantiated, the compiler will allocate 30 integers.
Array elements and subscripting
Each of the variables in an array is called an element. Elements do not have their own unique names. Instead, to access individual elements of an array, we use the array name, along with the subscript operator ([]), and a parameter called a subscript (or index) that tells the compiler which element we want. This process is called subscripting or indexing the array.
In the example above, the first element in our array is testScore[0]. The second is testScore[1]. The tenth is testScore[9]. The last element in our testScore array is testScore[29]. This is great because we no longer need to keep track of a bunch of different (but related) names -- we can just vary the subscript to access different elements.
Important: Unlike everyday life, where we typically count starting from 1, in C++, arrays always count starting from 0!
For an array of length N, the array elements are numbered 0 through N-1. This is called the array’s range.
An example array program
Here’s a sample program that puts together the definition and indexing of an array:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> int main() { int prime[5]{}; // hold the first 5 prime numbers prime[0] = 2; // The first element has index 0 prime[1] = 3; prime[2] = 5; prime[3] = 7; prime[4] = 11; // The last element has index 4 (array length-1) std::cout << "The lowest prime number is: " << prime[0] << '\n'; std::cout << "The sum of the first 5 primes is: " << prime[0] + prime[1] + prime[2] + prime[3] + prime[4] << '\n'; return 0; } |
This prints:
The lowest prime number is: 2 The sum of the first 5 primes is: 28
Array data types
Arrays can be made from any data type. Consider the following example, where we declare an array of doubles:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int main() { double batteryLifeInHours[3]{}; // allocate 3 doubles batteryLifeInHours[0] = 2.0; batteryLifeInHours[1] = 3.0; batteryLifeInHours[2] = 4.3; std::cout << "The average battery life is " << (batteryLifeInHours[0] + batteryLifeInHours[1] + batteryLifeInHours[2]) / 3.0 << "hour(s)\n"; return 0; } |
This program produces the result:
The average is 3.1
Arrays can also be made from structs. Consider the following example:
1 2 3 4 5 6 |
struct Rectangle { int length{}; int width{}; }; Rectangle rects[5]{}; // declare an array of 5 Rectangle |
To access a struct member of an array element, first pick which array element you want, and then use the member selection operator to select the struct member you want:
1 |
rects[0].length = 24; |
Arrays can even be made from arrays, a topic that we’ll cover in a future lesson.
Array subscripts
In C++, array subscripts must always be an integral type. This includes char, short, int, long, long long, etc… and strangely enough, bool (where false gives an index of 0 and true gives an index of 1). An array subscript can be a literal value, a variable (constant or non-constant), or an expression that evaluates to an integral type.
Here are some examples:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
int array[5]{}; // declare an array of length 5 // using a literal (constant) index: array[1] = 7; // ok // using an enum (constant) index enum Animals { animal_cat = 2 }; array[animal_cat] = 4; // ok // using a variable (non-constant) index: short index = 3; array[index] = 7; // ok // using an expression that evaluates to an integer index: array[1+2] = 7; // ok |
Fixed array declarations
When declaring a fixed array, the length of the array (between the square brackets) must be a compile-time constant. This is because the length of a fixed array must be known at compile time. Here are some different ways to declare fixed arrays:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// using a literal constant int numberOfLessonsPerDay[7]{}; // Ok // using a constexpr symbolic constant constexpr int daysPerWeek{ 7 }; int numberOfLessonsPerDay[daysPerWeek]{}; // Ok // using an enumerator enum Weekday { monday, tuesday, wednesday, thursday, friday, saturday, sunday, maxWeekday }; int numberOfLessonsPerDay[maxWeekday]{}; // Ok // using a macro #define DAYS_PER_WEEK 7 int numberOfLessonsPerDay[DAYS_PER_WEEK]{}; // Works, but don't do this (use a constexpr symbolic constant instead) |
Note that non-const variables or runtime constants cannot be used:
1 2 3 4 5 6 7 8 9 |
// using a non-const variable int daysPerWeek{}; std::cin >> daysPerWeek; int numberOfLessonsPerDay[daysPerWeek]{}; // Not ok -- daysPerWeek is not a compile-time constant! // using a runtime const variable int temp{ 5 }; const int daysPerWeek{ temp }; // the value of daysPerWeek isn't known until runtime, so this is a runtime constant, not a compile-time constant! int numberOfLessonsPerDay[daysPerWeek]{}; // Not ok |
Note that in the last two cases, an error should result because the length is not a compile-time constant. Some compilers may allow these kinds of arrays (for C99 compatibility reasons), but they are invalid in C++, and should not be used in C++ programs. If your compiler allows these arrays, you probably forgot to disable compiler extensions (Lesson 0.10 -- Configuring your compiler: Compiler extensions).
A note on dynamic arrays
Because fixed arrays have memory allocated at compile time, that introduces two limitations:
- Fixed arrays cannot have a length based on either user input or some other value calculated at runtime.
- Fixed arrays have a fixed length that can not be changed.
In many cases, these limitations are problematic. Fortunately, C++ supports a second kind of array known as a dynamic array. The length of a dynamic array can be set at runtime, and their length can be changed. However, dynamic arrays are a little more complicated to instantiate, so we’ll cover them later in the chapter.
Summary
Fixed arrays provide an easy way to allocate and use multiple variables of the same type so long as the length of the array is known at compile time.
We’ll look at more topics around fixed arrays in the next lesson.
![]() |
![]() |
![]() |
The above code works fine even after compiler settings , why you have written not ok in comments?
It works absolutely fine even after doing compiler setting , please explain why you have written not ok in the comments.
Your compiler is still misconfigured or broken. This isn't valid C++.
Hi Alex,
on the 2nd paragraph
"In lesson 4.7 -- Structs, you learned that you can use a struct to aggregate many different data types into one identifier. This is great for the case where we want to model a single object that has many different properties. However, this is not so great for the case where we want to track many related instances of something."
the hyperlinked text "4.7" is wrong, it should be 8.5.
The hyperlink directs to the proper page tho! :)
thank you for your free content by the way, you are awesome!
im confused with the following.
// using a constexpr symbolic constant
constexpr int daysPerWeek{ 7 };
int numberOfLessonsPerDay[daysPerWeek]{}; // Ok
// using a runtime const variable
int temp{ 5 };
const int daysPerWeek{ temp }; // the value of daysPerWeek isn't known until runtime, so this is a runtime constant, not a compile-time constant!
int numberOfLessonsPerDay[daysPerWeek]{}; // Not ok
how come the value of daysPerWeek is known at runtime but then the second daysPerWeek is not. can't the compiler see that temp = 5 ?
This one was makes confused me too, what I see that is compiler time, not the run time
im thinking maybe it has to be immediately obvious to the compiler or at least declared once before.
declared twice wont work.
int numberOfLessonsPerDay[DAYS_PER_WEEK]{}; // Works, but don't do this
hello, why you said "do not do this"
You should use a constexpr symbolic constant instead, as shown earlier in the same example.
Hey :)
Check out the lesson on macros, it tells you in detail why it is not good practice to use them like this. Happy coding!
Hi again :)
So I have a question.
This is my current container I'm working on, a 2D array:
This particular line is confusing me a lot:
Which apparently is the same as:
How does this work? I have never seen [ ] used after the parameters. Is this how it works under the hoods?
What's happening there? My guess:
- matrix[1] calls the overloaded operator[], which returns a pointer. Then since it's a pointer we can chain another [] (aka [2]), which calls the overloaded operator[] again and returns. It's very confusing, so I would appreciate if someone could kindly explain this.
Also, why doesn't it work if I return a reference, and not a pointer? Thank you!
Two small suggestions:
1. std::cout << "The average battery life is " << (batteryLifeInHours[0] + batteryLifeInHours[1] + batteryLifeInHours[2]) / 3.0 << " hour(s)\n"; instead of std::cout << "The average battery life is " << (batteryLifeInHours[0] + batteryLifeInHours[1] + batteryLifeInHours[2]) / 3.0 << "hour(s)\n";
2. This program produces the result:
The average battery life is 3.1 hour(s) instead of The average is 3.1
hjbjmyhizzvryqyezjfijjcyaxfmas
rcxteowhfxanbrqebwwzqyzpolitfc
Hi Nasc.
Might I suggest that we not name an array variable "array[]"? Yes, it's valid; I suppose "array" is not a key word but it forces us to peer at the trees and miss the forest. Like I would not name a database "database".
I renamed "array" where I could think of an example that makes sense. Feel free to point out other occurrences and share your ideas.
Hi there,
(Second edit: I think my question is answered in the next part of the Arrays discussion, and the answer is that your syntax in these instances is fine, but the Elements of these arrays would be unitialised. I'll leave my comment here so you might confirm for me that that's the correct, in any case! Ta!)
In your body of examples for 'Fixed Array Declarations', above, should:
not read
(with the curly braces) in order to qualify as a declaration?
(Edit:)
And again just below, actually:
with curly braces for
Thanks!
Lesson updated. Thanks for pointing out the inconsistencies!
Always reassuring to know that I'm absorbing enough in my learning to catch the occasional thing-that-doesn't-look-quite-right! I soldier on! Cheers. (p.s. This whole course is excellent, and I'm really enjoying it. Thanks for all your hard work!)
'Important: Unlike everyday life, where we typically count starting from 1, in C++, arrays always count starting from 0!'
I believe it would be better if this clarifies that the array index starting from 0 is not just in C++, but any programming language.
There are programming/scripting languages that start array indexes at 1
you can still say "in most programming languages"
The coderwall explains in Some detail the theory of how best to get the size of an array in C++ https://coderwall.com/p/nb9ngq/better-getting-array-size-in-c
Is it possible to customize and overload subscript operator in the way we are doing assignment and new and delete operator while creating a class?
I don't understand. Can you show an example of what you're trying to do?
"but they are invalid according to the C++ standard, and should be not be used in C++ programs."
Noticed extra "be"
Good eye, my mind seems to skip the extra `be`.
I was wondering why the code above won't compile because of 'temp' as the value of temp is known during compile-time.
and
what does this error mean?
"failure was caused by a read of a variable outside its lifetime"
You need to specify that temp is a constexpr as it's known at compile time and will not be modified.
That will work.