Lab 00 Feedback¶
Click <shift> <enter> in each code cell to run the code. Be sure to start with the #include
directives to load the required libraries.
Preprocessor Directives¶
An #include
directive is not a C++ statement; it is a preprocessor directive.
It is an instruction to the compiler to include a file or library before compiling.
Since it is not a C++ statement, it should not end with a semicolon.
#include <iostream> // does not end with a semicolon
#include <string>
#include <limits>
Array Indexing¶
Indexing starts at position 0, not 1. So, the first element of a 5 element array is at index 0, and the fifth (or last) element is at index 4.
int arr[5] = {1, 2, 3, 4, 5};
std::cout << "Printing 5 array elements (indexes 0 to 4):" << std::endl;
for (int i = 0; i < 5; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl << std::endl;
Printing 5 array elements (indexes 0 to 4): 1 2 3 4 5
The above loop iterates from 0 to 4 (5 iterations).
The middle part of the loop (i < 5)
is like a while loop condition.
We loop while i is less than 5, so when i++
makes i equal to 5, the loop is not entered again.
If we say i <= 5
, the loop will run past the end of the array.
// Index: 0 1 2 3 4 5
arr[5] = {1, 2, 3, 4, 5}; //__ <-- Invalid memory access.
Reading Input with std::cin
And std::getline
¶
When using std::cin
to read data from the console, the input is space delimited. This means that the input is read until a white space character like space or newline is encountered.
std::cout << "Understanding std::cin and std::getline" << std::endl;
std::string first_name;
std::string last_name;
std::cout << "Enter your first and last name: ";
std::cin >> first_name >> last_name;
std::cout << "Hello, " << first_name << " " << last_name << "." << std::endl;
Understanding std::cin and std::getline Enter your first and last name:
Hello, John Smith.
If we prompt for a name and age, and the user's name includes a space, the input will be split at the space.
std::string name;
int age = 0;
std::cout << "Enter your name and age: ";
std::cin >> name >> age;
std::cout << "Hello, " << name << ". You are " << age << " years old." << std::endl;
Enter your name and age:
Hello, John. You are 25 years old.
Since age is an integer, if the user enters a non-integer value, std::cin
will enter a fail state. We will have broken the input stream.
Try entering Mary Jane 25
, and see what happens.
Since some names do include white space, we can use std::getline()
to read an entire line of input, including white space.
std:: cout << "Enter your first name: ";
std::cin >> first_name;
std::cout << "Hello, " << first_name << "." << std::endl;
// With the std::cin.ignore line commented out, do we foresee any issues?
// std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Clear the input stream
std::cout << "Now enter your full name: ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << ".\nHave a good day." << std::endl << std::endl;
Enter your first name:
Hello, John. Now enter your full name: Hello, . Have a good day.
When using std::cin >>
before std::getline()
, what has happened to the input stream?
We seemed to have skipped the std::getline()
input. Why?
cin
stops reading at white space and does not consume the newline character.
getline()
generally reads to the end of the line and does consume the newline character.
For example:
- The user is prompted for a first name.
- The user types
Mary
, and the presses <enter>. - The <enter> key inserts a newline character in the input stream.
- The user is prompted for a full name.
- The
getline()
function sees the newline character and thinks the input was an empty string.
Let's try the above example again, but use std::cin.ignore()
to clear the input stream.
std:: cout << "Enter your first name: ";
std::cin >> first_name;
std::cout << "Hello, " << first_name << "." << std::endl;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Clear the input stream
std::cout << "Now enter your full name: ";
std::getline(std::cin, name);
std::cout << "Hello, " << name << ".\nHave a good day." << std::endl << std::endl;
Enter your first name:
Hello, John. Now enter your full name:
Hello, John Smith. Have a good day.
Using a Loop to Print Even Numbers from 1 to 100¶
How many times does this loop iterate?
std::cout << "Printing even integers from 1 to 100:" << std::endl;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
std::cout << i << " ";
}
}
std::cout << std::endl << std::endl;
Printing even integers from 1 to 100: 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100
The loop iterates 100 times and at each iteration, it checks if the current i value is even.
But do we have to evaluate every consecutive integer to discover whether it's even?
How many times does this next loop iterate?
for (int i = 2; i <= 100; i += 2) {
std::cout << i << " ";
}
std::cout << std::endl << std::endl;
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100
This second loop calculates the same correct result, while doing half as much work.
Using the MOD or REMAINDER Operator %
to Print n Elements Per Line¶
Attempt 1¶
int n = 10;
// Print the indexes, 10 per line.
// But this isn't quite correct. What's wrong?
std::cout << "First attempt to print 10 indexes per line:" << std::endl;
for (int i = 0; i < 100; i++) {
std::cout << i << " ";
if (i % n == 0) {
std::cout << std::endl;
}
}
std::cout << std::endl << std::endl;
First attempt to print 10 indexes per line: 0 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
But this isn't quite correct. What's wrong?
Zero is printed alone on the first line.
0 mod 10 = 0 // <-- The remainder is 0, but we don't want a newline right at the start.
1 mod 10 = 1
2 mod 10 = 2
3 mod 10 = 3
4 mod 10 = 4
5 mod 10 = 5
6 mod 10 = 6
7 mod 10 = 7
8 mod 10 = 8
9 mod 10 = 9
10 mod 10 = 0 // <-- Here is where we want to print our first newline.
Attempt 2¶
std::cout << "Second attempt to print 10 indexes per line:" << std::endl;
n = 10;
for (int i = 0; i < 100; i++) {
std::cout << i << " ";
if (i+1 % n == 0) {
std::cout << std::endl;
}
}
std::cout << std::endl << std::endl;
Second attempt to print 10 indexes per line: 0 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
This also isn't what we want. What's wrong?
Everything is printed on the same line.
Attempt 3¶
// Let's try one more time.
std::cout << "Third attempt to print 10 indexes per line:" << std::endl;
n = 10;
for (int i = 0; i < 100; i++) {
std::cout << i << " ";
if ((i + 1) % n == 0) { // Why does this change matter?
std::cout << std::endl;
}
}
std::cout << std::endl << std::endl;
Third attempt to print 10 indexes per line: 0 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
Operator %
has precedence over operator +
.
So, i + 1 % n
is interpreted as i + (1 % n)
, not (i + 1) % n
.
0 + (1 % 10) = 1 (0 + 1) % 10 = 1
1 + (1 % 10) = 2 (1 + 1) % 10 = 2
2 + (1 % 10) = 3 (2 + 1) % 10 = 3
3 + (1 % 10) = 4 (3 + 1) % 10 = 4
4 + (1 % 10) = 5 (4 + 1) % 10 = 5
5 + (1 % 10) = 6 (5 + 1) % 10 = 6
6 + (1 % 10) = 7 (6 + 1) % 10 = 7
7 + (1 % 10) = 8 (7 + 1) % 10 = 8
8 + (1 % 10) = 9 (8 + 1) % 10 = 9
9 + (1 % 10) = 10 (9 + 1) % 10 = 0
Because 1 % 10 = 1
, i + (1 % 10)
is always just i + 1
.