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 8.4 -- 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 tutorial says:
Important: Unlike everyday life, where we typically count starting from 1, in C++, arrays always count starting from 0!
But 0!=1. This is misleading.
In case if anyone wants to know how to read, "array[0] = 2.0;" you can read it as "array sub zero is assigned the value 2.0." Cheers!
Dear NASCAR driver,
Please let me ask you: in first sentence (This chapter is a bit harder than the previous ones), is by "previous" meant chapter C.5? Regards.
"previous ones", "ones" is plural, it refers to all chapters that were before this one.
Dear NASCAR driver,
Please let me express my sincere thanks for you answered this reckless question. Regards.
Help! I just finished chapter 5, did chapter O by accident, (didn't notice the "disjointed" lessons), assumed chapter 6 would follow chapter 5, yet the 2nd paragraph in Ch5 mentions "Ch4.7 -- Structs, you learned that you can use a struct to aggregate many different data types into one identifier." I'm like, I don't recall learning that, so I click it, and it takes me to the "original" chapter 4, which is now chapter S.
So should chapter S actually follow after chapter 4 or do you plan to move it some where else? And should I definitely do Chapter S before chapter 6?
Sorry for the confusion, but this is confusing :)
Current intended ordering is: 5, O, S, C, 6.
O, S, and C are temporary numbers due to inserted chapters.
The front page will always contain the intended ordering in sequence.
Ok, good to know.
I can see why chapter o is optional. After reading it I felt like, ok, now what. I mean it was thorough in explaining how bitwise operators work, but I kept waiting for the why and when do we need to use it? In my limited scope, all I could imagine is, if I start moving bits around, I'm just asking for my program to crash :)
this shouldnt work right? because its assigning the size of the array in runtime. correct?
Correct. If it works for you, make sure you followed lesson 0.10 and 0.11.
why we cant use uniform initialization in that line? is it different from initializing?
You can only initialize variables while they get created. `arr[1]` already exists and it's value is 0 (Because of the empty curly braces in line 5). If you want to initialize the array's members, you need to do so at the array's definition.
ah i see. Thank you!
fixed arrays are stored on heap or stack?
It's not standardized. Generally, they're stored on the stack.
is it possible to get user inputs for the elements of an array?
This?
yep. thanks.
Hi alex,
I think you forgot to use
in the array data type section.
Fixed! Thanks.
"For an array of length N, the array elements are numbered 0 through N-1! This is called the array’s range. "
After reading this, I got confused for a second because "N-1!" looks "N minus One Factorial" to me. Then I realized, It was just an exclamation mark!
I can see how this might be confusing, so I've made the sentence less excited. Thanks for pointing this out.
But N-1!=N-1
Is this an example of magic numbers?
#include <iostream>
#include <string>
std::string sch(std::string s, int x, int y)
{
std::string news = s;
news[x] = news[y];
news[y] = s[x]; //avoids temp variable
//news[y];
std::cout<<"x y s[]: "<<news[x]<<news[y]<<s[x]<<std::endl;
std::cout<<"news s: "<<news<<std::endl;
return news;
}
void permute(std::string s, int index)
{
if(index == s.length())// - 1
{
std::cout<<s<<" "<<s.length()<<std::endl;
}
for(int i = index; i < s.length(); i++)//2, 3 overmax
{std::cout<<"index: "<<index<<" is this a magic number?"<<" i:"<<i<<std::endl;
permute(sch(s, index, i),index +1);//index 3
}
}
int main()
{
std::cout<<"enter string: "<<std::endl;
std::string s;
std::cin>>s;
permute(s, 0);
return 0;
}
where it says magic numbers, index goes form 3 to 1, and then to zero. Why does index go from 3 to 1?
No. A magic number is a literal number with no direct way of identifying what it's meaning is.
Hi I am in 11th grade this year could you please explain to me how to initialize 2d character string array
Multidimensional arrays are covered in lesson 6.5
Where do you talk about compiler time?
In which Chapter I mean
lesson 2.9
Thanks for the quick reply
Hi,
The line 10 in your lesson is incorrect
Hi TanLan!
Closing code tags use a forward slash [ /code ] (without space)
You need @std::cout
Hi,
How can I can determine these array's length? Any neat trick?
Thanks, Have a great day.
Hi Nguyen!
This is covered in the next lesson.
Hi Alex and Nascardriver!
should i use this:
instead of:
??
because "constexpr" is used when the constant is compile time.
Thanks!
Hi Moein!
Yes, constexpr is a const variable, but it allows @arrayLength to be used in other contexpr expressions, which can run at compile-time.
Also, uniform initialization is better.
If we use g++ compiler, following code works.
int length;
std::cin >> length;
int array[length];
Hi Ramesh!
That's a compiler extension, don't use it. Compile with -pedantic-errors.
Where can I find all header files, all built-in functions, all built-in constants, all data types, etc?
Hi Samira!
It depends on your system. On linux they should be located in /usr/include, I don't know about other systems. Your IDE might be able to show they to you when you right click on the #include and select "Show Definition" or similar.
Alex.
I array data types example, cout must be std::cout.
By the way, can use enum type for array?
Hi Samira!
> can use enum type for array?
You can.
How can I do that?
Array Subscripts example line 18
not, ok, index out of bounds
Oops. Fixed, thanks!
I defined array with a fixed length 5, but why I can assign to array with the index greater than 4?
Hi Samira!
I assume your code looks similar to this
Line 5 is accessing and attempting to override an undefined value. The memory address at arr[6] is well defined, however the memory itself could be used by another variable or not even accessible to your program. So you're either
1. Accessing memory which isn't owned by your array, you can use it until your computer uses it for something else and you'll end up with weird values.
2. Overriding another variable, this is can be abused by attackers to run a stack overflow exploit.
3. Accessing inaccessible memory and your program crashes.
1 and 2 are a pain to debug, 3 is easily found, but your program might run for a hundred times before an error occurs, good luck debugging that.
Some compilers add run-time protection when building in Debug mode so you can't exceed array boundaries, for example a program compiled with gcc will terminate itself, print "*** stack smashing detected ***: <unknown> terminated" and attempt to create a memory dump.
Conside the following:
#include <iostream>
int main()
{
int length_a;
std::cin >> length_a;
int array_a[length_a]; // Not ok -- length is not a compile-time constant!
// using a runtime const variable
int temp = 5;
const int length_b = temp; // the value of length isn't known until runtime, so this is a runtime constant, not a compile-time constant!
int array_b[length_b]; // Not ok
return 0;
}
The lesson says that you can't use run-time constants to allocate memory for fixed arrays but this code compiles just fine on the GDB comiler. Can anyone explain why?
Hi Neo!
GDB isn't a compiler, it's a debugger. I assume you're using g++.
What you did is _not_ standard C++, it's a compiler extension and should not be used.
The proper way of creating arrays of dynamic size is covered in lesson 6.9a (You'll need to read the previous lessons before being able to understand it).
Adding -pedantic to your compiler options will cause your compiler to show warnings when you're using non-standard features.
hi alex, can you please make your comment area in your site folded, because sometimes i read your article it make me panic, but you can imagine my surprised, that on some article page, it's only quarter of scroll..., plzzzz,, and ..... "your photo is awesome"
In the section "Fixed array declarations" it would be helpful to talk about this variation:
The original version in the lesson doesn't compile under Visual Studio as would be expected, but the above seems to work fine. Does const make temp a compile-time constant? What does the C++ standard have to say about this?
In the above, temp would be a compile-time const, but length would be a runtime const.It's fine to initialize a const variable from a compile-time const, or even a non-const. So your snippet will compile file. What we're talking about in the lesson is that the length of a C-style array must be a compile time const. Thus, temp could be used as the array length, but length could not.Edit: My original response was incorrect, see my updated response further down this thread.
What an interesting example. Do all compilers make length a runtime const? I would think that a smart compiler could figure out that a const assigned to the value of another const would have to be constant.
I can't tell you about run-time- and compile-time constants, but I can show you my observations.
Compiles fine (without compiler extensions).
Both @temp and @length are treated exactly the same.
Both values are known at compile-time, stored in a read-only section and substituted when printing their value in @main.
Tested with g++ 8.0.1. I can't imagine any compiler would behave differently.
I like what you did here. Under Visual Studio, no surprises but I don't understand what the reinterpret_cast is all about. Could you explain?
To print a pointer with @printf the %p formatting is used. %p only works with void* so we need a cast.
static_cast converts the actual data of the variable we're casting. Say int to double. A double's representation in bits is different from an int's. static_cast changes those bits so if we converted 43 to a double we'd get 43.0.
reinterpret_cast does not do any conversion on the data. All it does is change the type, the bits stay the same. Since I don't want to convert @temp or @length (I only want their addresses as void*) I used reinterpret_cast.
More about casts: https://stackoverflow.com/a/332086/9364954
Nice explanation... very helpful. Thank you.
So I just realized I made a mistake in my original response. Let me provide a code snippet clarifying the correct behavior:
In example 1, length1 is initialized from a compile-time const, and thus is considered to be a compile-time const itself.
In example 2, length2 is initialized from a non-const, and thus is a considered a run-time const.
In example 3, length3 is initialized from a runtime-const, and thus is considered a run-time const.
Hopefully that helps clarify things.
Nice. The only thing that I'm uncertain about is c3.
Am I right in suggesting that the reason c3 might be considered a run-time const is because foo() could be called using different const parameters? To treat the array as having fixed length within foo() would mean it would essentially have to create different foo() routines for the different calls. Technically possible in some cases but I can see how the compiler writer might want to abandon ship at this point.
foo() could be called with anything -- a non-const, a runtime const, or a compile-time const. The point is that the function call isn't resolved until runtime, which means the const parameter has to be treated as a runtime const.
Yes, you'd have to create different foo variables for different array sizes, which is a pain. Fortunately, templates and template expression parameters make this significantly easier, so we can write one template function and instantiate as many variants as we use. This is covered in chapter 13.
Fine example with foo, consider including it in the "Const, constexpr, and symbolic constants" lesson; wasn't clear to me why const int length = c1; was a runtime constant. So the idea is, unless c1 is `const`, its value may change throughout execution, and the compiler won't take on that task for optimization, as it'd require actually executing the (potentially heavy-duty) program.
In the Array Subscripts section, you might consider replacing
"-- and strangely enough, bool"
with
"and bool (where false gives an index of 0 and true an index of 1)"
Good suggestion. Integrated into the lesson. Thanks!
Hi Alex!
I have two questions.
a) why isn't good to use define macros variables ?
b)
I think it's not good because the variable x would be resolved in the run time ?? am I right ?
Thanks!
1) I cover why macros aren't good to use in previous chapters -- look up macros in the index and have a read.
2) x needs to be a compile-time constant, and in this case it isn't.
what is a run time constant variable? Why is it that in the last case, the array declaration won't work? Could you please explain this in detail.
This is a bit hard to explain. When you assign a literal value to a const variable (e.g. const int x = 5), the compiler is smart enough to know that when it sees "x", it can substitute the value 5. Variable x is a constant, so it will never change. So these kinds of constants have values that are known at compile time.
On the other hand, in the last example (const int length = temp), we see a const variable initialized with the value of a normal variable. The value of this normal variable isn't known until runtime -- therefore, the compiler doesn't know what value the constant will have until runtime either. Therefore, this constant is a runtime constant, not a compile-time constant.
Fixed arrays must have a compile time constant as a length.
i think compiler is able to know length at that time, it is not run time compile variable. variable from cin input is run time. what do you think?
I think that if you try to compile both of these cases yourself, you'll see in neither case is length considered a compile-time constant.
The last variable to be known by the program, or the tardiest to initialize, is effectively the gate-keeper for any use case that looks at 'creation-time' (i.e. data types that require compile-time constants, etc.)
Does this sound like a sane reiteration of the point? Just trying to understand.
Suppose I have an array of length 50. What is the easiest way to print the sum of all the elements?
Use a loop to iterate through the array, so you can access each element. Sum of the value of the elements in a separate variable. Print out the sum.
Thank you for awesome site, keep going great job
This works on CODE::BLOCKS 16.01 successfully.
even though I input 1 or 0 as the value of (n), it print arr[1] without any error or even any warning.
Certain compilers will sometimes let you do things that aren't officially part of the C++ specification. Apparently Code::Blocks will let you do variable length arrays. That doesn't mean you should use them.
Ok Man ! Thanks !
But How Is It Printing The 2nd of element of array even if i defined the length to be 1 or 0. That's Strange !
You asked it to. Build-in arrays don't do any bounds checking.
What Do You Mean Here By "Build-In arrays" ?
The fixed arrays we cover in this lesson.
ok. Thanks. So, If we declare a run-time variable and ask for its value, and, even if it's smaller(like in the above example), it won't show any error.
No, NOT ONLY IN RUN-TIME VARIABLES BUT ALSO COMPILE-TIME VARIABLES.
And, One Thing : sizeof(array) still displays the original size and also, the program stops working...
Why?
I don't understand the question.
C++ doesn't do bounds checking on fixed arrays. However, it still knows the sizeof the array. If you write something out of bounds of your array, the behavior is undefined.
Ok. Thanks Man ! Can You Tell Me What Is An Initization Function giving an Example?
But What's The Point Of Using These Functions ?
At First, I Thought It is something like this :-
int x = dosomething(x); // x will be INITIALIZED to the return value of the function
Plz Explain !
To do any initialization your application needs to run.
Will u tell more about it later in other chapters ? So I Will Wait ;)