Week 5: Loops
Learning Goals
CONTENTS:
- Learning Goals
- Readings
- Background
- PreQuiz Assignment (due Monday Feb 10 at 9am)
- Recitation
- Recitation Submission Guidelines
- Homework
Readings
Please note the advised readings of “Brief C++ Late Objects” - Cay Horstmann:
- Monday: 4.1, 4.2
- Wednesday: 4.3
- Friday: 4.3 (re-read), 4.5, 4.6, 4.8, 4.9
Background
Loops are a tool that allows us to repeat a block of code. The number of repetitions is controlled by the conditions of the loop, and can range anywhere from never executing, executing a fixed number of times, or executing an infinite number of times. Loops will execute for as long as their condition is satisfied; once the condition is not true, the loop will stop and the program will continue. The structure of these conditions can vary depending on the type of loop used. There are three main types of loop we use in C++; the while loop, the do-while loop, and the for loop.
While Loops
While loops are the most basic form of loops. Their structure looks like:
while (condition)
{
//code to execute
}
Here, while
is a C++ reserved word, condition
should be a Boolean expression that will evaluate to either true
or false
, and the comment between the brackets is where we would add code to execute. If the condition is true, then the specified statement(s) within the loop are executed. After running once, the Boolean expression is re-evaluated. If the condition is true, the specified statement(s) are executed again. This process of evaluation and execution is repeated until the condition becomes false
.
// Here is an example of a while loop
// where the condition is based on user input.
int userChoice;
userChoice = 1;
while (userChoice != 0)
{
cout << "Do you want to see the question again?" << endl;
cout << "Press 0 if no, any other number if yes." << endl;
cin >> userChoice;
}
Entering 0
will terminate the loop, but any other number will cause the loop to execute again. Note how we must initialize the condition before the loop starts. Setting userChoice = 1
ensures that the while loop will run at least once.
// Here is an example of a while loop
// where the condition is based on a counter.
int i;
i = 0;
while (i < 5)
{
cout << i << endl;
i = i + 2;
}
Notice how you must manually initialize i=0
and then manually increment i
by 2
(i = i + 2
).
Do-While Loops
The do-while loop is a variant of the while loop. The critical difference with a do-while loop is that the block of code we wish to execute is written before the condition. The structure of a do-while loop looks like this:
do {
// code block to be executed
}
while (condition);
In a do-while loop, the block of code is executed once before the condition is checked. This means we will never entirely skip a do-while loop. You will often find this type of loop to be useful when gathering user input, like the example shown below.
// Here is an example of the while loop from example 1.1.1. rewritten as a do-while loop.
int userChoice;
do {
cout << "Do you want to see the question again?" << endl;
cout << "Press 0 if no, any other number if yes." << endl;
cin >> userChoice;
}
while (userChoice != 0);
Note that here we do not have to initialize user choice before the loop begins.
For Loops
You will frequently come across instances where you already know the number of iterations you would like your loop to complete, like the while (i < 5)
example shown above. In these cases, there is a special loop that has a counter built in rather than needing to keep track on your own. For loops have three elements, which we call the “three Cs” create, compare, change:
- CREATE: It must create/”initialize” a counter variable to a starting value. Note: When initializing your counter, you can choose to either declare a new variable or use an existing variable. If you declare a new variable in your initialization, it will only exist in the scope of the loop; this means once the loop concludes, you cannot access that variable again.
- COMPARE: many things as a logical expression. if the expressions value is true, then the body of the loop is executed. If it is false, the body of the loop does not execute and jumps to the next statement(s) just after the loop.
- CHANGE: Update the counter variable during each iteration
The basic structure of a for loop looks like this:
for ( create ; compare ; change )
{
//code to execute
}
Here, for
is a C++ reserved word.
// Here is a section of code that will
// print the word "hello" five times:
for ( int count = 0 ; count < 5 ; count++ )
{
cout << "hello" << endl;
}
Notice the following three parts of the for loop:
- CREATE: count is initialized to 0,
- COMPARE: the conditional expression is count < 5
- CHANGE: count++ to increment the count value by one
// Here is an example that would work e
// quivalently to the `while (i < 5)` example
for (int i = 0; i < 5; i = i + 2)
{
cout << i << endl;
}
// REMINDER of `while (i < 5)` example:
int i;
i = 0;
while (i < 5)
{
cout << i << endl;
i = i + 2;
}
-Wsign-compare
As we deal with loops it becomes particularly important that we add -Wsign-compare
to our build commands.
g++ -Wall -Werror -Wpedantic -Wsign-compare -std=c++17 myCodeFile.cpp
Common Errors and Debugging Loops
Unique errors with loops include:
- Errors with the loop syntax itself, such as your condition or the set of statements in your for loops. Check that you have semicolons
;
and have declared all your variables that you use in this area. - infinite loops, which will frequently present as either a program that never stops running or an error saying something along the lines of memory exceeded or time exceeded. Check your conditions, and make sure the variables that control your condition are updating correctly.
- incorrect numbers of iterations, which means you may not be updating your counter correctly or your logic may be incorrect.
Here is a flowchart for helping you figure out (and resolve) what is wrong with your loops:
Any errors that you may come across either within the bracketed section of your loop or outside of your loop are subject to the same rules as any code we have previously worked with. If you are struggling with errors in those areas, revisit debugging tips from the relevant sections to help you.
The details of the flowchart are written here in text for better accessible technology support:
Does your code compile?
- no: comment out the loop and only the loop. does it comile now?
- no: You have issues elsewhere in your code. Resolve those and try again.
- yes: Uncomment your loop. Comment out the executed code between the brackets. Does it compile now?
- no: there is something wrong with your loop syntax. Check your conditions and brackets.
- yes: There is something wrong with your code inside the brackets. Resolve those errors first.
- yes: Does your code run?
- no: it quites with an error. add a cout statement immediately before your loo, and a cout statement immediately after your loop. Run again. what happens?
- neith print: your error is earlier in your code. Resolve those errors and try again.
- only the first statement prints: your error is in your loop. You can add cout statements inside the loop to see which line casues the error.
- both statements print: your error is after your loop. Resolve those errros and try again..
- yes: but it doesn’t stop running: you have an infinite loop in your code. You can add cout statements to each loop to find the culprit, and then check the condition.
- yes: but the output is wrong: Add cout statements to print the variable values at each step. Make sure there are the correct number of steps, adn that each value is changing appropriately.
- yes, and it’s correct!: Done!
- no: it quites with an error. add a cout statement immediately before your loo, and a cout statement immediately after your loop. Run again. what happens?
PreQuiz Assignment (due Monday Feb 10 at 9am)
Recitation
Recitation Spot The Error - Problem 1
The program below will display the average of three values by calling the function findMean
. Identify the error(s) in the code below, and write the correct line(s).
#include <iostream>
using namespace std;
double findMean(int a, int b, int c)
{
int mean = a+b+c / 3
return mean;
}
int main()
{
double average = avg(2,5,2);
assert(average == 3);
return 0;
}
Recitation Spot The Error - Problem 2
The program below checks if the two strings given are the same. Identify the error(s) in the code below, and write the correct line(s).
#include <iostream>
#include <string>
using namespace std;
string passcodeMatchCheck(string passcode, string confirmPasscode)
{
return passcode == confirmPasscode;
}
int main()
{
bool passcodeMatch = passcodeMatchCheck(2158,"2158");
assert(passcodeMatch == true);
}
Recitation Spot The Error - Problem 3
The same company uses a member ID as the username for its employees. The employees all have a four digit member ID, and the member ID cannot start with a 0.
#include <iostream>
#include <cassert>
using namespace std;
bool idLengthCheck(int ID)
{
if (ID >= 999 || ID < 10000)
{
return true;
}
return false;
}
int main()
{
assert(idLengthCheck(12345678));
assert(idLengthCheck("123456789") == False);
return 0;
}
Recitation Spot The Error - Problem 4
The program below will use two functions: one to check for password match and another to check if the ID is valid before registering the user. Assume the relevant functions have been defined successfully. Identify the error(s) in the code below, and write the correct line(s).
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
bool passwordMatchCheck(char, char);
bool idLengthCheck(char);
int main() {
int ID;
string password;
string confirmPassword;
cout << "Enter your member ID: ";
cin >> ID;
assert(idLengthCheck(ID));
cout << "Enter your password: ";
cin >> password;
cout << "Confirm your password: ";
cin >> confirmPassword;
if (passwordMatchCheck(password, confirmPassword))
{
cout << "Password set successfully for " << username << "." << endl;
}
else if (!passwordMatchCheck(password, confirmPassword))
{
cout << "Passwords do not match." << endl;
}
else if(!idLengthCheck(ID))
{
cout << "ID is invalid." << endl;
}
return 0;
}
bool passwordMatchCheck(string password, string confirmPassword)
{
// appropriate definitions
}
bool idLengthCheck(string password)
{
// appropriate definitions
}
Recitation Spot The Error (Style Issues) - Problem 5
The program below is a working program that uses the getPrice
function to compute the price of a wall frame of a given area and color. This code does not contain any syntax or logical errors. However, it has multiple style errors making the code very difficult to read. These errors can range from usage of unintended whitespace to having extraneous variables or clauses in your code. Identify the style error(s) in the code below and rewrite the code to improve readability.
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
double getPrice(double area, string color){
assert(area>=0); double cost = 0.0;
if (color == "green"){
cost = 4; }
else if (color == "red")
{ cost = 3; }
else if (color == "orange")
{
cost = 2;
}
else if (color == "blue")
{
cost = 1;
} return area * cost;}
int main()
{
string color, shape;
int area_choice;
double radius;
double area = 0;
cout << "Enter the area of the frame: (1) 5x5 (2) 4x6 (3) 8x10" << endl;
cin >> area_choice;
assert(
area_choice == 1 || area_choice == 2 || area_choice == 3
);
if(area_choice == 1){area = 5*5; }
else if (area_choice == 2){area = 4*6; }
else if (area_choice == 3){area = 8*10; }
cout << "Enter the color of the frame: (green, red, orange, blue): ";
cin >> color;
assert(
color == "green" || color == "red" || color == "orange" || color == "blue"
);
double price = getPrice(area, color);
cout << "You will receive a "<< color << " color frame with a price of $" << price << ". ";
cout << "Thank you for your business."<<endl;
return 0;
}
Recitation Pseudocode Analysis Problem 6
What output does the following pseudocode produce?
Start
Declare an integer variable `m` and initialize it to -1.
Declare an integer variable `i` and initialize it to 0.
While `i` is less than 5, do:
Declare an integer variable `s` and initialize it to 1.
If `i` is not 0 and the remainder of `i` divided by 3 is 0, then:
Multiply `s` by -1 and assign the result back to `s`.
Print the product of `m` and `s`.
Else:
Increment `m` by 2.
Print the value of `m`.
Increment `i` by one.
End
Recitation Valentine’s Day! - Problem 7
At the Violet Peak Cafe in CU Boulder, the arrival of valentine’s week means it’s time to stock up on specialty coffee beans and syrups. To efficiently manage storage, the cafe uses two types of containers:
- Cylindrical Containers for large batches of coffee beans.
- Spherical Containers for special red velvet mocha syrup.
The manager wants to calculate the volume of each container to ensure they have enough storage capacity before the season begins. Your task is to help them by writing two functions that accurately calculate the volumes of the containers.
/*
@brief Calculates the volume of a cylindrical container
@param radius Radius of the base
@param height Height of the cylinder
@return double - volume of the cylindrical container
*/
double calculateCylindricalVolume(double radius, double height) { /* Your code goes here. */ }
/*
@brief Calculates the volume of a spherical container
@param radius Radius of the sphere
@return double - volume of the spherical container
*/
double calculateSphericalVolume(double radius) { /* Your code goes here. */ }
Recitation Valentine’s Day! - Problem 7.a.: Algorithm
Write out the steps you would use to solve this problem by hand as pseudocode.
Recitation Valentine’s Day! - Problem 7.b.: Examples
Pick two possible inputs for each of your two functions (four total). Follow the steps you wrote for these values to find your result, and verify it.
Recitation Valentine’s Day! - Problem 7.c.: Assert Statements
Translate your inputs and expected outputs into assert
statements.
Recitation Valentine’s Day! - Problem 7.d.: Implementation
Translate your pseudocode into a C++ program to solve the above code, using your assert statements in your main
function to verify that your program works as expected.
Recitation Submission Guidelines
Important: Follow these instructions carefully when preparing your recitation assignments. Your final submission should be in a single document, and the only action required on Canvas is uploading that document.
- Documentation:
- Create a pdf that includes your submission for all recitation questions. This is the pdf you will upload to your canvas assignment. Feel free to use Word/Google doc to create the pdf.
- Clearly label each question with its corresponding number and include content as applicable (see #2).
- Content to Include:
- Screenshots of Your Code:
- For each question, include a screenshot of your code.(corrected code in case of spot the errors)
- Screenshots of Code Output (if applicable):
- For some longer questions, it might be required to take a screenshot of the code’s output. Include these screenshots as part of your submission.
- Longer Recitation Questions (Multiple Parts):
- Option A:
- Comment your answers directly within your code file.(Spot the errors)
- Take screenshots of the commented code and paste them into your document.
- Option B:
- Take screenshots of the unmodified code.
- Write your answers (Free Response/Pseudocode/Edge case identifictation) to the subquestions in the pdf document next to the corresponding screenshots.
- Option A:
- Screenshots of Your Code:
- Submission:
- Upload the final pdf document to Canvas. This is the only action required on Canvas for your submission.
By following these steps, your submission will be clear, organized, and standardized across all recitation assignments.
Homework
You should complete the following homework using VSCode and the skills that you have learned to author, compile, and execute programs. You should build and fix your code using VSCode. Once you believe you have completed the assignment locally, submit your work on Canvas using the appropriate link for the assignment and the “coderunner” tool.
The coderunner questions match these questions exactly. It will tell you what to do for the problem, give you a few examples of input/output. Give you a space to submit your code.
Encrypting Lowercase Characters
The Caesar cipher shifts each letter by a fixed number of positions within the alphabet. The shift value can be positive or negative and should wrap around the alphabet if necessary. For example, with a shift of 3, a
would be replaced by d
, b
would become e
, and so on. If the shift is -3, d
would be replaced by a
, e
would become b
, etc. For simplicity, we are only encrypting lowercase letters in this question.
Note: Characters like ‘a’ and ‘z’ have specific ASCII values that are case-sensitive (a == 97 && z == 122
). The code uses these values indirectly by operating on character arithmetic rather than directly manipulating ASCII values.
Write a program that encrypts lowercase letters using the Caesar cipher. Prompt the user for a letter and a shift value in main()
, and use the function specification listed below for encryption.
Function: | encryptLower(char, int) char encryptLower(char letter, int shift_value) |
Purpose: | Encrypt the letter using the shift value. The function should not print anything. |
Parameters: | char letter - The letter that is being encrypted. int shift_value - The shift value. |
Return value: | If successful, returns the newly encrypted letter. |
Error handling && Boundary conditions: | - If the unencrypted letter is not lowercase, then the unencrypted letter is returned. In other words, return the original letter if it’s not lowercase. - Hint: You may use the modulo % operation to handle the wrap-around, e.g., if the letter is a and the shift value is -1 , the encrypted letter should result in z . |
Example:
// This is only an example usage, and you should develop your own main function
// Assume the proper libraries are included.
// Assume the proper implementation of encryptLower() is included.
int main() {
char letter = 'r';
char encrypted_letter = encryptLower(letter, 5);
cout << "Letter " << letter << " was encrypted to " << encrypted_letter << endl;
return 0;
}
Sample Output (from above example): Letter r
was encrypted to w
.
HINT: If you are struggling with this a more extensive template is provided after the examples
// A MORE EXTENSIVE TEMPLATE::
//
// IMPORT STUFF
//
#include<iostream> // cout, endl
#include<cassert> // assert
using namespace std;
//
// DECALARE HELPERS
//
char encryptLower(char letter, int shift_value);
void testEncrypt( );
//
// DEFINE MAIN
//
int main() {
// can comment me out before submission
testEncrypt();
// I was provided on the web-workbook
// I should be changed before final submission
char letter = 'r';
char encrypted_letter = encryptLower(letter, 5);
cout << "Letter " << letter << " was encrypted to " << encrypted_letter << endl;
return 0;
}
//
// DEFINE ALL HELPER FUNCTIONS
//
/**
* encryptLower
* given a lowercase letter
* shift the value to allow for encryption of the character
*/
char encryptLower(char letter, int shift_value)
{
// change me to false before submission!
// so the debug prints don't happen!
bool debug = true;
if (debug) cout << "\n\nTESTING: " << letter << " shifted by " << shift_value << endl;
if (debug) cout << "I am a guarded print statement. I can be helpful for debugging code." << endl;
// write psudo-code comments here before you code
return letter;
}
void testEncrypt( )
{
// I'm the easy tests...
assert( ',' == encryptLower(',' , 1));
assert( 'D' == encryptLower('D' , 1));
// // uncomment me in blocks
// assert( 'b' == encryptLower('a' , 1));
// assert( 'c' == encryptLower('a' , 2));
// assert( 'd' == encryptLower('a' , 3));
// // uncomment me in blocks
// assert( 'b' == encryptLower('c' , -1));
// assert( 'a' == encryptLower('c' , -2));
// // I'm a bit harder (consider using `%` as part of solution)
// assert( 'a' == encryptLower('a' , 26));
// assert( 'c' == encryptLower('a' , 28));
// // I am even harder
// assert( 'a' == encryptLower('z' , 1));
// assert( 'b' == encryptLower('z' , 2));
// assert( 'z' == encryptLower('a' , -1));
// assert( 'y' == encryptLower('a' , -2));
// // I am likely extra hard tests
// assert( 'u' == encryptLower('s', -50));
// // ADVANCED: not on gradescope anymore
// // but you might look into the topic "char overflow"
// // consider an `unsigned char`
// assert( 'v' == encryptLower('z', 22));
}
Building a Snowman
In this problem, you are tasked with simulating the process of three snowballs rolling down a hill to create a snowman. Each snowball must grow to a specific size to form the snowman’s head, mid-body, and lower-body.
Initially, each snowball starts with a size of 1 unit and grows at a variable rate. The growth rate begins at 1 unit per second and increases by 1 unit each second (for example, the snowball grows by 1 unit in the first second, 2 units in the second second, 3 units in the third second, and so on).
You need to calculate the amount of time each snowball will roll to reach the required sizes for the snowman’s head, mid-body, and lower-body. Additionally, determine the total time needed for all three snowballs to achieve their respective sizes.
Note: You should check if the size input for each body part is positive in main()
. If the input is non-positive (i.e., zero or negative), output "Please enter a positive integer for <section> size:"
, where <section>
is part of the snowman that received invalid input, and prompt for the input again. This ensures that only valid sizes are accepted for the snowman parts.
Function: | calculateTime(int) int calculateTime(int target_size) |
Purpose: | The function will calculate the time needed for the snowball to reach each part’s specified target_size . The function should not print anything. |
Parameters: | int target_size - The desired size that the snowball needs to reach |
Return Value: | If successful, it returns the time it takes to reach the desired size of the snowball in seconds. |
Error Handling: | The error handling for desired size will occur in main() , which means all target_size should be valid. |
Example:
// This is only an example usage, and you should develop your own main function
// Assume the proper libraries are included.
// Assume the proper implementation of calculateTime() is included.
int main() {
int head_time = calculateTime(6);
cout << "Time to reach head size: " << head_time << " seconds" ;
return 0;
}
Sample Output (from above example): Time to reach head size: 3 seconds
Develop and validate your solution in VS Code. Once you are happy with your solution, go to coderunner on Canvas and paste the whole program into the answer box!
Print Collatz Sequence
For this question, you will write a program that prompts the user to enter an integer value between 10 and 500 (both exclusive). Your program should then print out a sequence of numbers between the given value and 1 (inclusive) following the pattern below: For a given number ai,
- If ai is even, then ai+1 = floor(ai/2)
- If ai is odd, then ai+1 = 3*ai + 1
Your program should stop printing numbers once the sequence reaches the value of 1.
If the user enters a number that is not between 10 and 500 (both exclusive), print Invalid input.
and prompt the user for a number again.
This sequence is referred to as the Collatz sequence. The Collatz Conjecture states that this sequence will eventually reach the value of 1 for any starting number, a fact that has not yet been proven by modern mathematics!
Note: floor(x) means that x should be rounded down to the nearest integer.
Develop and validate your solution in VS Code. Once you are happy with your solution, go to coderunner on Canvas and paste the whole program into the answer box!
Potion Crafting
You are developing a crafting system for an RPG video game where players can create two types of potions: Health Potions and Magic Potions. Each type of potion requires four key ingredients: Tealeaves, Sunflowers, Toadstools, and Pine Needles. However, the quantity of each ingredient needed differs slightly between the two types of potions.
Your task is to write a program that asks the user which potion they would like to prioritize—Health or Magic. If the user enters an invalid number for the type of potion, the program should ask them to re-enter like this: Invalid input. Please select 1 or 2.
The program will then prompt the user to input the number of each ingredient they currently have (Tealeaves, Sunflowers, Toadstools, and Pine Needles). Based on the available ingredients, calculate how many potions of the priority type can be crafted. Any leftover ingredients should be used to craft as many of the other types of potion as possible. Finally, the program should output how many of the priority potions can be crafted and how many of the other potions can be made with the remaining ingredients.
The ingredient requirements for each type of potion are as follows:
Ingredients | Amount for Health Potion | Amount for Magic Potion |
---|---|---|
Tealeaves | 6 | 2 |
Sunflowers | 1 | 3 |
Toadstools | 5 | 10 |
Pine Needles | 2 | 1 |
Develop and validate your solution in VS Code. Once you are happy with your solution, go to coderunner on Canvas and paste the whole program into the answer box!
Validate Integer
Design a function validateInt
that accepts a string input and determines if it represents a valid integer by checking if each character in the string is a valid value. Your program should ask the user to input an integer, store it as a string, and then invoke the validateInt
function to check its validity. The program should then print whether the string is a valid integer or not. (Negative integers are also valid integers).
PROTIP: We move through strings using a for loop. For any string x
the expression x.length()
will evaulate to a type size_t
. This is a very specific type of number. If you’d like, you can treat it like an unsigned int
instead. e.g.
string x;
cout << "I can haz string without spaces?" << endl;
cin >> x;
for ( size_t i = 0 ; i < x.length() ; i++ )
{
cout << "using size_t above: " << x[i] << endl;
}
for ( unsigned int i = 0 ; i < x.length() ; i++ )
{
cout << "using unsigned int above: " << x[i] << endl;
}
// // COMPILER ERROR thanks to `-Werror`
// for ( int i = 0 ; i < x.length() ; i++ )
// {
// cout << "using int above: " << x[i] << endl;
// }
Function: | validateInt(string) bool validateInt(string input) |
Purpose: | Iterate through a string and verify if it is a valid integer or not. The function should not print anything. |
Parameters: | string input - The string to be verified |
Return value: | It returns true if the string is a valid integer. Otherwise, it returns false . |
Error handling && Boundary conditions: | If length of input = 0, false is returned |
Example: |
// Assume the proper libraries are included.
// Assume the proper implementation of validateInt() is included.
int main()
{
string number;
cout << "Enter the integer : " << endl;
getline(cin, number);
if(!validateInt(number))
{
cout << "The entered string is not a valid integer!!" << endl;
}
else
{
cout << "The entered string is a valid integer!!" << endl;
}
return 0;
}
example of running the above code
Develop and validate your solution in VS Code. Once you are happy with your solution, go to coderunner on Canvas and paste just the validateInt()
function into the answer box!