CS420 - Midterm Cheat Sheet
CS420 - Midterm Cheat Sheet
CS420 - Midterm Cheat Sheet
The dereference operator (*) is prepended to a pointer variable's name to retrieve the data to which the pointer variable points. Ex: If valPointer points to a memory
address containing the integer 123, then printf("%d", *valPointer); dereferences valPointer and outputs 123. ASSIGNS VALUE OF ADDRESS
Null pointer assignments and initialization - *pointer = NULL; // to assign as null or “0” on some systems
int main(void) {
int someInt;
int* valPointer; // integer pointer
someInt = 5;
printf("someInt address is %p\n", (void*) &someInt); //using & to obtain address
valPointer = &someInt; // assigning int* pointer to the address of someInt
printf("valPointer is %p\n", (void*) valPointer); //will print the address in hex using %p
return 0;
int main() {
int someInt;
int* valPointer;
someInt = 5;
printf("someInt address is %p\n", (void*) &someInt); //PRINTS ADDRESS i.e. 76
return 0;
}
7.4 Using Malloc & Pointers with Struct Types [Memory Allocation] (C programming)
#include <stdio.h> int main(void) {
#include <stdlib.h> myItem* myItemPtr1 = NULL;
strrchr(sourceStr, searchChar)
if (strrchr(orgName, 'D') != NULL) { // 'D' exists in orgName?
Returns NULL if searchChar does not subString = strrchr(orgName, 'D'); // Points to last 'D'
strrchr()
exist in sourceStr. Else, returns strcpy(newText, subString); // newText now "Dept."
pointer to LAST occurrence (searches in }
reverse, hence middle 'r' in name).
strstr(str1, str2)
subString = strstr(orgName, "Dept"); // Points to first 'D'
Returns NULL if str2 does not exist in if (subString != NULL) {
strstr() str1. Else, returns a char pointer strcpy(newText, subString); // newText now "Dept. of
pointing to the first character of the Redundancy Dept."
first occurrence of string str2 within }
string str1.
// Modify string, hello + user specified name // Output greeting and name
strcpy(greetingPtr, "Hello "); printf("Hello %s", nameCopy);
strcat(greetingPtr, nameArr);
strcat(greetingPtr, "."); // Deallocate memory
free(nameCopy);
// Output greeting and name
printf("%s\n", greetingPtr); return 0;
}
free(greetingPtr);
return 0;
7.8 Vector ADT (C programming)
Structs and pointers can be used to implement a computing concept known as an abstract data type (ADT), which is a data type whose creation and update are supported
by specific well-defined operations. A key aspect of an ADT is that the internal implementation of the data and operations are hidden from the ADT user, a concept known
as information hiding
void vector_destroy(vector* v) Destroys the vector by freeing all memory allocated within the vector. vector_destroy(&v)
void vector_resize(vector* v, Resizes the vector with vectorSize number of elements. If the vector
size increased, each new element within the vector is initialized to 0. vector_resize(&v, 25)
unsigned int vectorSize)
Returns the vector's size — i.e. the number of elements within the
unsigned int vector_size(vector* v) vector. if (vector_size(&v) == 0)
return v->size;
7.11 Memory regions: Heap/Stack (C programming)
A program's memory usage typically includes four diZerent regions:
• Code — The region where the program instructions are stored.
• Static memory — The region where global variables (variables declared outside any function) as well as static local variables (variables declared inside
functions starting with the keyword "static") are allocated. Static variables are allocated once and stay in the same memory location for the duration of a
program's execution.
• The stack — The region where a function's local variables are allocated during a function call. A function call adds local variables to the stack, and a return
removes them, like adding and removing dishes from a pile; hence the term "stack." Because this memory is automatically allocated and deallocated, it is also
called automatic memory.
• The heap — The region where the malloc function allocates memory, and where the free function deallocates memory. The region is also called free store
Virtual functions
Runtime polymorphism only works when an overridden member function in a base class is virtual. A virtual function is a member function that may be overridden in a
derived class and is used for runtime polymorphism. A virtual function is declared by prepending the keyword "virtual". Ex: virtual string GetDescription() const. At runtime,
when a virtual function is called using a pointer, the correct function to call is dynamically determined based on the actual object type to which the pointer or reference
refers.
The override keyword is an optional keyword used to indicate that a virtual function is overridden in a derived class. Good practice is to use the override keyword when
overriding a virtual function to avoid accidentally misspelling the function name or typing the wrong parameters.
class Business {
public:
string GetDescription() const {
return name + " -- " + address;
}
No virtual function:
...
}; Friends Cafe -- 500 2nd Ave
class Restaurant : public Business {
public:
string GetDescription() const {
return name + " -- " + address +
"\n Rating: " + to_string(rating);
With virtual function:
}
... Friends Cafe -- 500 2nd Ave
}; Rating: 5
int main() {
Business* businessPtr;
Restaurant favoriteCafe;
favoriteCafe.SetName("Friends Cafe");
Virtual table
favoriteCafe.SetAddress("500 2nd Ave"); To implement virtual functions, the compiler creates a virtual table that allows
favoriteCafe.SetRating(5); the computer to quickly lookup which function to call at runtime. The virtual table
contains an entry for each virtual function with a function pointer that points to
// Point to favoriteCafe the most-derived function that is accessible to each class. Looking up which
businessPtr = &favoriteCafe; function to call makes runtime polymorphism slower than compile-time
polymorphism.
cout << businessPtr->GetDescription();
}
protected:
string name;
string address;
};
logic_error To report errors in a program's logic. Ex: out_of_range error (index out of bounds)
runtime_error To report errors that can only be detected at runtime. Ex: overflow_error (arithmetic overflow)
cout << "Current roster: " << endl; for (string playerName : teamRoster) {
cout << playerName << endl;
for (i = 0; i < teamRoster.size(); ++i) { }
playerName = teamRoster.at(i);
cout << playerName << endl;
}
Figure 15.1.2: Modifying a vector using a range-based for loop. Figure 15.1.3: Using a range-based for loop with auto to output a
#include <iostream> vector's elements.
#include <vector>
using namespace std; vector<double> examGrades = {45.7, 72.5, 53.2};
return 0;
}
Figure 15.1.5: Using a range-based for loop with auto to compute average and to modify and output a vector's elements.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<double> examGrades = {45.7, 72.3, 53.6}; // User's exam grades
double averageGrade;
return 0;
}
15.2 List
The list class defined within the C++ Standard Template Library (STL) defines a container of ordered elements, i.e., a sequence. The list class supports functions for
inserting, modifying, and removing elements.
The list type is an ADT implemented as a templated class that supports diZerent types of elements. A C++ list is implemented as a doubly-linked list. A list can be declared
and created as list<T> newList; where T represents the list's type, such as int or string. #include <list> enables use of a list within a program.
front()
// Assume list is: 6, 3, 1
front()
Returns element at the front of the list. exList.front(); // returns 6
back()
// Assume list is: 6, 3, 1
back()
Returns element at the back of the list. exList.back(); // returns 1
An iterator is an object that points to a location in a list and can be used to traverse the list bidirectionally.
15.3 Pair
The pair class
The pair class in the C++ Standard Template Library (STL) defines a container that consists of two data elements. #include <utility> enables use of the pair class. Many
STL container classes internally use or return pair objects. Ex: a map contains key-value pairs.
The pair type is an ADT implemented as a templated class (discussed elsewhere) that supports diZerent types values. A pair can be declared as pair<F, S> newPair; where
F represents the pair's first element type and S represents the pair's second element type. Ex: pair<int, string> newPair; declares a pair with an integer first element and a
string second element.
The make_pair() function creates a pair with the specified first and second values, with which a pair variable can be assigned. Each element in a pair can be accessed and
modified using the pair's first and second members.
Figure 15.3.1: Creating a pair and accessing the pair's elements.
#include <iostream>
#include <string>
#include <utility>
int main() {
pair<string, int> caPair;
// 2013 population data from census.gov Population of California in 2013 was 38332521.
caPair = make_pair("California", 38332521); Population of California in 2010 was 37253965.
cout << "Population of " << caPair.first << " in 2013 was "
<< caPair.second << "." << endl ;
cout << "Population of " << caPair.first << " in 2010 was "
<< caPair.second << "." << endl ;
return 0;
}
15.4 Map
Map container
A programmer may wish to lookup values or elements based on another value, such as looking up an employee's record based on an employee ID. The map class within
the C++ Standard Template Library (STL) defines a container that associates (or maps) keys to values. #include <map> enables use of a map.
The map type is an ADT implemented as a templated class (discussed elsewhere) that supports diZerent types of keys and values. Generically, a map can be declared
and created as map<K, V> newMap; where K represents the map's key type and V represents the map's value type.
The emplace() function associates a key with the specified value. If the key does not already exist, a new entry within the map is created. If the key already exists, the
associated map entry is not updated. Thus, a map associates at most one value for a key.
The at() function returns the value associated with a key, such as statePopulation.at("CA").
A map entry can be updated by assigning the entry with a new value. Ex: statePopulation.at("CA") = 39776830;
Table 15.4.1: Common map functions.
// map originally empty
emplace(key, value) exMap.emplace("Tom", 14);
emplace() Associates key with specified value. If key already exists, the map // map now: Tom->14,
entry is not changed. exMap.emplace("John", 86);
// Map now: Tom->14, John->86
[ ] operator
The map class' [ ] operator can be used to add map entries (Ex: exMap["Dan"] = 25;) and access map entries (Ex: exMap["Dan"];).
However, if a map does not contain the specified key, the [ ] operator creates a new entry in the map with the key and the default
value for the map's value type. Ex: If the key "Bob" does not exist in the map, myVal = exMap["Bob"]; creates a new map entry with
key "Bob" and value 0. When using the [ ] operator, if creating a map entry with a default value is not desired, a programmer should
first check that the key exists before accessing the map with that key. This material uses emplace() and at() to add and access map
entries, but the examples above can be modified to use the [ ] operator.
emplace()
Like many C++ containers, the map class has both an insert() function and an emplace() function to add new entries to a map. insert()
requires that an entry be explicitly constructed before insertion. emplace() does not have this requirement, and constructs entries
of the correct type upon insertion by automatically calling an appropriate constructor. This material uses emplace() for the map
class as an intuitive way of adding a pair entry to a map without explicitly constructing the pair beforehand.
15.5 Set
Set container
The set class defined within the C++ Standard Template Library (STL) defines a collection of unique elements. The set class supports functions for adding and removing
elements, as well as querying if a set contains an element. For example, a programmer may use a set to store employee names and use that set to determine which
customers are eligible for employee discounts.
The set type is an ADT implemented as a templated class that supports diZerent types of elements. A set can be declared as set<T> newSet; where T represents the set's
type, such as int or string. #include <set> enables use of a set within a program.
15.6 Queue
queue class
The queue class defined within the C++ Standard Template Library (STL) defines a container of ordered elements that supports element insertion at the tail and element
retrieval from the head.
The queue type is an ADT implemented as a templated class that supports diZerent types of elements. A queue can be declared as queue<T> newQueue; where T
represents the element's type, such as int or string. #include <queue> enables use of a queue within a program.
15.7 Deque
deque class
The deque (pronounced "deck") class defined within the C++ Standard Template Library (STL) defines a container of ordered elements that supports element insertion
and removal at both ends (i.e., at the head and tail of the deque).
A deque can be declared as deque<T> newDeque; where T represents the element's type, such as int or string. #include <deque> enables use of a deque within a
program.
deque's push_front() function adds an element at the head of the deque and increases the deque's size by one. The push_front() function shifts elements in the deque to
make room for the new element. deque's front() function returns the element at the head of the deque. And, deque's pop_front() function removes the element at the
head of the deque. If the deque is empty, front() results in undefined behavior.
The push_front(), front(), and pop_front() functions allow a deque to be used as a stack. A stack is an ADT in which elements are only added or removed from the top of a
stack
Table 15.7.1: Common deque functions.
push_front(newElement)
// Assume exDeque is: 3 5 6
push_front() exDeque.push_front(1);
Adds newElement element at the head of the deque. The deque's
// exDeque is now: 1 3 5 6
size increases by one.
push_back(newElement)
// Assume exDeque is: 3 5 6
push_back() exDeque.push_back(7);
Adds newElement element at the tail of the deque. The deque's
// exDeque is now: 3 5 6 7
size increases by one.
front()
// Assume exDeque is: 3 5 6
front() exDeque.front(); // Returns 3
Returns, but does not remove, the element at the head of the
// exDeque is still: 3 5 6
deque. If the deque is empty, the behavior is not defined.
back()
// Assume exDeque is: 3 5 6
back() exDeque.back(); // Returns 6
Returns, but does not remove, the element at the tail of the
// exDeque is still: 3 5 6
deque. If the deque is empty, the behavior is not defined.
Answer: Explanation:
<assign> ® <id> = <expr> • I switched the positions of + and * to make + have higher precedence, since the
<id> ® A | B | C lower the symbol on the parse tree the higher the precedence
<expr> ® <term> * <expr> • I switched <expr> to the right side of the * operator to make sure that we
| <term> recurse on the right-side. In doing so, we become right associative.
<term> ® <term> + <factor>
| <factor>
<factor> ® (<expr>)
| <id>
3. Show that the following set of grammar rule is ambiguous by demonstrating two different parse trees can be
generated for this statement: X * Y * Z
<stmt> → <term>
<term> → <term> * <term> | <id>
<id> → X | Y | Z
Answer:
For a grammar rule to be ambiguous there must be more than one way to parse a tree. Below you will see that if we
create the parse tree in both Left and Right associativity (recursion) we can prove that it is ambiguous.
Answer:
EBNF: Explanation:
<program> ® begin <stmt_list> end We use the curly braces to indicate repition of 0 or more
<stmt_list> ® <stmt> {( ; ) <stmt>} because <stmt_list> can be just <stmt> or it can recurse
<stmt> ® <var> = <expression> itself with right associativity and be <stmt>; <stmt_list>.
<var> ® A | B | C
<expression> ® <var> ( + | - ) <var> I used parenthesis for the last line because it has the
option of being + - or just one <var>.