Contents

Discussion material for EECS 402 posted below.

Know which discussion your looking for?

1 2 3 4 5 6 7 8 9 10 11


Unfortunately, anchor tags may be broken in some browsers


Discussion 1

Discussion 1 delves into primitive types and gives a basic review of C++ from elementary programming classes. Moreover, it will help you get setup on the University of Michigan server, basic Linux commands, and compiling C++ code on CAEN.


Discussion 2

Discussion 2 talks about more basic C++ concepts such as if statements and conditional flow, as well as loops. It reiterates things like connecting to the remote CAEN server at Michigan.


Discussion 3

Discussion 3 dives into arrays and GDB. Unfortunately, the lecture recording, where memory diagrams of arrays were drawn on the board and walk through examples for GDB, could not be posted. Example, walk through code is posted below.

#include <iostream>
using namespace std;

// Global Constants
const int ROWSIZE = 3;
const int COLSIZE = 5;

// function definitions
void timesTwo(int size, int arr[]);
void printArray2D(int arr[][colsize], const int rows);

// main
int main(){

  // declaring a 1d array
  int arr1D[5] = {1,2,3,4,5};

  // multiplying all the values by 2
  timesTwo(SIZE, arr1D);


  // initializing a 2d array size 3 by 5
  int arr2D[3][5];
  for(int i = 0; i < 3; ++i){
    for(int j = 0; j < 5; ++j){
       arr2D[i][j] = 5 * i + j;
    }
  }

  // print 2d array out
  printArray2d(arr2D);
  return 0;
}

void timesTwo(int size, int arr[]){
  for(int i = 1; i < size; ++i){
    arr[i] *= 2;
  }
}

void printArray2D(int arr[][]){
  for(int r = 0; r < ROWSIZE; ++r){
    for(int c = 0; c < COLSIZE; ++c){
       cout << arr[r][c] << " ";
     }
     cout << endl;
  }
}

Discussion 4

In Discussion 4 we delved into classes and walked through an example of classes. The starter code we wrote is below, and so is certain project related questions at the bottom of the .cpp file

#include <iostream>
using namespace std;

//Name: Faruk Kurtovic and Aneesh Rastogi
//Unique Name: kurtovic@umich.edu aneeshr@umich.edu
//project: Discussion4 example
//      this project attempts to create Object Oriented class
//      and building abstractions


//Global Constants
const int MIN_SEATS = 0; 
const int MAX_SEATS = 400; //biggest classroom - 400 seats (Stamps Auditorium)

const int BUILDING_FLOORS = 3;
const int ROOMS_PER_FLOOR = 10;
///

/// class declarations at top of file before main()
// ClassRoom object to represent a single classroom
class ClassRoom{
private:
    bool built; 
    int chairCount;
    bool inUse;
public:
    // default constructor -- 'built' attribute is false
    // but when this is called, a ClassRoom object is created in C++
    ClassRoom();

    // non default constructor
    ClassRoom(int numberOfChairs, bool beingUsed);

    // copy ctor
    ClassRoom(ClassRoom & otherRoom);

    // dont implement -- but think about it's usefulness later
    // bool setChairAndInUse(int numChairs, bool beingUsed);

    // returns true if this ClassRoom is already 'built'
    bool isBuilt();

    // gets the number of chairs 
    int getChairCount();

    // sets the amount of chairs in the room returns true if clipped
    bool setChairCount(int chairs);

    // increases the number of chairs by delta chairs returns true if clipped
    bool increaseChairs(int deltaChairs);

    // returns true if classroom is being used
    bool isBeingUsed();

    // returns true if its possible to start a lecture - false if already has lecture
    bool startLecture();

    // ends lecture if there is one - doesnt do anything if no lecture
    void endLecture();
};

//class declaration to represent entire building with floors and rooms
class Building{
private:
    // 2d array of classRooms
    ClassRoom rooms[BUILDING_FLOORS][ROOMS_PER_FLOOR];

    // number of rooms that exist
    int numBuiltRooms;

    // number of rooms that are used 
    int numRoomsUsed;

public:
    Building(); //a building starts with none of it's room as 'built'
    // ~Building();
    // Building(Building& otherBuilding); only if there's time at end <- copy constructor

    // prints out numRoomsUsed and numBuiltRooms
    void printStats();

    // Function returns the number of chairs within a certain room
    int getChairs(int floor, int roomNum);

    // Function sets the number of chairs within a room
    // Returns true if chairs need to be 'clipped'
    bool setChairs(int floor, int roomNum, int seats);

    // Functions fills chairs with 
    bool increaseChairs(int floor, int roomNum, int deltaChairs);

    // creates classRoom initializes values within a class from values --> ClassRoom now 'built'
    bool createClassRoom(int floor, int roomNumber, int chairs, bool inUse);

    // create classRoom intializes a new classroom from an existing class --> ClassRoom now 'built'
    bool createClassRoom(int floor, int roomNumber, ClassRoom & newClass);

    // empty values within class Room, return false if the classRoom is not built
    bool clearClassRoom(int floor, int roomNumber);

    // occupyClassroom fills up the room in the building, returns false if the classRoom is not built
    bool occupyClassRoom(int floor, int roomNumber);

    // ClassRoom& getClassRoom(int floor, int roomNumber); DONT DO, BUT THINK ABOUT IT --> why is it useful? why is it bad?
};

int main(){
    Building building;

    building.printStats();

    // fill building with empty rooms, with classes, of max chairs
    for(int i  = 0; i < BUILDING_FLOORS; ++i){
        for (int j = 0; j < ROOMS_PER_FLOOR; ++j) {
            building.createClassRoom(i, j, MAX_SEATS, true);
        }
    }

    building.printStats();

    // check to see if we can add 
    if(building.increaseChairs(0, 0, 1)){
        cout << "Success had to clip to increase chairs" << endl;
    }
    else {
        cout << "failure" << endl;
    }

    cout << building.getChairs(0,0) << endl;

    building.setChairs(0,0,0);

    cout << building.getChairs(0,0) << endl;


    cout << "finishing from main function" << endl;
    return 0;
}


// default class constructor -- it's not built
ClassRoom::ClassRoom(){
    inUse = false;
    numChairs = 0;
    built = false;


}

// non default constructor
ClassRoom::ClassRoom(int numberOfChairs, bool beingUsed){
    inUse = beingUsed;
    numChairs = numberOfChairs;
    built = false;
}

// copy ctor
ClassRoom::ClassRoom(ClassRoom & otherRoom){
    inUse = otherRoom.inUse;
    numChairs = otherRoom.numChairs;
    built = otherRoom.built;
    
}


//returns if classroom is built
bool ClassRoom::isBuilt(){
    return built;
}

// returns number of chairs
int ClassRoom::getChairCount(){
    return numChairs;
}

// sets the number of chairs in a classroom
// returns true if clipped
bool ClassRoom::setChairCount(int chairs)//returns true if seatCount is lower/greater than min/max -"clipping"
{

    // numChairs should be equal to chairs
    // but we have a limit on numChairs
    
    if (chairs <= MAX_SEATS && chairs >= MIN_SEATS){
        numChairs = chairs;
        return false;
    }
    else if(chairs > MAX_SEATS){
        chairs = MAX_SEATS;
        return true;
    }

    chairs = MIN_SEATS;
    return true;
}

// increase number of chairs by delta chairs
// returns true if clipped
bool ClassRoom::increaseChairs(int deltaChairs){
    newNumChairs = numChairs + deltaChairs;
    return setChairCount(newNumChairs);
} 

// returns true if classRoom is in use
bool ClassRoom::isBeingUsed(){
    
}

// returns if its possible to start a lecture
bool ClassRoom::startLecture(){

}

// ends lecture if running
void ClassRoom::endLecture(){
    
}


//class definition to represent entire building with floors and rooms
Building::Building(){   //a building starts with none of it's room as 'built'
    numBuiltRooms = 0;
    numRoomsUsed = 0;
}

// prints out values
void Building::printStats(){
    cout << numBuiltRooms << endl;
    cout << numRoomsUsed << endl;

}

// Building(Building& otherBuilding); only if there's time at end
int Building::getChairs(int floor, int roomNum){
    
    return rooms[floor][roomNum].getChairs();
    
}

// sets the chairs in a room
// returns true if clipped
bool Building::setChairs(int floor, int roomNum, int seats){
    
}

// increases the chairs in a room by a certain amount
// returns true if clipped
bool Building::increaseChairs(int floor, int roomNum, int deltaChairs){
    }

// if we can make a a room, make a room
// returns falls if not possible
bool Building::createClassRoom(int floor, int roomNumber, int chairs, bool inUse){

}

// returns true if we can createClassRooms
bool Building::createClassRoom(int floor, int roomNumber, ClassRoom & newClass){

}

// returns true if you can clearClass Room
// checks to see if room is valid
bool Building::clearClassRoom(int floor, int roomNumber){

}

// retursn true if room is occupied
// returns false otherwise
bool Building::occupyClassRoom(int floor, int roomNumber){

}
    // ClassRoom& getClassRoom(int floor, int roomNumber); DONT DO, BUT THINK ABOUT IT --> why is it useful? why is it bad?


//Project stuff:
/*
-   in the project, we have an object (class) RowColClass which stores a row and col used
    to index into an image (2D array) --> functions that need to access a pixel have
    a 'RowColClass' parameter passed in to know which pixel to use/update in the 2D array

-   bool ColorImageClass::setColorAtLocation(RowColumnClass &inRowCol,ColorClass &inColor)
    "the inRowCol parameter is passed by reference, but we dont need to change it-->
    why is it passed by reference?" 
    --> "efficiency"
    --> probably should be const RowColumnClass &inRowCol (BUT DO NOT CHANGE IT IN THE PROJCET)

*/





Discussion 5

This discussion delves into .h and .cpp files and how constructors and destructors run. Moreover, it talks about getters and setters in classes, as well as header gaurds, and strings in C++ and C. Sample Code is posted below to follow along:

Embed Block
Add an embed URL or code. Learn more
//////////////////////////////////////////////////////
////////////////// FIRSTGRADER.H /////////////////////
//////////////////////////////////////////////////////

// #include <iostream>

#ifndef FIRST_GRADER_H
#define FIRST_GRADER_H


class first_grader{
  private:
    int age;
public:
    //set private attribute 'age'
    void setAge(const int ageIn);
    //get age function -- doesnt modify data -> const function
    int getAge() const ;
    //default ctor -- necessary since at least one non-default ctor exists
    first_grader();
    //non-default ctor
    first_grader(int ageIn);
    //copy ctor
    first_grader(const first_grader &other);
    //destructor -- no necessary, but useful for examples
    ~first_grader();
};

#endif


//////////////////////////////////////////////////////
///////////////// FIRSTGRADER.CPP ////////////////////
//////////////////////////////////////////////////////

#include "first_grader.h"
#include <iostream>
using namespace std;
// #include <iostream>

first_grader::first_grader() {
  cout << "default ctor" << endl;
}

first_grader::first_grader(const int ageIn) {
  cout << "nondefault ctor" << endl;
  age = ageIn;
}

first_grader::first_grader(const first_grader &other) {
  cout << "copy ctor" << endl;
  //below is valid
  // age = otherFirstGrader.getAge();  
  age = other.age;
}
void first_grader::setAge(const int ageIn) {
  cout << "set age" << endl;
  age = ageIn;
}

int first_grader::getAge() const {
  cout << "get age" << endl;
  return age;
}

first_grader::~first_grader() {
  cout << "~ destructor ... age = " << age << endl;
    //nothing -- becomes more useful with dynamic memory
}


Discussion 6

In Discussion 6, I we talked about dynamic memory and how it differs from variables declared in the scope of a function. Moreover, we talked about using dynamic memory, pointers, and dynamic arrays.


Discussion 7

In Discussion 7 we covered basic Object Oriented Programming Design as well as we whiteboard coded how to solve two basic problems. Moreover, we talked about the use of dynamic arrays. Unfortunately, sample code cannot be posted.


Discussion 8

In Discussion 8, we talked about Linked Lists and Node classes. Moreover, we delved into some basic functions like insert and delete. A sample singly linked list starter code is implemented below in 4 different files:

////////////////
//// Node.h ////
////////////////
#ifndef _NODE_H_
#define _NODE_H_
using namespace std;

class Node{
    // private:
    public:
        char value;
        Node* next;


        
    // public:
    //     // Non-default Constructor
    //     Node(char val);
    //     // gets the next pointer
    //     Node* getNext();
    //     // sets the next pointer
    //     void setNext(Node* in);
    //     // gets the value of node
    //     char getVal();
    //     // sets the value of the node
    //     void setVal(char in);
};

#endif

////////////////
/// Node.cpp ///
////////////////

#include "Node.h"
using namespace std;

// Node::Node(char in){
 
// }

// Node* Node::getNext(){

// }

// char Node::getVal(){

// }

// void Node::setVal(char in){

// }

// void Node::setNext(Node* in){

// }


////////////////
//// List.h ////
////////////////
#ifndef _LIST_H_
#define _LIST_H_

#include "Node.h"
using namespace std;

class List{
    private:
        Node* head;
        Node* tail;
    public:
        List();
        // List(char val);

        //add node with val to end
        void insert(char val);
        void operator +=(char val);
        void changeVal(int index, char val);

        //print content of each node
        // ( value ) --> ( value ) --> ...
        void printList();

        void erase(int index);
        ~List();

         //advanced practice: do at home
        // void insert(int index, char val);
};

#endif

////////////////
/// List.cpp ///
////////////////
#include <iostream>
using namespace std;
#include "List.h"

//create empty list
List::List(){

}

//create list with one node containing val
// List::List(char val){
// }

//create node at end of LL, init to val
void List::insert(char val){

}

//create node at end of LL, init to val
void List::operator +=(char val){

}

//chand the val inside node at place 'index'
void List::changeVal(int index, char val){


}

//print the list
void List::printList(){
  
}

//erase the node at the 'index' spot
void List::erase(int index){
    
}

//free all the memory associated with this list
//clear up everythign on the heap
List::~List(){

}


Discussion 9

Quiz given on stacks and queues in discussion:  



            Assume a correctly implemented Stack, Queue, LinkedList
            Stack has the functionality:
                .push(int val) // pushes value into the stack
                .pop() // removes from top of stack
                .empty()    // returns true if stack is empty
                .top() //returns top of stack
            Queue has the functionality:
                .push(int val) // pushes value into the queue
                .pop() // removes from front of queue
                .empty() // returns true if the queue is empty
                .front() // returns front of queue
            LinkedList has the functionality:
            += operator() // adds to the *FRONT* of the list
                .insert(int val, int index) // adds a value at an index
                .erase(int index) // removes a value at an index
                .getHead() // returns value at head
                .getTail() // returns value at tail
            int main () {
                Stack A;
                for ( int i = 4 ; i > 0 ; i--) {
                    A.push(i);
                }
                while ( A.empty() == false ) {
                    cout<<A.top()<<endl;
                    A.pop();
                }
                Queue B;
                for ( int i = 4 ; i > 0 ; i-- ) {
                    B.push(i);
                }
                while ( B.empty() == false ) {
                    cout<< B.top()<<endl;
                    B.pop();
                }
                LinkedList C;
                for ( int i = 4; i > 0 ; i-- ) {
                    C += i; //NOTE: post fix operator
                }
                cout<<"Ends of C:"<<C.getHead()<<", "<<C.getTail()<<endl;
                C.insert(6, 0);
                cout<<"Ends of C"<<C.getHead()<<" "<<C.getTail()<<endl;
                C.insert(9, 4);
                cout<<"Ends of C"<< C.getHead()<<" "<<C.getTail()<<endl;
                while ( C.empty() == false ) {
                    cout<<C.getHead()<<endl;
                    C.erase(0);
                }
                return 0;
            }

In Discussion 9, we covered stacks, queues and the big three. Also, there was quiz given in class. Below is sample code for a Linked List:

/////////////////
/////List.h//////
/////////////////

#ifndef _LIST_H_
#define _LIST_H_

// Implemenatation of a Singly Linked-List


using namespace std;

class Node { //SHOULD BE IN SEPERATE FILE -- VIOLATION OF DESIGN
            // done for simplicity
    public:
        char value; //make private with get() and set()
        Node* next; //make private with get() and set()
};

class List{
    private:
        Node * firstNodePointer; //"head"
        Node * lastNodePointer; //"tail"
        int length;
    public:
        List();
  
        // add 'val' to end of list (THE FOLLOWING TWO ARE EQUIVALENT)
        void append(const char val);
        void operator +=(const char val);

        //change the ith value in the list : (0-based)
        bool changeVal(const int index, const char newval);

        //print content of entire list... each node (THE FOLLOWING TWO ARE EQUIVALENT)
        void printList();   // ( value ) --> ( value ) --> ...
        // ostream& operator<<(ostream & outputstream);  // ( value ) --> ( value ) --> ...

        bool erase(int index);  //remove ith node from link list

        ~List(); //"clean up" : destroy dynamic memory
};

#endif


/////////////////
////List.cpp/////
/////////////////

#include <iostream>
using namespace std;
#include "List.h"

// at any point, are list will look something like this:
//   O ---> O ---> O ---> O ---> (NOTHING ... address 0)
// where each O represents a node with a value, and "--->" represents that the next
// pointer of each node points to the "next" node in the chain (using next pointer)



List::List() {
    firstNodePointer = 0;   //set head & tail node * to point to address 0
    lastNodePointer = 0;
    length = 0; //list starts empty, length = 0
}



// add 'val' to end of list (THE FOLLOWING TWO ARE EQUIVALENT)
void List::append(const char val) {

    //create a new Node, dynamically
    Node * newNode = new Node;
    newNode -> value = val; //initialize
    newNode -> next = 0; // newNode added to end of list, points to nothing

    if (length == 0) { //list is empty: length == 0, tail = 0, head = 0
        firstNodePointer = newNode;
        lastNodePointer = newNode;
        length = 1;
    }

    else {  // length > 0:  head != 0 & tail != 0 .... there is at least one Node in the list
        lastNodePointer -> next = newNode;
        lastNodePointer = newNode;
        ++length;
    }
    //Question: does "newNode" go out of scope now?
    //          why is this good/bad?
}

//THIS CODE IS DUPLICATED FROM "append(val)"  --> in practice, make private method, call from both
void List::operator +=(const char val){

    //create a new Node, dynamically //IDEA: put next three lines in constructor for Node
    Node * newNode = new Node;
    newNode -> value = val; //initialize
    newNode -> next = 0; // newNode added to end of list, points to nothing

    if (length == 0) { //list is empty: length == 0, tail = 0, head = 0
        firstNodePointer = newNode;
        lastNodePointer = newNode;
        length = 1;
    }
    
    else {  // length > 0:  head != 0 & tail != 0 .... there is at least one Node in the list
        lastNodePointer -> next = newNode;
        lastNodePointer = newNode;
        ++length;
    }
    //Question: does "newNode" go out of scope now?
    //          why is this good/bad?

}

//change the ith value in the list : (0-based)
//returns true if value successfully changed to 'val'
bool List::changeVal(const int index, const char newval){

    // if ( index >= length ) {     //index beyond length of list
    //  return false;
    // }

    int idx = 0;
    bool changed = false;
    Node * iteratePointer = firstNodePointer;

    while ( idx < index && iteratePointer != 0 ) {
        iteratePointer = iteratePointer -> next; //move on to "next" node
        ++idx;  //keep track of how many nodes visited
    }

    if ( idx == index && iteratePointer != 0 ) {
        iteratePointer -> value = newval; //update value
        changed = true;
    }
    return changed;
}

//print content of entire list... each node (THE FOLLOWING TWO ARE EQUIVALENT)
void List::printList(){   // ( value ) --> ( value ) ---> ...
    Node * nPointer = firstNodePointer;

    if ( length == 0 ) {
        cout << " < empty list > " << endl;
        return;
    }

    while (nPointer != 0 ){

        cout << " ( " << nPointer -> value << " ) --->";

        nPointer = nPointer -> next;
    }
    cout << " 0 address" << endl;
}

// return true if succesfully delete, false otherwise
bool List::erase(int index) {  // remove ith node from link list

    // approach: 1) find the node right before (predecessor to) the node we want to delete
    //           2) make a tempPointer to the thing in front
    //           3) make predecessor -> next = the  "-> next " of what we want to delete
    //           4) delete tempPointer
    //
    // EDGE CASE: delete first node : index == 0

    if ( index >= length ) { // if "index" greater than index of last node
        return false;
    }

    if ( index == 0 ) { //deleting first thing in list

        Node * toDelete = firstNodePointer;

        if ( length == 1 ) { // there was only one node in the list --> now it's empty
            lastNodePointer = 0;
        }
        else {
            //do nothing
        }

        firstNodePointer = firstNodePointer -> next;
        delete toDelete;
        toDelete = 0;
        --length; //update number of nodes
        //CHECK YOUR UNDERSTANDING :    Why do we need "toDelete" ? 
        //                              Why not just delete firstNodePointer ?
    }

    else { //it's within the list somewhere
        Node * predecessor = firstNodePointer; //start at beginning
        int idx = 0;
        while ( idx < index - 1 ) {
            predecessor = predecessor -> next;
            ++idx;
        }

        Node * toDelete = predecessor -> next;

        if ( index == length - 1 ) { //if removing last node -- requires that length is always correct !
        //if ( predecessor -> next == lastNodePointer ) { //equivalent
            lastNodePointer = predecessor; //new tail is thing before old tail
            predecessor -> next = 0;
            //CHECK YOUR UNDERSTANDING:
            // What if we didn't check this ? What would happen ? What invariant is broken ?
        }
        else {
            predecessor -> next = toDelete -> next;
            toDelete -> next = 0;
        }

        delete toDelete;
        toDelete = 0;
        --length;
    }
    return true;
}
List::~List(){ //"clean up" : destroy dynamic memory

    Node * iter = firstNodePointer;

    while ( iter != 0 ) {
        Node * temp = iter;
        iter = iter -> next;

        temp -> next = 0;
        delete temp;
        temp = 0;
        --length;
    }
    firstNodePointer = lastNodePointer = 0;
}

Discussion 10

In Discussion 10, we delved into binary search trees and templating.


Discussion 11

In Discussion 11, we talk about the standard templated library and different data structures available. We also delve into functors used for custom sorting. More resources can be found @ cppreference