Showing posts with label chapter 8. Show all posts
Showing posts with label chapter 8. Show all posts

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().

Saturday, 28 April 2018

Chapter 8 // Exercise 10 - 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 10



10. Write a function maxv() that returns the largest element of a vector argument.


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

double maxv(const vector<double>& v)
{
 //if vector only has 1 value return that
 if (v.size() == 1)
  return v[0];

 //make first value in vector max value
 double largest = v[0];

 //go through every value, if the next value is bigger
 //than the last, make that the new max value
 for (int i = 0; i < v.size(); ++i)
 {
  if (largest < v[i])
   largest = v[i];
 }

 return largest;
}

int main()
{
 vector<double> numbers = { 1000, 6, -12, 700, 56, 89, -900, 1 };

 double max = maxv(numbers);

 cout << max << endl;

 keep_window_open();

 return 0;
}

At first I tried to use the max_element() function however it didn't seem to like working with vectors, so I used the template code to draft this function. It was a lot simpler than I initially thought. Since Bjarne didn't specify a data type I went with double however you can easily change the data type yourself.

Wednesday, 25 April 2018

Chapter 8 // Exercise 9 - 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 9



9. Write a function that given two vector<double>s price and weight computes a value (an "index") that is the sum of all price[i]*weight[i]. Make sure to have weight.size()==price.size().


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

//read numbers into weight
vector<double> getAmount(string label)
{
 vector<double> v_amount;
 int howMany;
 double amount;

 cout << "How many items are there for " << label << ": ";
 cin >> howMany;
 for (int i = 0; i < howMany; ++i)
 {
  cout << ">>";
  cin >> amount;
  v_amount.push_back(amount);
  cout << endl;
 }
 
 return v_amount;
}

//multiply weight by price if vectors are same size
double getSum(const vector<double>& price, const vector<double>& weight)
{
 double sum = 0;

 if (price.size() == weight.size())
 {
  for (int i = 0; i < price.size(); ++i)
  {
   sum += price[i] * weight[i];
  }
 }
 else
  cout << "Sorry those vectors are not the same size.\n";

 cout << "\nSum: " << sum << endl;

 return sum;
}


int main()
{
 vector<double> weight = getAmount("weight");
 vector<double> price = getAmount("price");

 double sum = getSum(price, weight);

 keep_window_open();

 return 0;
}

Saturday, 21 April 2018

Chapter 8 // Exercise 7, 8 - 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 7



7. Read five names into a vector<string> name, then prompt the user for the ages of the people names and store the ages in a vector<double> age. Then print out the five (name[i],age[i]) pairs. Sort the names (sort(name.begin(), name.end())) and print out the (name[i], age[i]) pairs. The tricky part here is to get the age vector in the correct order to match the sorted name vector. Hint: Before sorting name, take a copy and use that to make a copy of age in the right order after sorting name.


#include "stdafx.h"
#include "std_lib_facilities.h"
//print vectors to the screen
void print(const vector<double>& ages, const vector<string>& names)
{
 for (int i = 0; i < ages.size(); ++i)
 {
  cout << names[i] << ": " << ages[i] << endl;
 }

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

//read five names into a vector string
vector<string> getNames(vector<string>& v)
{
 string name;

 for (int i = 0; i < 5; ++i)
 {
  cout << "Name Please: ";
  cin >> name;
  v.push_back(name);
  cout << endl;
 }

 return v;
}

//read 5 ages for names
vector<double> getAges(const vector<string>& name, vector<double>& v_age)
{
 double age;

 for (int i = 0; i < name.size(); ++i)
 {
  cout << "Age for " << name[i] << ": ";
  cin >> age;
  v_age.push_back(age);
  cout << endl;
 }

 return v_age;
}

//compare copy of name vector to new to sort ages correctly
void sortNames(vector<string> name_copy, vector<string>& name, vector<double> age_copy, vector<double>& age)
{
 sort(name.begin(), name.end());  //sort actual names

 //go through each member of sorted name
 for (int i = 0; i < name.size(); ++i)
 {
  //go through each member of original copy name
  for (int j = 0; j < name.size(); ++j)
  {
   //if sorted name matches original
   if (name[i] == name_copy[j])
   {
    //assign original age to new position to match sorted vector
    age[i] = age_copy[j];
   }
  }
 }
}


int main()
{
 //get names
 vector<string> names;
 getNames(names);

 //get ages
 vector<double> ages;
 getAges(names, ages);

 //print original vectors
 print(ages, names);

 //sort the vectors using copies to compare
 sortNames(names, names, ages, ages);

 //print vectors again to see changes
 print(ages, names);

 keep_window_open();

 return 0;
}


Chapter 8 // Exercise 8


8. Then, do that exercise again but allowing an arbitrary number of names.

The only part of this I changed was the function to get the names:

//read five names into a vector string
vector<string> getNames(vector<string>& v)
{
 string name;

 cout << "Press 'q' to stop entering names" << endl;

 while(name != "q")
 {
  cout << "Name Please: ";
  cin >> name;
  if (name == "q")
   break;
  v.push_back(name);
  cout << endl;
 }

 return v;
}

Wednesday, 18 April 2018

Chapter 8 // Exercise 5, 6 - 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 5



5. Write two functions that reverse he order of elements in a vector<int>. For example 1,3,5,7,9 becomes 9,7,5,3,1. The first reverse function should produce a new vector with the reversed sequence, leaving its original vector unchanged. The other reverse function should reverse the elements of its vector without using any other vectors (hint: swap).


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

//prints a given vector to the screen with a label
void print(string& label, const vector<int>& v)
{
 cout << label << ": " << endl;

 for (int i = 0; i < v.size(); ++i)
 {
  //if incrementor is divisible by 10, start a new line to print
  cout << v[i] << '\t';
  if (i % 10 == 0 && i != 0)
   cout << '\n';
 }

 cout << '\n';
}

//calculates fibonnaci sequence for a given amount of numbers
void fibonnaci(int first, int second, vector<int>& v, int howMany)
{
 //is vector empty?
 if (v.size() == 0)
 {
  v.push_back(first);
  v.push_back(second);

  int temp;

  //pushback numbers from sequence depending on how many we want
  //start with 3rd number
  for (int i = 1; i < howMany; ++i)
  {
   temp = v[i] + v[i - 1];
   v.push_back(temp);
  }
 }
 else
  cout << "Sorry that vector is not empty.\n";
}

//swap vectors elements creating new vector leaving original unchanged
vector<int> swap1(const vector<int>& originalV)
{
 vector<int> newV;
 for (int i = originalV.size() - 1; i >= 0; --i)
 {
  newV.push_back(originalV[i]);
 }

 return newV;
}

//swap vectors elements using swap
void swap2(vector<int>& originalV)
{
 for (int i = 0; i < originalV.size()/2; ++i)
 {
  swap(originalV[i], originalV[originalV.size() - (i + 1)]);
 }
}

int main()
{
 vector<int> fibonacciNumbers;
 vector<int> newFibonacci;

 //populate vector with sequence
 fibonnaci(1, 2, fibonacciNumbers, 10);

 //swap creating a copy and assigning to new vector
 newFibonacci = swap1(fibonacciNumbers); 

 //print the vectors
 string label = "Fibonacci Numbers";
 print(label, fibonacciNumbers);
 label = "New Fibonacci";
 print(label, newFibonacci);

 //print the original vector
 label = "Fibonacci Numbers";
 print(label, fibonacciNumbers);

 //swap using swap function and no other vectors
 swap2(fibonacciNumbers);

 //print the original vector which has now been modified
 label = "Swapped Fibonocci Numbers";
 print(label, fibonacciNumbers);

 keep_window_open();

 return 0;
}

For this exercise I decided to build upon the previous ones instead of writing numbers to pushback into random vectors. The first swap, swap1() works by taking a const reference to the original vector (so it doesn't change it) and applies those values to a new vector. The for loop starts at the end of the original vector and pushes back a number into the new one until it gets to the first value. It then returns the new vector as value.

Chapter 8 // Exercise 


6. Write versions of the functions from exercise 5, but with a vector<string>.


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

//prints a given string vector to the screen with a label
void print(string& label, const vector<string>& v)
{
 cout << label << ": " << endl;

 for (int i = 0; i < v.size(); ++i)
 {
  //if incrementor is divisible by 10, start a new line to print
  cout << v[i] << '\t';
  if (i % 10 == 0 && i != 0)
   cout << '\n';
 }

 cout << '\n';
}

//swap string vectors using another vector
vector<string> swapString1(const vector<string>& originalV)
{
 vector<string> newV;
 for (int i = originalV.size() - 1; i >= 0; --i)
 {
  newV.push_back(originalV[i]);
 }

 return newV;
}

void swapString2(vector<string>& originalV)
{
 for (int i = 0; i < originalV.size() / 2; ++i)
 {
  swap(originalV[i], originalV[originalV.size() - (i + 1)]);
 }
}

int main()
{
 vector<string> myString = { "hello", "world", "this", "is", "a", "blog", "post" };
 vector<string> newString;

 //swap creating a copy
 newString = swapString1(myString);

 //print the vectors
 string label = "My String";
 print(label, myString);
 label = "New String";
 print(label, newString);

 //swap without creating a copy
 label = "My String";
 print(label, myString);

 swapString2(myString);

 label = "My String";
 print(label, myString);

 keep_window_open();

 return 0;
}

Sunday, 15 April 2018

Chapter 8 // Exercise 3, 4 - 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 3



3. Create a vector of Fibonacci numbers and print them using the function from exercise 2. To create the vector, write a function, fibonacci(x,y,v,n), where integers x and y are ints, v is an empty vector<int>, and n is the number of elements to put into v; v[0] will be x and v[1] will be y. A Fibonacci number is one that is part of a sequence where each element is the sum of the previous ones. For example, starting with 1 and 2, we get 1,2,3,4,8,13,21,....Your fibonacci() function should make such a sequence starting with its x and y arguments.

For this one I changed the name of few things to make them more descriptive. I also decided to not make the ints references and instead allow the user to pass numbers directly as arguments. The vector is just passed by reference in fibonacci() due to the need to modify it.

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

//prints a given vector to the screen with a label
void print(string& label, const vector<int>& v)
{
 cout << label << ": " << endl;

 for (int i = 0; i < v.size(); ++i)
  cout << v[i] << endl;

 cout << '\n';
}

//calculates fibonnaci sequence for a given amount of numbers
void fibonnaci(int first, int second, vector<int>& v, int howMany)
{
 //is vector empty?
 if (v.size() == 0)
 {
  v.push_back(first);
  v.push_back(second);

  int temp;

  //pushback numbers from sequence depending on how many we want
  //start with 3rd number
  for (int i = 1; i < howMany; ++i)
  {
   temp = v[i] + v[i - 1];
   v.push_back(temp);
  }
 }
 else
  cout << "Sorry that vector is not empty.\n";
}

int main()
{
 vector<int> fibonacciNumbers;

 //populate vector with sequence
 fibonnaci(1, 2, fibonacciNumbers, 10);

 //print the vector
 string label = "Fibonacci Numbers";
 print(label, fibonacciNumbers);

 keep_window_open();

 return 0;
}

Chapter 8 // Exercise 4
4. An int can hold integers only up to a maximum number. Find approximation of that maximum number by using fibonacci().
#include "stdafx.h"
#include "std_lib_facilities.h"

//prints a given vector to the screen with a label
void print(string& label, const vector<int>& v)
{
 cout << label << ": " << endl;

 for (int i = 0; i < v.size(); ++i)
 {
  //if incrementor is divisible by 10, start a new line to print
  cout << v[i] << '\t';
  if (i % 10 == 0 && i != 0)
   cout << '\n';
 }

 cout << '\n';
}

//calculates fibonnaci sequence for a given amount of numbers
void fibonnaci(int first, int second, vector<int>& v, int howMany)
{
 //is vector empty?
 if (v.size() == 0)
 {
  v.push_back(first);
  v.push_back(second);

  int temp;

  //pushback numbers from sequence depending on how many we want
  //start with 3rd number
  for (int i = 1; i < howMany; ++i)
  {
   temp = v[i] + v[i - 1];
   v.push_back(temp);
  }
 }
 else
  cout << "Sorry that vector is not empty.\n";
}

int main()
{
 vector<int> fibonacciNumbers;

 //populate vector with sequence
 fibonnaci(1, 2, fibonacciNumbers, 10);

 //print the vector
 string label = "Fibonacci Numbers";
 print(label, fibonacciNumbers);

 //after printing 100 numbers this is highest number it can go to
 int number = 1836311903;
 cout << '\n' << number;

 keep_window_open();

 return 0;
}
Here I added a couple of lines in print to print numbers in rows of 10. When told to find 100 numbers the number before everything goes weird is 1836311903. 

Wednesday, 11 April 2018

Chapter 8 // Exercise 2 - 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 2



2. Write a function print() that prints a vector of ints to cout. Give it two arguments: a string for 'labeling' the output and a vector.

Not quite sure what he means when he wants us to 'label' the output. Does he mean a note that says "these numbers are from this vector"? That's how I've interpreted it anyway. For the print() function we pass a string reference to avoid copying data and since we are just printing the contents of a vector there is no need to modify it so it is passed via const reference. For this exercise I added a little in main just to show the function working.

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

//prints a given vector to the screen with a label
void print(string& label, const vector<int>& v)
{
 cout << label << ": " << endl;

 for (int i = 0; i < v.size(); ++i)
  cout << v[i] << endl;

 cout << '\n';
}

int main()
{
 vector<int> numberVector = { 1,2,3,4,5,6,7,8,9,10 };
 string label = "Vector of Numbers";

 print(label, numberVector);

 keep_window_open();

 return 0;
}

Sunday, 8 April 2018

Chapter 8 // Exercise 1 - 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 1



1. Modify the calculator program from Chapter 7 to make the input stream an explicit parameter (as shown in section 8.5.8), rather than simple using cin. Also give the Token_stream constructor (section 7.8.2) an istream& parameter so that when we figure out how to make out own istream (e.g., attached to files), we can use the calculator for those. Hint: Don't try to copy an istream.

// pandp.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "std_lib_facilities.h"
#include <windows .h>

//user defined type to hold name-value pair for use in calculator
struct Token {
 char kind;
 double value;
 string name;
 Token(char ch) :kind(ch), value(0) { }
 Token(char ch, double val) :kind(ch), value(val) { }
 Token(char ch, string n) :kind(ch), name(n) { }
};

//user-defined type that handles retrieving items from input
class Token_stream {
 bool full;
 Token buffer;
public:
 Token_stream() :full(0), buffer(0) { } //default constructor
 Token_stream(istream&);     //constructor for istream

 Token get();
 void unget(Token t) { buffer = t; full = true; }

 void ignore(char);
};

double expression(Token_stream& ts);  //forward declaration
void calculate(Token_stream& ts);
void showHelp();

const char let = 'L';
const char quit = 'Q';
const char print = '\n';
const char number = '8';
const char name = 'a';
const char squareR = 's';
const char findPow = 'p';
const char isConst = 'C';
const char help = 'h';

const string declKey = "let";
const string quitKey = "quit";
const string sqrtKey = "sqrt";
const string powKey = "pow";
const string constKey = "const";
const string printKey = "'\n'";


//evaluate each char in the stream and determine what it is 
Token Token_stream::get()
{
 if (full) //check if we have already have a token ready
 {
  full = false;
  return buffer;
 }

 char ch;
 cin.get(ch);        //does not skip whitespace
 while (isspace(ch))       //if ch is whitespace
 {
  if (ch == '\n')       //if ch == newline 
   return Token(print);    //print result

  cin.get(ch);       //if not newline get next ch in stream
 }

 switch (ch)
 {
 case '(': case ')': case '+': case '-':
 case '*': case '/': case '%':
 case '=': case ',':
  return Token(ch);     //let each char represent itself
 case '.':
 case '0': case '1': case '2': case '3':
 case '4': case '5': case '6': case '7':
 case '8': case '9':
 {
  cin.unget();      //put digit back into the input stream
  double val;
  cin >> val;       //read a floating-point number
  return Token{ number, val };  //return number or . with a value, put back into buffer
 }

 //allow user defined variables if user types #
 case '#':
  return Token(let);

  //if user presses h or H return to execute help function
 case 'h': case 'H':
  return Token(help);

 default:
  //do this if ch is a letter
  if (isalpha(ch) || ch == '_')
  {
   string s;
   s += ch;

   //while there are still chars in cin, read them into s
   while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_'))
    s += ch;
   cin.unget();

   //if string is equal to other commands defined below, return them
   if (s == declKey)
    return Token(let);
   if (s == constKey)
    return Token(isConst);
   if (s == quitKey)
    return Token(quit);
   if (s == sqrtKey)
    return Token(squareR);
   if (s == powKey)
    return Token(findPow);

   return Token(name, s);
  }

  //if the char does not fit any of these paramenters return an error message
  error("Bad token");
 }
}

//discard characters up to and including a c
//c represents the kind of token
void Token_stream::ignore(char c)
{
 //first look in the buffer
 if (full && c == buffer.kind)
 {
  full = false;
  return;
 }

 full = false;

 //now search input
 char ch;
 while (cin >> ch)
  if (ch == c) return;
}

//-----------------------------------------------------------------------------------------------------//

//-----------------------------------------------------------------------------------------------------//

struct Variable
{
 string name;
 double value;
 bool isConst;
 Variable(string n, double v, bool ic) :name(n), value(v), isConst(ic) { }
};

//-----------------------------------------------------------------------------------------------------//

class Symbol_table {
 vector<Variable> var_table;
public:
 double get(string s);
 void set(string s, double d);
 bool is_declared(string s);
 double define(string var, double val, bool isConst);
 double declare(Token_stream& ts);
};

//return the value of the Variable named s
double Symbol_table::get(string s)
{
 for (int i = 0; i < Symbol_table::var_table.size(); ++i)
 {
  if (Symbol_table::var_table[i].name == s)
  {
   return Symbol_table::var_table[i].value;
  }
 }
 error("get: undefined name ", s);
}

//set the Variable named s to d
void Symbol_table::set(string s, double d)
{
 for (int i = 0; i < Symbol_table::var_table.size(); ++i)
 {
  //allow redefinitions as long as variable isn't const
  if (Symbol_table::var_table[i].name == s && Symbol_table::var_table[i].isConst == false)
  {
   Symbol_table::var_table[i].value = d;
   return;
  }
 }
 error("set: undefined name ", s);
}

//is variable already declared?
bool Symbol_table::is_declared(string s)
{
 for (int i = 0; i < Symbol_table::var_table.size(); ++i)
 {
  if (Symbol_table::var_table[i].name == s && Symbol_table::var_table[i].isConst == true)
   error("Cannot reassign const variable");
  else if (Symbol_table::var_table[i].name == s && Symbol_table::var_table[i].isConst == false)
   return true;
 }

 return false;
}

//allow programmers to add (var,val) to variable vector
double Symbol_table::define(string var, double val, bool isConst)
{
 if (is_declared(var))
  error(var, " declared twice");

 var_table.push_back(Variable(var, val, isConst));

 return val;
}

//check for name definition errors
double Symbol_table::declare(Token_stream& ts)
{
 Token t = ts.get();

 //is const the next word in the stream?
 bool isC;
 if (t.kind == isConst)
 {
  isC = true;
  t = ts.get();  //get the the next word in the stream for the name
 }
 else
  isC = false;

 if (t.kind != name)
  error("name expected in declaration;");

 string name = t.name;

 //if name has already been declared ask if they want to change it
 if (Symbol_table::is_declared(name))
 {
  cout << name + ", declared twice. Would you like to reassign? (No need to print with ';') y/n > ";
  cin.clear();
  cin.ignore(10000, '\n'); //clear the buffer
  string ans;
  getline(cin, ans);
  if (ans == "n")
   error(name, ", will not be reassigned; ");
  if (ans == "y")
  {
   cout << "(No need to print with ';') Please enter new value: ";
   int val;
   cin >> val;
   Symbol_table::set(name, val);

   double d = val;   //return value to print to reset calculator
   return d;
  }

 }

 Token t2 = ts.get();
 if (t2.kind != '=')
  error("= missing in declaration of ", name);

 double d = expression(ts);
 Symbol_table::var_table.push_back(Variable(name, d, isC));

 return d;
}

//-----------------------------------------------------------------------------------------------------//
Symbol_table symbols;
//-----------------------------------------------------------------------------------------------------//

//check tokenstream for 'your char here'
Token checkForChar(Token t, char ch)
{
 if (t.kind != ch)
 {
  //convert ch to string for error message
  string chstring = "";
  chstring += ch;
  error("'" + chstring + "' expected");
 }

 return t;
}

//solve characters received from ts.get()
double primary(Token_stream& ts)
{
 //get character from stream
 Token t = ts.get();
 switch (t.kind)
 {
  //solve "(expression)"
 case '(':
 {
  double d = expression(ts);
  t = ts.get();
  checkForChar(t, ')');
  return d;
 }

 //solve "-primary"
 case '-':
  return -primary(ts);

  //solve "number"
 case number:
  return t.value;

  //solve "name"
 case name:
  return symbols.get(t.name);

  //solve "sqrt(expression)"
 case squareR:
 {
  //get next char after 'sqrt' if not '(' then error   
  t = ts.get();
  checkForChar(t, '(');

  //if expression is less than 0 print an error
  double d = expression(ts);
  if (d < 0)
   error("Cannot squareroot negative integers");

  //get next char after expression, if not ')' then error
  t = ts.get();
  checkForChar(t, ')');

  // return square root of the expression taken from the tokenstream
  return sqrt(d);
 }

 //solve "pow(expression, expression)"
 case findPow:
 {
  //get next char after 'pow' if not '(' then error   
  t = ts.get();
  checkForChar(t, '(');

  //get the expression after '('
  double d = expression(ts);

  //get next char after 'expression' if not ',' then error   
  t = ts.get();
  checkForChar(t, ',');

  //get the expression after ','
  double i = expression(ts);

  //get next char after expression, if not ')' then error
  t = ts.get();
  checkForChar(t, ')');

  // return expression using pow() from 
  return pow(d, i);
 }

 default:
  error("primary expected");
 }
}

//solves for primary, *, / and %
double term(Token_stream& ts)
{
 double left = primary(ts);
 while (true)
 {
  Token t = ts.get();
  switch (t.kind)
  {
  case '*':
   left *= primary(ts);
   break;
  case '/':
  {
   double d = primary(ts);
   if (d == 0)
    error("divide by zero");
   left /= d;
   break;
  }
  case '%':
  {
   double d = primary(ts);
   if (d == 0)
    error("%:divide by zero");
   left = fmod(left, d);
   break;
  }
  default:
   ts.unget(t);
   return left;
  }
 }
}

//solves for terms and + -
double expression(Token_stream& ts)
{
 double left = term(ts);
 while (true)
 {
  Token t = ts.get();

  switch (t.kind)
  {
  case '+':
   left += term(ts);
   break;
  case '-':
   left -= term(ts);
   break;
  default:
   ts.unget(t);
   return left;
  }
 }
}

double statement(Token_stream& ts)
{
 Token t = ts.get();
 switch (t.kind)
 {
 case let:
  return symbols.declare(ts);
 default:
  ts.unget(t);
  return expression(ts);
 }
}

void clean_up_mess()
{
 cout << "\nRestarting Calculator .";
 Sleep(400);
 cout << ".";
 Sleep(400);
 cout << ".";
 Sleep(400);
 cout << ".";
 Sleep(400);
 cout << ".\n\n";
 cin.clear();
 cin.ignore(10000, '\n'); //clear the buffer 
}

const string prompt = "> ";
const string result = "= ";

void calculate(Token_stream& ts)
{
 while (true) try
 {
  cout << prompt;
  Token t = ts.get();

  while (t.kind == print)
   t = ts.get();       //first discard all 'prints'

             //if user types h or H show help, then clear the stream and get new values
  if (t.kind == help)
  {
   showHelp();
   cout << prompt;
   t = ts.get();
  }

  if (t.kind == quit)
   return;

  ts.unget(t);

  cout << result << statement(ts) << endl;
 }
 catch (runtime_error& e)
 {
  cerr << e.what() << endl;
  clean_up_mess();
 }
}

int main()

try {
 symbols.define("pi", 3.1415926535, true);
 symbols.define("e", 2.7182818284, true);
 symbols.define("k", 1000, false);

 Token_stream ts;

 calculate(ts);
 return 0;
}

catch (exception& e) {
 cerr << "exception: " << e.what() << endl;
 char c;
 while (cin >> c && c != ';');
 return 1;
}

catch (...) {
 cerr << "exception\n";
 char c;
 while (cin >> c && c != ';');
 return 2;
}

void showHelp()
{
 cout << "-----------------------HOW TO USE THE CALCULATOR------------------------\n";
 cout << "------------------------------------------------------------------------\n";
 cout << "1. To exit the program type 'quit' and press enter.\n";
 cout << "2. To show results, press enter.\n";
 cout << "3. To create your own keyword, type 'let yourWord = value'\n";
 cout << "   You can let a keyword be a const by typing 'const' before 'let'\n";
 cout << "4. To find the squareroot, type 'sqrt' followed by your number.\n";
 cout << "5. To find a number to a power of, type 'pow(number,number)'\n";
 cout << "------------------------------------------------------------------------\n\n";

 cin.clear();
 cin.ignore(10000, '\n'); //clear the buffer for new values
}

Wednesday, 4 April 2018

Chapter 8 // Drill 3 - 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 // Drill 3



3. Write a program using a single file containing three namespaces X, Y, and Z so that the following main() works correctly:

int main()
{
X::var = 7;
X::print(); //print X's var

using namespace Y;
var = 9;
print(); //print Y's var

{
using Z::var;
using Z::print;
var = 11;
print(); //print Z's var
}

print(); //print Y's var
X::print(); //print X's var

}

Each namespace needs to define a variable called var and a function called print() that outputs the appropriate var using cout.


#include "std_lib_facilities.h"

namespace X {
 double var;

 void print()
 {
  cout << "X: " << var << endl;
 }
}

namespace Y {
 double var;

 void print()
 {
  cout << "Y: " << var << endl;
 }
}

namespace Z {
 double var;

 void print()
 {
  cout << "Z: " << var << endl;
 }
}

int main()
{
 X::var = 7;
 X::print();  //print X's var

 using namespace Y;
 var = 9;
 print();  //print Y's var

 {
  using Z::var;
  using Z::print;
  var = 11;
  print(); //print Z's var
 }

 print();  //print Y's var
 X::print();  //print X's var

 keep_window_open();

 return 0;
}

Sunday, 1 April 2018

Chapter 8 // Drill 2 - 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 // Drill 2



2. Write three functions swap_v(int, int), swap_r(int&, int&), and swap_cr(const int&, const int&). Each should have the body
{int temp; temp = a, a = b; b = temp}

where a and b are the names of the arguments. Try calling each functions like this:
int x = 7;
int y = 9;
swap_?(x, y);
swap_?(7, 9);
const int cx = 7;
const int cy = 9;
swap_?(cx, cy);
swap_?(7.7, 9.9);
double dx = 7.7;
double dy = 9.9;
swap_?(dx, dy);
swap_?(7.7, 9.9);

Which functions and calls compiled and why?
After each swap that compiled, print the value of the arguments after the call to see it they were actually swapped. If you are surprised by the result, consult section 8.6.

First of all the program won't compile because you cannot change a const value so the third function needs to have a different body. This can be done by creating a second temp variable, assigning b to it and then sending temp and temp2 to one of the previous functions to be swapped.

Also, when sending numbers to the functions they will not be printed as functions can only return 1 value so the print was added to end of each calling function instead apart from the const function as that calls one that already has a print command.

Also on the functions that send numbers you cannot use pass-by-reference because that requires an object to be passed not a value. Also the double values will be truncated as all three functions use ints.

For this exercise I modified the previous drill to accomadate this one, so the program is split into three seperate files; my.h, my.cpp and use.cpp which contains main();

//my.h
#pragma once
//my.h
#include "std_lib_facilities.h"

//declarations
void swap_v(int, int);
void swap_r(int&, int&);
void swap_cr(const int&, const int&);

void keepWindowOpen();


//my.cpp
//my.cpp

#include "my.h"


//swap two integers using pass-by-value
void swap_v(int a, int b)
{
 int temp;
 temp = a;
 a = b;
 b = temp;

 cout << a << '\t' << b << endl;

 return;
}

//swap two integers using pass-by-reference
void swap_r(int& a, int& b)
{
 int temp;
 temp = a;
 a = b;
 b = temp;

 cout << a << '\t' << b << endl;

 return;
}

//swap two integers using pass-by-const-reference
void swap_cr(const int& a, const int& b)
{
 int temp;
 int temp2;

 temp = a;
 temp2 = b;

 swap_r(temp, temp2);

 return;
}

//function to keep the window open
void keepWindowOpen()
{
 char c;
 cout << "\nPress any key to quit: ";
 cin >> c;
}


//use.cpp
/use.cpp

#include "my.h"

int main()
{
 //variables to swap
 int x = 7;
 int y = 9;

 swap_r(x, y);
 swap_cr(7, 9);

 //const variables to swap
 const int cx = 7;
 const int cy = 9;

 swap_v(cx, cy);
 swap_cr(7.7, 9.9);

 //double variables to swap
 double dx = 7.7;
 double dy = 9.9;

 swap_v(dx, dy);
 swap_cr(7.7, 9.9);

 //keep window open until any key press
 keepWindowOpen();
}




Wednesday, 28 March 2018

Chapter 8 // Drill 1 - 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 // Drill 1



1. Create three files: my.h, my.cpp, and use.cpp. The header file my.h contains:

extern int foo;
void print_foo();
void print(int);

The source code file, my.cpp #includes my.h and std_lib_facilities.h, defines print_foo() to print the value of foo using cout, and print(int i) to print the value of i using cout.

The source code file use.cpp #includes my.h, defines main() to set the value of foo to 7 and print it using print_foo(), and to print the value of 99 using print(). Note that use.cpp does not #include std_lib_facilities.h as it doesn't directly use any those facilities.

Get these files compiled and run. On Windows, you need to have both use.cpp and my.cpp in a project and use { char cc; cin >> cc} in use.cpp to be able to see your output. Hint: You need to #include <iostream> to use cin.


//my.h
#pragma once
//my.h

//declarations
extern int foo;
void print_foo();
void print(int);

void keepWindowOpen();

//my.cpp

//my.cpp

#include "my.h"
#include "std_lib_facilities.h"

int foo;

//print the value of foo
void print_foo()
{
 cout << foo << endl;
}

//print a given integer
void print(int i)
{
 cout << i << endl;
}

//function to keep the window open
void keepWindowOpen()
{
 char c;
 cout << "\nPress any key to quit: ";
 cin >> c;
}


//use.cpp

//use.cpp

#include "my.h"

int main()
{
 //assign 7 to foo
 foo = 7;

 //print what's in foo
 print_foo();

 //send an integer to be printed to screen
 print(99);

 //keep window open until any key press
 keepWindowOpen();
}


A pretty simple exercise which showcases how to split a project up into separate files. Seeing as how you can't use keep_window_open() from std_lib_facilities I created a function in my.cpp which does the same thing and then declared it in my.h so it could be used in main(). This way I didn't have to #include <iostream> in use.cpp as it was already declared in my.cpp from the other header file.