Skip to content

Latest commit

 

History

History
189 lines (130 loc) · 12.6 KB

PizzaPartyContinuation.md

File metadata and controls

189 lines (130 loc) · 12.6 KB

Look no further than your front yard for the next issue of the C++ Times. Our hard-working journalists go to the ends of the earth to bring you all the latest headlines from the world of CS1021C/EECE1080C.

Pizza Party 3.0

Recall where we last left off when designing and implementing the Pizza Party application:

  1 #include <iostream>
  2 
  3 /*
  4  * This program describes Will's pizza party with his (only)
  5  * friend Kevin.
  6  */
  7 int main() {
  8   std::string wills_friend{"Kevin"};
  9   std::cout << "Will and his friend " << wills_friend
 10             << " are sharing a large pizza.\n";
 11   std::cout << "Will eats 4 slices and " << wills_friend << " eats 2.\n";
 12   return 0;
 13 }

We called that version 2.0 and it was a significant upgrade over version 1.0. However, there are still many things that can be improved.

Most importantly, our string literals continue to have a hard-coded number of slices that each person eats. If I wanted to change the number of slices that I eat, it would require me to change the the number 4 anywhere I see it in the code. This is certainly not good!

So, let's fall back on the trick we learned earlier and replace those values with variables!

We learned in the previous lecture that every variable in C++ belongs to a particular category. Depending on the category of the variable, we can tell what kinds of values that variable can hold. In Pizza Party 2.0, our wills_friend variable held only strings which put it in a particular category.

Let's say that the number of slices that each person eats must be a whole number -- no one can eat just half a slice, after all! Pizza is just too tasty to stop halfway through! We will need, then, a category of variable designed to hold whole numbers! We will call them integers and their type is int.

A Type of Digression

Wait, type? What's that?? The type of a variable defines the

  1. range of valid values of a variable and
  2. valid operations (e.g., addition, subtraction, comparison, extracting a substring, etc) for a variable;

In this class we will learn the five most important types in C++:

Name Type Example
int Whole numbers 1, 10, 1024
double Fractional numbers 1.5, 71.0
char Single character 'c', '\n'
bool True or false true, false
std::string Strings "Testing", "c"

There are a few very important things to recognize in this table:

  1. 'c' is a character and "c" is a string, even though they both contain a single c. The ' is used to enclose a char and " is used to enclose a std::string.
  2. '\n' is a character, even though it looks like it contains two characters. Think about why and recall escape sequences.
  3. doubles can hold whole numbers (i.e., ints are a subset of doubles) but ints cannot hold fractional numbers.

Types play an important role in programming languages. Because they signal to the programmer (and the compiler!) the valid values that a variable can hold, they help prevent very terrible run-time errors. NASA famously lost a very expensive rocket in a very public, humiliating fashion because their software attempted to stuff a big number into a variable whose type limited it to hold only small numbers! Read more about that here.

If the compiler can alert the programmer to the fact that they are confusing types, their software can be safer: There is no chance that they assign, say, "My name is ..." to a variable designed to hold a number. Therefore, the software is always guaranteed to safely perform operations on variables (it would be very bad to attempt to divide "Please enter your password" by 5, say, because the result is nonsensical).

A type error occurs when a programmer attempts to assign a value of one type to a variable designated to hold a different, incompatible, type. For instance, attempting to store 'c' to a variable whose type is bool would make no sense (although C++ tries to be "helpful" in cases like this -- we will come back to that later!). A language that can always detect type errors (whether those errors are detected when the program is compiled or run) is known as a strongly typed programming language. A language that is not strongly typed is known as a weakly typed programming language. Obviously, it would be better for the language to detect type errors when the program is compiled (that makes them easier to fix), but even detecting type errors at runtime is better than nothing!

Back to Our Party

So, where were we? We were about to use variables of int type to hold the number of slices that my friend and I ate. We want these variables to hold 2 and 4 respectively. So, when we declare/define them (recall the definition of a declaration from last class), we will also want to initialize them (again, recall initialization from last class). As we discussed previously, although it is not strictly required, it is best practice to initialize variables when you declare/define them. You will see why in future lectures.

In order to accomplish what we just described, we can write

  int will_slices{2};
  int friend_slices{4};

and then introduce those variables in the appropriate places in the std::cout statements.

Pizza Party 4.0

Here's what our code looks like now:

#include <iostream>

int main() { std::string wills_friend{"Kevin"};

int will_slices{2}; int friend_slices{4};

std::cout << "Will and his friend " << wills_friend << " are sharing a large pizza.\n"; std::cout << "Will eats " << will_slices << " slices and " << wills_friend << " eats " << friend_slices << ".\n"; return 0; }

It would be great if our program were able to keep track of the number of the slices of pizza left to be eaten at any given time. Let's assume that a large pizza contains 10 slices of pizza to start (which was the class' consensus, despite some argument!).

Again, the number of slices is always going to be a whole number. Therefore, if we want to store this value in a variable, we would give that variable the int type. It seems like a reasonable name for a variable that holds the number of slices remaining to be eaten would be slices_remaining. It would start out containing the value 10.

  int slices_remaining{10};

After my friend and I eat some of the pizza, that number of slices remaining is going to change! Good thing that variables are designed to do exactly that -- vary!

In order to update the value of a variable, we can use the assignment statement/expression. Generally, the format of the assignment statement/expression is

  variable = <New Value>;

Notice that the variable you are updating goes on the left side of the =s sign. This arrangement is not obvious when you first see such a construction. As long as the New Value has a type that is compatible with the variable type, it can be anything you like: a literal, a variable, or the result of an operation!

The only requirement is that it have a value. In C++, an expression is anything that has a value! So far, we have seen two things that have values:

  1. Variables (their contents)
  2. Literals (well, exactly what is written)

There are others, though. In particular, the result of mathematical operations generate values and are, therefore, considered expressions. Let's use an expression to calculate a new value for the slices_remaining variable after my friend and I chow down.

Reminiscent of a word problem from elementary school math class, let's answer the following question: If there were 10 slices of pizza to start and Will ate 4 and his friend at 2, how many slices are left?

Number of slices that we started with - (number of slices that Will ate + the number of slices that his friend ate)

Awesome answer. Let's just translate that into C++:

  slices_remaining - (will_slices + friend_slices)

And we want to assign the result of that expression (!!) to slices_remaining so that it's value is updated:

  slices_remaining = slices_remaining - (will_slices + friend_slices);

Note a few things:

  1. We can use slices_remaining on both sides of the = without a problem. slices_remaining is only changed as a result of the assignment after the calculation on the right-hand side of the = is evaluated.
  2. There is a ; at the end because that entire "thing" represents a complete instruction to perform some action (the very definition of a statement) and we know that all statements in C++ end in a ;.

I was sneaky! I slipped in another new term: evaluate. When you evaluate an expression, you calculate it's value. For instance, if you evaluate the expression wills_friend, you get "Kevin" (remember, variables are expressions) and if you evaluate 5 + 3 you get 8. Pretty cool.

Here's the final version of Pizza Party 4.0:

#include <iostream>

int main() { std::string wills_friend{"Kevin"};

int will_slices{2}; int friend_slices{4};

int slices_remaining{10};

std::cout << "Will and his friend " << wills_friend << " are sharing a large pizza.\n"; std::cout << "Will eats " << will_slices << " slices and " << wills_friend << " eats " << friend_slices << ".\n";

slices_remaining = slices_remaining - (will_slices + friend_slices);

std::cout << "After eating their fill, the pizza has " << slices_remaining << " slices remaining.\n";

return 0; }

New Terms Defined in This Edition

  1. type
  2. type error
  3. strongly type language
  4. weakly type language
  5. assignment statement/expression
  6. expression
  7. evaluate