Pages

Wednesday, 16 May 2018

Chapter 9 // Drill 1, 2, 3, 4, 5 - Principles & Practice Using C++

n this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


EDIT 24/03/2021
Please note the code below is for historical purposes (it's quite wrong). Also, thanks to a comment below I noticed two issues in add_day and add_month. The changes can be found here:
I haven't changed the other drills. Also, as the drill says the check for a valid date can be very simple, I didn't check for invalid dates like certain months only having 30 days or 31. It basically acts as though every month is 31 days long.

EDIT 31/10/2019
My lord, what a mess these examples are. I have now updated these drills on my GitHub as I work my way through the book again. Even though I only did this a year ago, I can't believe how much my skills have improved (as well as my ability to use c style casts...I use them too much now). Seeing the whole bool last year, end year if not last year = ...eurgh.

Chapter 9 // Drill



This drill simply involves getting the sequence of versions of Date to work. For each version define a Date called today initialised to June 25, 1978. Then, define a Date called tomorrow and give is a value by copying today into it and increasing its day by one using add_day(). Finally output today and tomorrow using a << defined as in section 9.8.

Your check for a valid date may be very simple. Feel free to ignore leap years. However, don't accept a month that is not in the (1,12) range or day of the month that is not in the (1,31) range. Test each version with at least one invalid date (e.g., 2004, 13, -5).

Drill 1
The version from section 9.4.1:

#include "stdafx.h"
#include "std_lib_facilities.h"

//9.4.1 - simple Date
struct Date
{
 int y;  //year
 int m;  //month
 int d;  //day
};

Date today;
Date tomorrow;

//initialise the day
void init_day(Date& dd, int y, int m, int d)
{
 //check that y m d is a valid date
 if (y < 1900 || y > 2018)
  cout << "Error, invalid year." << endl;
 else if (m < 1 || m > 12)
  cout << "Error, invalid month." << endl;
 else if (d < 1 || d > 31)
  cout << "Error, invalid day." << endl;
 else
 {
  //if date is valid, initalise the date
  dd.y = y;
  dd.m = m;
  dd.d = d;
 }

 return;
}

//increment date by n days
void add_day(Date dd, Date& dd_copy, int n)
{
 bool lastDay = false;
 bool endYear = false;

 //if day go above 31, increase month, set day to 1
 //if month goes above 12, increase year, set month to 1
 for (int i = 0; i < n; ++i)
 {
  //wrap days
  if (dd.d == 31)
   lastDay = true;
  dd.d = (dd.d == 31) ? 1 : ++dd.d;

  if (lastDay)
  {
   //wrap month
   lastDay = false;
   dd.m = (dd.m == 12) ? 1 : ++dd.m;
   if (dd.m == 12)
    endYear = true;

   if (endYear)
   {
    //just increase year by one
    endYear = false;
    ++dd.y;
   }

  }
  
 }

 //assign tomorrow with copy of modified today
 dd_copy = dd;
}

//print to screen
ostream& operator<<(ostream& os, const Date& d)
{
 return os << d.d << ", " << d.m << ", " << d.y << endl;
}

int main()
{
 //initialise today with June 25 1978
 init_day(today, 1978, 6, 25);

 //assign by copying and increase by 1 day
 add_day(today, tomorrow, 1);

 //print out results
 cout << "Today: " << today << endl;
 cout << "Tomorrow: " << tomorrow << endl;

 keep_window_open();

 return 0;
}

The most challenging part of this was getting the days and months to wrap correctly. I know he only wanted us to increase by 1 day but I feel like he's going to ask us to do something similar at some point. The days only wrap at 31 though so it's not completely accurate however it does work as expected.

Drill 2

The version from section 9.4.2:


#include "stdafx.h"
#include "std_lib_facilities.h"

//9.4.2 - simple Date
//guarantee initialisation with constructor
//provide some notational convenience
struct Date
{
 int y, m, d;   //year, month, day
 Date(int y, int m, int d); //check for valid date and initialise
 void add_day(int n);  //increase the Date by N days
};

//intialise dates
Date today(1978, 6, 25);
Date tomorrow(today);

//Date Constructor - initialise the day
Date::Date(int y, int m, int d)
{
 //check that y m d is a valid date
 if (y < 1900 || y > 2018)
  cout << "Error, invalid year." << endl;
 else if (m < 1 || m > 12)
  cout << "Error, invalid month." << endl;
 else if (d < 1 || d > 31)
  cout << "Error, invalid day." << endl;
 else
 {
  //if date is valid, initalise the date
  Date::y = y;
  Date::m = m;
  Date::d = d;
 }

 return;
}

//increment date by n days
void Date::add_day(int n)
{
 bool lastDay = false;
 bool endYear = false;

 //if day goes above 31, increase month, set day to 1
 //if month goes above 12, increase year, set month to 1
 for (int i = 0; i < n; ++i)
 {
  //wrap days
  if (Date::d == 31)
   lastDay = true;
  Date::d = (Date::d == 31) ? 1 : ++Date::d;  //if day is equal to 31, make it 1, otherwise ++

  if (lastDay)
  {
   //wrap month
   lastDay = false;
   Date::m = (Date::m == 12) ? 1 : ++Date::m; //if month is equal to 12, make it 1, otherwise ++
   if (Date::m == 12)
    endYear = true;

   if (endYear)
   {
    //just increase year by one
    endYear = false;
    ++Date::y;
   }

  }
  
 }
}

//print to screen
ostream& operator<<(ostream& os, const Date& d)
{
 return os << d.d << ", " << d.m << ", " << d.y << endl;
}

int main()
{
 //increase day by one
 tomorrow.add_day(1);

 //print out results
 cout << "Today: " << today << endl;
 cout << "Tomorrow: " << tomorrow << endl;

 keep_window_open();

 return 0;
}
For this version, the two functions were changed a little to become part of the Date struct and used the global operator to assign straight to the variables in the struct instead of taking in variables. Tomorrow is also intialised with today and then increased in main() using the add_day() function.
Drill 3
The version from section 9.4.3:
#include "stdafx.h"
#include "std_lib_facilities.h"

#include "stdafx.h"
#include "std_lib_facilities.h"

//9.4.3 - simple Date (control access)
class Date
{
private:
 int y, m, d;
public:
 Date(int y, int m, int d);
 void add_day(int n);

 int month() { return m; }
 int day() { return d; }
 int year() { return y; }
};

//intialise dates
Date today(1978, 6, 25);
Date tomorrow(today);

//Date Constructor - initialise the day
Date::Date(int y, int m, int d)
{
 //check that y m d is a valid date
 if (y < 1900 || y > 2018)
  cout << "Error, invalid year." << endl;
 else if (m < 1 || m > 12)
  cout << "Error, invalid month." << endl;
 else if (d < 1 || d > 31)
  cout << "Error, invalid day." << endl;
 else
 {
  //if date is valid, initalise the date
  Date::y = y;
  Date::m = m;
  Date::d = d;
 }

 return;
}

//increment date by n days
void Date::add_day(int n)
{
 bool lastDay = false;
 bool endYear = false;

 //if day goes above 31, increase month, set day to 1
 //if month goes above 12, increase year, set month to 1
 for (int i = 0; i < n; ++i)
 {
  //wrap days
  if (Date::d == 31)
   lastDay = true;
  Date::d = (Date::d == 31) ? 1 : ++Date::d;  //if day is equal to 31, make it 1, otherwise ++

  if (lastDay)
  {
   //wrap month
   lastDay = false;
   Date::m = (Date::m == 12) ? 1 : ++Date::m; //if month is equal to 12, make it 1, otherwise ++
   if (Date::m == 12)
    endYear = true;

   if (endYear)
   {
    //just increase year by one
    endYear = false;
    ++Date::y;
   }

  }
  
 }
}

//print to screen
ostream& operator<<(ostream& os, Date& d)
{
 return os << d.day() << ", " << d.month() << ", " << d.year() << endl;
}

int main()
{
 //increase day by one
 tomorrow.add_day(1);

 //print out results
 cout << "Today: " << today << endl;
 cout << "Tomorrow: " << tomorrow << endl;

 keep_window_open();

 return 0;
}
Not much changed on this version, just the operator overload which could no longer access the variables within the class directly. It had to be changed to non-const though as it kept returning an error which I found strange considering I wasn't trying to change anything; just print it to the screen.

Drill 4
The version from section 9.7.1:
#include "stdafx.h"
#include "std_lib_facilities.h"

enum class Month
{
 jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};

//forward declaration
Month returnMonth(int month);

//9.4.3 - simple Date (use Month type)
class Date
{
public:
 Date(int y, Month m, int d);
 void add_day(int n);
 int year() { return y; }
 Month month() { return m; }
 int day() { return d; }
private:
 int y;
 Month m;
 int d;
};

//intialise dates
Date today(1978, Month::jun, 25);
Date tomorrow(today);

//Date Constructor - initialise the day
Date::Date(int y, Month m, int d)
{
 //check that y m d is a valid date
 if (y < 1900 || y > 2018)
  cout << "Error, invalid year." << endl;
 else if (static_cast<int>(m) < 1 || static_cast<int>(m) > 12)
  cout << "Error, invalid month." << endl;
 else if (d < 1 || d > 31)
  cout << "Error, invalid day." << endl;
 else
 {
  //if date is valid, initalise the date
  Date::y = y;
  Date::m = m;
  Date::d = d;
 }

 return;
}

//increment date by n days
void Date::add_day(int n)
{
 bool lastDay = false;
 bool endYear = false;

 //if day goes above 31, increase month, set day to 1
 //if month goes above 12, increase year, set month to 1
 for (int i = 0; i < n; ++i)
 {
  //wrap days
  if (Date::d == 31)
   lastDay = true;
  Date::d = (Date::d == 31) ? 1 : ++Date::d;  //if day is equal to 31, make it 1, otherwise ++

  if (lastDay)
  {
   //wrap month
   lastDay = false;
   int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1); //if month is equal to 12, make it 1, otherwise ++
   Date::m = returnMonth(mon);
   if (static_cast<int>(Date::m) == 12)
    endYear = true;

   if (endYear)
   {
    //just increase year by one
    endYear = false;
    ++Date::y;
   }

  }
  
 }
}

//switch to return correct type of Month
Month returnMonth(int month)
{
 switch (month)
 {
 case 1:
  return Month::jan;
  break;
 case 2:
  return Month::feb;
  break;
 case 3:
  return Month::mar;
  break;
 case 4:
  return Month::apr;
  break;
 case 5:
  return Month::may;
  break;
 case 6:
  return Month::jun;
  break;
 case 7:
  return Month::jul;
  break;
 case 8:
  return Month::aug;
  break;
 case 9:
  return Month::sep;
  break;
 case 10:
  return Month::oct;
  break;
 case 11:
  return Month::nov;
  break;
 case 12:
  return Month::dec;
  break;
 default:
  cout << "Bad month" << endl;
 }
}

//print to screen
ostream& operator<<(ostream& os, Date& d)
{
 return os << d.day() << ", " << static_cast<int>(d.month()) << ", " << d.year() << endl;
}

int main()
{
 //increase day by one
 tomorrow.add_day(10);

 //print out results
 cout << "Today: " << today << endl;
 cout << "Tomorrow: " << tomorrow << endl;

 keep_window_open();

 return 0;
}
There is actually 2 versions of Date in this section and he doesn't specify which one to use so however the second one includes a second class inside of it called Invalid{} which he hasn't hinted at anywhere so I went with the first. I'm guessing it was an error check but why not just make it a function? The fact that it was a class denotes a few functions in there so I'm not going to guess what they may be.

Anyway, because of enums being special I had to create a quick function which could assign the correct month in the add_day() function as you can't assign an integer to an enum. Well, you can, but some very strange things happen and even then the enum doesn't know what that integer means. For example say we wanted to assign June to our month variable, you can't just "=6" as the enum doesn't know that 6 is June. So the function uses a switch statement to compare the enum against an integer and then return the correct value.


Drill 5
The version from section 9.7.4:
#include "stdafx.h"
#include "std_lib_facilities.h"

enum class Month
{
 jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec
};

//forward declaration
Month returnMonth(int month);

//9.4.3 - simple Date (use Month type)
class Date
{
public:
 Date(int y, Month m, int d);
 int day() const { return d; };  //const member: can't modify
 Month month() const { return m; }
 int year() const { return y; }

 void add_day(int n);
 void add_month(int n);
 void add_year(int n);

 bool lastDay = false;
 bool endYear = false;
private:
 int y;
 Month m;
 int d;
};

//intialise dates
Date today(1978, Month::jun, 25);
Date tomorrow(today);

//Date Constructor - initialise the day
Date::Date(int y, Month m, int d)
{
 //check that y m d is a valid date
 if (y < 1900 || y > 2018)
  cout << "Error, invalid year." << endl;
 else if (static_cast<int>(m) < 1 || static_cast<int>(m) > 12)
  cout << "Error, invalid month." << endl;
 else if (d < 1 || d > 31)
  cout << "Error, invalid day." << endl;
 else
 {
  //if date is valid, initalise the date
  Date::y = y;
  Date::m = m;
  Date::d = d;
 }

 return;
}

//increment date by n days
void Date::add_day(int n)
{
 //if day goes above 31, increase month, set day to 1
 //if month goes above 12, increase year, set month to 1
 for (int i = 0; i < n; ++i)
 {
  //wrap days
  if (Date::d == 31)
   lastDay = true;
  Date::d = (Date::d == 31) ? 1 : ++Date::d;  //if day is equal to 31, make it 1, otherwise ++

  if (lastDay)
  {
   //wrap month
   lastDay = false;
   int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1); //if month is equal to 12, make it 1, otherwise ++
   Date::m = returnMonth(mon);
   if (static_cast<int>(Date::m) == 12)
    endYear = true;

   if (endYear)
   {
    //just increase year by one
    endYear = false;
    ++Date::y;
   }

  }
  
 }
}

void Date::add_month(int n)
{
 for (int i = 0; i < n; ++i)
 {
  //if month is equal to 12, make it 1, otherwise ++
  int mon = (static_cast<int>(Date::m) == 12) ? 1 : (static_cast<int>(Date::m) + 1);
  Date::m = returnMonth(mon);
  if (static_cast<int>(Date::m) == 12)
   endYear = true;

  if (endYear)
  {
   //just increase year by one
   endYear = false;
   ++Date::y;
  }
 }
}

void Date::add_year(int n)
{
 for (int i = 0; i < n; ++i)
  ++Date::y;
}

//switch to return correct type of Month
Month returnMonth(int month)
{
 switch (month)
 {
 case 1:
  return Month::jan;
  break;
 case 2:
  return Month::feb;
  break;
 case 3:
  return Month::mar;
  break;
 case 4:
  return Month::apr;
  break;
 case 5:
  return Month::may;
  break;
 case 6:
  return Month::jun;
  break;
 case 7:
  return Month::jul;
  break;
 case 8:
  return Month::aug;
  break;
 case 9:
  return Month::sep;
  break;
 case 10:
  return Month::oct;
  break;
 case 11:
  return Month::nov;
  break;
 case 12:
  return Month::dec;
  break;
 default:
  cout << "Bad month" << endl;
 }
}

//print to screen
ostream& operator<<(ostream& os, Date& d)
{
 return os << d.day() << ", " << static_cast<int>(d.month()) << ", " << d.year() << endl;
}

int main()
{
 //increase day by one
 tomorrow.add_day(1);
 tomorrow.add_month(2);
 tomorrow.add_year(5);

 //print out results
 cout << "Today: " << today << endl;
 cout << "Tomorrow: " << tomorrow << endl;

 keep_window_open();

 return 0;
}

For this one I just separated parts of add_day() into their own functions with a few tweaks.

Sunday, 13 May 2018

Chapter 8 // Exercise 14 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 8 // Exercise 14



14. Can we declare a non-reference function argument const (e.g., void f(const int);)? What might that mean? Why might we want to do that? Why don't people do that often? Try it; write a couple of small programs to see what works.


#include "stdafx.h"
#include "std_lib_facilities.h"

void f(const int);

int main()
{
 int n1 = 1;
 const int n2 = 2;

 f(n1);
 f(n2);
 f(3);

 keep_window_open();

 return 0;
}

void f(const int i)
{
 cout << i << endl;
}

You can declare a non-reference argument const. As you cannot change the value it is only really useful for printing to the screen or extracting data for other calculations. 

And thus concludes Chapter 8. When I first read this chapter almost a year and a half ago now, I honestly couldn't wrap my head around pointers and pass-by-value/reference. I just thought I wasn't going to get it. Then I had to build engines using DirectX9 and DirectX11 and everything is a pointer. The more time I spend programming the more comfortable I feel using more advanced concepts. However, going back to the basics is useful as there are many things in this chapter I've implemented in my code. I kept passing the d3d device by reference between classes, that's now a pointer instead. The next chapter is about classes which I needed as I feel like I needed to seriously brush up.

Wednesday, 9 May 2018

Chapter 8 // Exercise 13 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 8 // Exercise 13



13. Write a function that takes a vector<string> argument and returns a vector<int> containing the number of characters in each string. Also find the longest and the shortest string and the lexicographically first and last string. How many separate functions would you use for these tasks? Why?


#include "stdafx.h"
#include "std_lib_facilities.h"

void print(const vector<int>& vInt, const vector<string>& vStr1, const vector<string>& vStr2)
{
 cout << "Chars in each string: ";
 for (int i = 0; i < vInt.size(); ++i)
  cout << vInt[i] << " ";

 cout << "\n\nLongest String: " << vStr1[0] << endl;
 cout << "\nSmallest String: " << vStr1[1] << endl;

 cout << "\nAlphabetically First Word: " << vStr2[0] << endl;
 cout << "\nAlphabetically Last Word: " << vStr2[1] << '\n' << endl;
}

//number of characters in each string
vector<int> findNumChars(const vector<string>& v)
{
 vector<int> numChar;

 for (int i = 0; i < v.size(); ++i)
 {
  //push back size of each string
  numChar.push_back(v[i].size());
 }

 return numChar;
}

//find longest&shortest string in vector
vector<string> findMinMax(const vector<string>& v)
{
 vector<string> minMax;

 int largest = v[0].size();
 int smallest = v[0].size();
 int iterator1 = 0;
 int iterator2 = 0;  //to pushback correct items from vector

 for (int i = 0; i < v.size(); ++i)
 {
  //if largest is smaller than value, make that new largest
  if (largest < v[i].size())
  {
   largest = v[i].size();
   iterator1 = i;
  }

  //if smallest is bigger than value, make that new smallest
  if (smallest > v[i].size())
  {
   smallest = v[i].size();
   iterator2 = i;
  }
 }

 minMax.push_back(v[iterator1]); //push back largest string
 minMax.push_back(v[iterator2]); //push back smallest string

 return minMax;
}

//find alphabetically first and last string
vector<string> findAlphaB(vector<string> v_copy)
{
 vector<string> alpha;

 //sort the copy to be in alphabetical order
 sort(v_copy.begin(), v_copy.end());

 alpha.push_back(v_copy[0]);
 alpha.push_back(v_copy[v_copy.size() - 1]);

 return alpha;
}

int main()
{
 vector<string> words = { "keyboard", "cat", "nyan", "cat", "tank", "cat", "hipster", "kitty", "grumpy", "cat" };

 //find number of character in each string
 vector<int> numChar = findNumChars(words);

 //find largest and shortest strings
 vector<string> minMax = findMinMax(words);

 //find alphabetically first and last string
 vector<string> alphaB = findAlphaB(words);

 //print results
 print(numChar, minMax, alphaB);

 keep_window_open();

 return 0;
}

You could do separate functions for every task, for example, a function that only finds the longest string and a function that only finds the shortest string however, to save on code and efficiency, I decided to return these values as vectors. That way we know that the vectors (apart from number of chars in a string) will only ever have 2 values in them; the largest followed by the smallest and the first alphabetical word followed by the last. There should technically be separate print functions however we know exactly what the size of 2 vectors will be, so I consider it OK to directly access the items in them.

Saturday, 5 May 2018

Chapter 8 // Exercise 12 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 8 // Exercise 12



12. Improve print_until_s() from section 8.5.2. Test it. What makes a good set of test cases? Give reasons. Then, write a print_until_ss() that prints until it sees a second occurrence of its quit argument.


#include "stdafx.h"
#include "std_lib_facilities.h"

void print_until_s(const vector<string> &v, string quit)
{
 //for every 's' in 'v'
 for (string s : v)
 {
  if (s == quit)
   return;

  cout << s << " ";
 }
}

int main()
{
 vector<string> words = { "this", "is", "the", "ultimate", "showdown", "of", "ultimate", "destiny",
 "good", "guys", "bad", "guys", "and", "explosions", "as", "far", "as", "the", "eye", "can", "see" };

 print_until_s(words, "and");

 cout << '\n' << endl;

 keep_window_open();

 return 0;
}


I made the vector a const pointer as we aren't modifying any values and generally formatted it to a style that I prefer (it really annoys me when the bracket starts on the same line as the argument). As for testing, this works quite well but stops at the first instance of the word, which is a given. It also prints the entire vector if no quit word is found.


#include "stdafx.h"
#include "std_lib_facilities.h"

void print_until_ss(const vector<string> &v, string quit)
{
 int quitFound = 0;

 //for every 's' in 'v'
 for (string s : v)
 {
  if (s == quit)
   ++quitFound;
  else if (quitFound == 2)
   return;

  cout << s << " ";
 }
}

int main()
{
 vector<string> words = { "this", "is", "the", "ultimate", "showdown", "of", "ultimate", "destiny",
 "good", "guys", "bad", "guys", "and", "explosions", "as", "far", "as", "the", "eye", "can", "see" };

 print_until_ss(words, "ultimate");

 cout << '\n' << endl;

 keep_window_open();

 return 0;
}

Wednesday, 2 May 2018

Chapter 8 // Exercise 11 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 8 // Exercise 11



11. Write a function that finds the smallest and the largest element of a vector argument and also computes the mean and median. Do not use global variables. Either return a struct containing the results or pass them back through reference arguments. Which of the two ways of returning several result values do you prefer and why?

#include "stdafx.h"
#include "std_lib_facilities.h"

struct stats
{
 double smallest;
 double largest;
 double mean;
 double median;
};

//print vectors to the screen
void print(const vector<double>& price)
{
 for (int i = 0; i < price.size(); ++i)
 {
  cout << price[i] << endl;
 }

 cout << "--------------------------------" << endl;
}

//print struct
void print(const stats& s)
{
 cout << "Largest: " << s.largest << endl;
 cout << "Smallest: " << s.smallest << endl;
 cout << "Mean: " << s.mean << endl;
 cout << "Median: " << s.median << endl;
}

stats findVectorStats(const vector<double>& v, vector<double> v_copy, stats& stat)
{ 
 //initialise values
 stat.largest = v[0];
 stat.smallest = v[0];
 stat.mean = v[0];
 stat.median = v[0];
 
 //if vector only has 1 value return that
 if (v.size() == 1)
  return stat;

 for (int i = 0; i < v.size(); ++i)
 {
  //if next value is bigger than last, make that new largest
  if (stat.largest < v[i])
   stat.largest = v[i];
  //if next value is smaller than last, make than new min
  else if (stat.smallest > v[i])
   stat.smallest = v[i];

  //add numbers together for mean calculation
  stat.mean += v[i];
 }

 //find mean
 stat.mean = stat.mean / v.size();

 //find median by sorting to find middle number
 sort(v_copy.begin(), v_copy.end()); //put in ascending order

 //if vector has odd number of items
 if (v_copy.size() % 2 != 0)
 {
  stat.median = v_copy[(v_copy.size() / 2)];
 }
 //if vector has even number of items
 else
 {
  stat.median = (v_copy[v_copy.size() / 2 - 1] + v_copy[v_copy.size() / 2]) / 2;
 }

 //return struct
 return stat;
}

int main()
{
 vector<double> numbers = { 1, -9, 2, 3, 3, 3, 1500 };

 stats findStats;
 
 findVectorStats(numbers, numbers, findStats);

 print(findStats);

 keep_window_open();

 return 0;
}


I really wanted to separate all the different operations into their own functions however Bjarne said to create just one. I also decided to return a struct of all the values to save having four separate variables in main().