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();
}