Contents

Command line

You should be able to use a command line interface (CLI). From Terminal in Mac, PowerShell in Windows, or whatever you might be using in Linux, you should be able to use the following commands:

If you need a refresher, see this page about the CLI (for the 160 class).

(Back to top)

Variables and constants

Variables must be declared before they can be used, though you can initialize a variable at the same it is declared. Declarations should go at the top of the scope in which the variables will be used. Variables should not be declared in the global scope (e.g., outside of all functions/classes). Variable names should follow these identifier naming style guidelines.

Constants should usually be declared in the global scope, just below the header. Constants are, well, constant, so they can never be reassigned later in your code. Constant names should follow these identifier naming style guidelines.

The basic types we most often user are: int, long, float, double, char, string, and bool.

Here is an example of a very simple program that uses constants and variables:

For more information, see the CSC160 page on variables.

(Back to top)

IO

To interact with the user, use cout (for standard output), cerr (for errors), cin (to get input), and getline (to get entire lines of input).

To interact with a file, be sure to include the fstream library at the top of your C++ source file. To read from a file, you will need to create an ifstream (input file stream) object and open your file through that: ifstream inFile; inFile.open(filename.c_str());. You can then use inFile (or whatever you called it) just like cin (in fact, you can use it with getline, too). Use inFile.close(); to close the file.

To write to a file, you will need to create an ofstream (output file stream) object and open the file you want to write to through that. By default, whatever is stored in the file you open via ofstream will be erased (there is a way to append, too). Here's the code: ofstream outFile; outFile.open(filename.c_str());. Then use outFile (or whatever you'd like to call it) exactly like cout. Use inFile.close(); to close the file.

Here's an example that uses all three:

(Back to top)

Conditionals

Use if, else if, and else statements to test conditions. Generally, we have the structure:

In an if/else or if/else-if/else, exactly one branch will be executed—the others will be ignored. In an if or if/else-if, it is possible that none of the branches will be executed.

An expression can be:

For case-based conditions, you can also use a switch statement. These can be used with int and char types. Here's the structure:

Here, variable is the int or char type to be evaluated. Each case covers one of the possibilities, where val1 is the value you want to test against. You need a break statement at the end of each case, or else the code within the next case will be evaluate (sometimes you want that, but usually not). Here's an example where we use a switch statement to determine what choice the user just entered:

(Back to top)

Functions

There are three elements to remember about functions: declarations, definitions, and invocations. Functions should be declared above main and defined below. Invocations can occur in main or any other function.

Functions are described by their signature, which consists of the return type, name, and parameters. Here's an the signature for main:

Here's the signature of a function named printName that doesn't return anything, but takes a string as a parameter:

For each parameter, the signature must include the type and a name that will be used to refer to that parameter within the function. The order matters—whatever order you put the parameters in in your signature, you must use the same order in your declaration, definition, and invocation.

Declarations consist of the signature followed by a ;. Definitions consist of the signature followed by a pair of curly braces. If the signature includes a return type, then the function should always return something of that type, using the return statement. Invocations consist of the function name, a pair of parentheses, and then include the variables or values you want to correspond to each parameter from the signature, in the same order. The names of the variables you pass in do not need to be the same as the parameter names!!! Here's and example:

Be sure to take a look at the style guide for information about the format of comments above functions.

In the functions above, we're passing parameters by value. That means that the values of variables passed in when a function is invoked are copied into memory designated explicitly for the function. That also means that if you reassign a new value to a parameter, that reassignment will not be reflected outside of the function. Here's an example:

This will print:

Hank
Hank

In order to be able to reassign a value to parameters, you need to pass by reference. This involves adding an ampersand (&) prior to parameter names in the function signature (so your declaration and definition will be affected). You don't need to do anything special in the function. Here's the code from above, with pass by reference:

This will print:

Hank
Bob

Perfect! Now, lets suppose that you don't want to allow changes to the data that's passed in. That may seem funny, since we motivated using pass-by-reference so that we could change the underlying value. But there are other motivations, such as not wasting memory by uselessly copying structures over and over again. So, if you want to not copy the data, but you also don't want to be able to change the value, then there is a special keyword that precedes the parameter type in the signature: const. If you try to alter the value of a parameter that is const, then the compiler will get mad at you. Here's an example:

(Back to top)

Loops

There are three main loops: for, while, and do while. Here are examples of all three. Each prints out the number 1–10.

(Back to top)

Structs and classes

Structs and classes are actually the same thing in C++, with the one exception that the default privacy setting for structs is public, while it is private for classes. They can both have public and private data members and methods. They can have constructors and destructors. In practice, structs are usually used as a container for several publicly accissible data members (this type of thing is commonly called a Plain Old Data (POD) stucture).

Structs should be defined above main, and should include the keyword struct followed by the name of the structure, followed by a pair of curly braces and a semicolon. Inside the braces, the data members (or fields) should be declared. Each should consist of the type followed by its name, just like when you declare variables anywhere else. You can declare an instance of your struct just like any other variable or constant; just use the name of your struct as the type. You can then use the dot notation to access fields of the instance. Here's an example:

We can implement a class almost identically; we just need to use the class keyword instead of struct and we need to make data members publicly accessible:

While this is technically correct, it is not how we should implement classes. Instead, we should create two separate files: the header file which consists of the class specification or interface (the file name should end in .h) and a file for the class implementation (the file name should end in .cpp). Class names conventionally start with a capital letter, so we would use Person instead of person. In addition, it is typical that data members are not exposed publicly, but instead methods (functions defined within the class) are used to get or set data member values. Here's an example:

Person.h Person.cpp main.cpp

To compile and run, do:

$ g++ Person.cpp main.cpp -o person
$ ./person 
Name:   Bobby
Age:    8
Gender: m

Struct and class instances can be passed to functions, but if they are not passed by reference, then none of the changes to any static data members will not be reflected outside of the function. This is because the entire instance is copied in pass by reference, data members included.

(Back to top)

Arrays

Arrays store a list of data in adjacent memory blocks. Arrays can be of any type, including nested arrays. Here're some ways we can create a simple array to hold five ints:

The last example above also demonstrates how to access an array element. The indexes start at 0, and end at the length - 1. Note that we must keep track of the size!

When you pass arrays to functions, the parameter in the function signature just needs to have a [] at the end. You can update the elements of the array without passing by reference. E.g.,:

This prints out the following:

1 3 4 
392 3 4

Now suppose you want to pass an array, but don't want it modified? You can use the const keyword. E.g., use the signature void modify(const int nums[], int size) in the example above. This will cause compiler errors if the modify function includes any assignments to elements of nums, such as nums[0] = 392;.

Multi-dimensional arrays are pretty simple extensions. The main caveat is that where there are a couple of places where you don't need the array size in a 1D array (e.g., when you declare and initialize at the same time, or when specifying an array as a parameter), with 2+D arrays, you need to specify the size for every dimension other than the first. E.g.,:

To pass as a parameter, just add an extra square bracket with the dimension for each additional dimension. E.g.:

Will print out:

1 11 4 
6 23 422 
29 8 98 

392 11 4 
6 23 422 
29 8 98 

Arrays are very related to pointers. Here's a nice YouTube video explaining the relationship.

(Back to top)

Pointers

First, watch this video to refresh yourself with pointers, the heap, and the stack..

Here are some of the basics. To create a pointer of a given type, place an asterisk after the type and before the variable name: int *myIntPointer;. If you have another variable, say myRegularInt, that you want myIntPointer to point to, you need to assign the address of myRegularInt to myIntPointer. You do this by using the & symbol:

This will print out 10. The asterisk in front of myIntPointer in the last line dereferences the value pointed to by myIntPointer. Now if we do myRegularInt = 20;, then *myIntPointer will be 20 as well.

In the example above, myRegularInt was placed on the stack, so the pointer myIntPointer pointed to memory on the stack. To allocate memory from the heap (something we need to do for arrays where we don't know at compile time what the size will be), we need to use the new keyword. E.g.,:

This will print 10. Now, every time we allocate memory, we need to deallocate it, too, using the delete keyword:

In classes, the destructor should do this for any dynamic memory allocated during the lifetime of an instance.

Lets talk about dynamic arrays. They look very similar to static array. Here's a full example:

Note the delete[] myNums;—we have to add square brackets for an array deallocation. This prints out:

1 13 424 
392 13 424

Now, what if we want to pass a pointer by reference? This is especially helpful when we need to allocate additional space for a dynamic array:

This prints out:

1 13 424 
392 1309 9

When we use pointers with classes and structs, we can use the arrow notation (->) to dereference. Suppose we wanted to dynamically allocate memory for an instance of the Person class. Here's what it would look like:

The arrow notation is equivalent to the following:

Arrows are easier to write and are more standard, so I would strongly recommend you use them. We'll use pointers more throughout the semester.

(Back to top)