I am trying to write a function in C++ to evaluate a postfix notation equation. My general strategy is to scan a string (in the proper format, e.g. "10 20 + 30 -").
I am doing this by incrementing an index variable i. At each increment, I check to see if the character is a digit, operator, or neither. If it's a digit, I use the getNextNum() function to get all following digits, convert that to a float, then push it to a stack. I also increment i by the length of the number captured.
If the character is an operator, I get the top two elements of the stack, do the operation, then push the result back to the stack.
The trouble is, my while loop only seems to go through once. The function only returns the first number in the string. I can't figure out what's wrong, I would appreciate any help! I inserted cout statements in the while loop, and i is only incrementing to the index after the first number.
EDIT: Ok, I added the getNextNum() function. Also, I updated the evalPostfix() with a cout of strLength, as well as i after each iteration of the while loop. When running the given code, I get this:
Running…
Please enter an expression in postfix notation: 555 666+
3
555
3
Your expression evaluates to: 555
It seems like strLength is being set to less than it should. Why could this be?
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <stack>
using namespace std;
string getNextNum(string equation, int i);
float evalPostfix(string postfix);
float doOperation(float x, float y, char op);
float doOperation(float x, float y, char op)
{
switch (op) {
case '+':
return x + y;
case '-':
return x - y;
case '*':
return x * y;
case '/':
return x / y;
default:
return 0.0;
}
}
string getNextNum(string equation, int i)
{
string num = "";
const string DELIM = "+-*/%^ ";
while (i<equation.length()) {
// Iterate through equation until you hit a delimiter.
if (DELIM.find(equation[i]) != -1) {
break;
}
num += equation[i];
i++;
}
return num;
}
float evalPostfix(string postfix)
{
const string OPS = "+-*/%^";
const string NUMS = "0123456789";
int strLength = postfix.length();
stack<float> numStack;
int i = 0;
cout << strLength << endl;
while (i<strLength) {
if (NUMS.find(postfix[i]) != -1) {
// If a character is a digit, then you should get the
// value and push it to the stack (could be multiple characters long).
string sNextNum = getNextNum(postfix, i);
float fNextNum = atof(sNextNum.c_str());
numStack.push(fNextNum);
cout << sNextNum << endl;
i += (sNextNum.length() - 1);
}
else if (OPS.find(postfix[i] != -1)) {
// Otherwise, pop the top two elements of the stack, perform the
// operation, then push the result back to the stack.
char op = postfix[i];
float x = numStack.top();
numStack.pop();
float y = numStack.top();
numStack.pop();
float z = doOperation(x, y, op);
numStack.push(z);
}
i++;
cout << i << endl;
};
// Once the entire string has been scanned through, there should be a float
// left in the stack, simply return that.
return numStack.top();
}
int main ()
{
cout << "Please enter an expression in postfix notation: ";
string postfix;
cin >> postfix;
float eval = evalPostfix(postfix);
cout << "Your expression evaluates to: " << eval;
return 0;
}
You have a few issues one of the major one being a typo, you have a misplaced ) this:
else if (OPS.find( postfix[i] != -1 ) ) {
^ ^
should be:
else if (OPS.find( postfix[i] ) != std::string::npos) {
^ ^
so you are comparing the char at position i to -1 and then doing a find on the boolean result. Next you should be using -1 to compare the results of find but std::string::npos
As Jonathan pointed out:
cin >> postfix ;
only read up to the first black or newline. Using getline will fix that problem:
if (getline(cin, postfix))
One primary problem was that the input cin >> postfix; statement only reads the first word. Echo inputs to ensure that the program is seeing what you think it is seeing.
Shafik Yaghmour points out another problem.
Points to learn:
echo inputs to make sure the program is seeing what you think it is seeing;
trace key variables with suitable printing messages;
post SSCCE (Short, Self-Contained, Correct Example) — code that can be compiled;
post example input and the output you're getting from it.
This code works on input 555 666+:
#include <iostream>
#include <string>
#include <stack>
using namespace std;
static float doOperation(float x, float y, char op)
{
cout << "doOp: x = " << x << ", y = " << y << ", op = " << op << endl;
if (op == '+')
x += y;
return x;
}
string getNextNum(string equation, int i)
{
string num = "";
const string DELIM = "+-*/%^ ";
while (i<equation.length()) {
// Iterate through equation until you hit a delimiter.
if (DELIM.find(equation[i]) != -1) {
break;
}
num += equation[i];
i++;
}
return num;
}
float evalPostfix(string postfix)
{
const string OPS = "+-*/%^";
const string NUMS = "0123456789";
int strLength = postfix.length();
stack<float> numStack;
int i = 0;
while (i<strLength) {
cout << "Top - i: " << i << ", strLength: " << strLength << endl;
if (NUMS.find(postfix[i]) != -1) {
// If a character is a digit, then you should get the
// value and push it to the stack (could be multiple characters long).
string sNextNum = getNextNum(postfix, i);
float fNextNum = atof(sNextNum.c_str());
numStack.push(fNextNum);
cout << sNextNum << endl;
i += (sNextNum.length() - 1);
}
else if (OPS.find(postfix[i])!= -1) {
// Otherwise, pop the top two elements of the stack, perform the
// operation, then push the result back to the stack.
char op = postfix[i];
float x = numStack.top();
numStack.pop();
float y = numStack.top();
numStack.pop();
float z = doOperation(x, y, op);
numStack.push(z);
}
i++;
cout << "End - i: " << i << ", strLength: " << strLength << endl;
}
cout << "After - i: " << i << ", strLength: " << strLength << endl;
// Once the entire string has been scanned through, there should be a float
// left in the stack, simply return that.
return numStack.top();
}
int main ()
{
cout << "Please enter an expression in postfix notation: ";
string postfix;
//cin >> postfix;
if (getline(cin, postfix))
{
cout << "Evaluating: " << postfix << endl;
float eval = evalPostfix(postfix);
cout << "Your expression evaluates to: " << eval << endl;
}
return 0;
}
Sample trace:
Please enter an expression in postfix notation: 555 666+
Evaluating: 555 666+
Top - i: 0, strLength: 8
555
End - i: 3, strLength: 8
Top - i: 3, strLength: 8
End - i: 4, strLength: 8
Top - i: 4, strLength: 8
666
End - i: 7, strLength: 8
Top - i: 7, strLength: 8
doOp: x = 666, y = 555, op = +
End - i: 8, strLength: 8
After - i: 8, strLength: 8
Your expression evaluates to: 1221
Clearly, you can lose much of the diagnostic output once the specific problem you are solving is resolved, but being prepared to add it along the lines shown can dramatically speed up the process of solving it.
Related
I am so close to solving this roman numeral to integer problem. However, in my if statement for when character equals M, I am getting an error thrown when declaring my previous variable when the input is MCMXCIV for example. Because there is nothing before M, it is throwing an out-of-bounds error. How can I fix this?
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
using namespace std;
//Character to search and add to the integer
char character;
//The integer value that is needed to add up and output the corresponding value
int integer = 0;
//One of the test runs and what will be needed for every special case
int main()
{
//Roman numeral given
string input;
//Prompt for user to enter the roman numeral integer
cout << "Enter the roman numeral you want to convert into a number: " << endl;
cin >> input;
cout << input << " is what you are wanting to convert." << endl;
//Read through the string that is being inputted then assign values to the overall integer
for (int i = 0; i < input.length(); i++)
{
character = input.at(i);
cout << "This is the character that is being read right now: " << character << endl;
//Arithmitic for when the character is found and the corresponding value needs to be added
if(character == 'I')
{
integer+=1;
cout << "Integer value now: " << integer << endl;
}
else if(character == 'V')
{
char previous = input.at(i-1);
integer+=5;
if(character == 'V' && previous == 'I')
{
integer = integer - 2;
}
cout << "Integer value now: " << integer << endl;
}
else if(character == 'X')
{
integer+=10;
cout << "Integer value now: " << integer << endl;
}
else if(character == 'L')
{
integer+=50;
cout << "Integer value now: " << integer << endl;
}
else if(character == 'C')
{
integer+=100;
cout << "Integer value now: " << integer << endl;
}
else if(character == 'D')
{
integer+=500;
cout << "Integer value now: " << integer << endl;
}
else if(character == 'M')
{
char previous = input.at(i-1);
integer+=1000;
if(character == 'M' && previous == 'C')
{
integer -= 200;
}
cout << "Integer value now: " << integer << endl;
}
}
cout << "The integer value is: " << integer << endl;
}
First of all: Good that you used the at() function. So you could detect the "out of bounds" problem.
in char previous = input.at(i - 1);, variable "i" could be 0 and you then try to access array element "-1", which is of course out of bounds for your use case.
So, you need an additional check, if "i" greater then 0, before subtracting.
But in general, your approach is too complicated. You can make your life easier, by analyzing or reading, how roman numerals are defined. Look for example here. And please read especially about the "subtractive notation".
You already noticed that but, unfortunately, your implementation is not always following that rule. You made the check only for "M" and "V". But basically, you need to do that for all literals (except "I").
You can boil down this to the rule:
If a literal before a following literal is less, then use the subtrative form. Or, even better, you can read from right to left and finally say:
"If the current literal is less than the follwoing, then use the subtractive form."
And what is the subtractive form? We can simply add the negative number. Example, using number 94 which is "XCIV". We start summing up from the right:
Start. Begin from right. Initialize sum with rightmost value: Looking at 'V': sum = 5
Next: Read 'I'. Check, if this is less than the following literal 'V'. Yes, it is. So, use subtractive form. Add the negative. Now sum = sum + (-1), sum = 4
Now: Read 'C'. Check, if this is less than the following literal 'I'. No, it is not. So, simply add the positive value. Now sum = sum + 100, sum = 104
Next: Read 'X'. Check, if this is less than the following literal 'C' . Yes, it is. So, use subtractive form. Add the negative. Now sum = sum + (-10), sum = 94
So, this is now a very simply algorithm. We will convert a roman literal (one letter) to a integer and then build a sum with positive or negative values.
One of many many potential implementations could look like this:
#include <iostream>
#include <string>
int convert(char romanLiteral) {
switch (romanLiteral) {
case 'I':
return 1;
case 'V':
return 5;
case 'X':
return 10;
case 'L':
return 50;
case 'C':
return 100;
case 'D':
return 500;
case 'M':
return 1000;
default:
return 0;
}
}
int romanLiteralStringToInteger(const std::string& romanLiteralString) {
// Sanity check:
if (romanLiteralString.empty()) return 0;
// Get length of input string
int lengthOfRomanLiteralString = static_cast<int>(romanLiteralString.length());
// Initialize sum with rightmost value
int sum = convert(romanLiteralString[lengthOfRomanLiteralString-1]);
// Now iterate over the string form right to left
for (int i = lengthOfRomanLiteralString - 2; i >= 0; --i) {
// Check if this literal is less than the following
if (convert(romanLiteralString[i]) < convert(romanLiteralString[i+1]))
sum -= convert(romanLiteralString[i]);
else
sum += convert(romanLiteralString[i]);
}
return sum;
}
int main() {
std::string romanNumber = "XCIV";
std::cout << romanNumber << " --> " << romanLiteralStringToInteger(romanNumber) << '\n';
}
In C++ you would probably use associative containers like std::map or std::unordered_map for converting one literal to a number. And maybe a ternary operator, instead of an if.
Then the problem could be implemented like the following:
#include <iostream>
#include <string>
#include <unordered_map>
int romanLiteralStringToInteger(const std::string& romanLiteralString) {
if (romanLiteralString.empty()) return 0;
std::unordered_map<char, int> T = { { 'I' , 1 }, { 'V' , 5 }, { 'X' , 10 }, { 'L' , 50 }, { 'C' , 100 }, { 'D' , 500 }, { 'M' , 1000 } };
int sum = T[romanLiteralString.back()];
for (int i = romanLiteralString.length() - 2; i >= 0; --i)
sum += (T[romanLiteralString[i]] < T[romanLiteralString[i + 1]] ? -T[romanLiteralString[i]] : T[romanLiteralString[i]]);
return sum;
}
int main() {
std::string romanNumber = "XCIV";
std::cout << romanNumber << " --> " << romanLiteralStringToInteger(romanNumber) << '\n';
}
And the hardcore solution with a stateful lambda.
#include <iostream>
#include <string>
#include <unordered_map>
#include <numeric>
#include <iterator>
std::unordered_map<char, int> ARTI{{'I',1 },{'V',5 },{'X',10 },{'L',50 },{'C',100},{'D',500 },{'M',1000 }};
int main() {
std::string romanNumber = "XCIV";
std::cout << std::accumulate(std::next(romanNumber.rbegin()), romanNumber.rend(), ARTI[romanNumber.back()], [&, next = ARTI[romanNumber.back()]](const int s, const char c) mutable {
int sum = s + (ARTI[c] < next ? -ARTI[c] : ARTI[c]); next = ARTI[c]; return sum; });
}
I am writing an IP calculator program to convert an IP adress into the broadcast adress, network adress etc.
I need to convert the adress into 8-digit biniary first, I already used itoa for it decimal to biniary conversion, but I still need to make it always 8 digit.
I want to use a switch to do it. First the program counts the number of digits in the binary form, and then, using switch (I put it into a comment, I need to figure out this proble first) and if it adds enough zeros in front of the number (actually a string at this point) so it would always be 8 characters long.
I want to use string e1('00',e); instruction to add two zeros to the string, but it doesn't work. e is the original string, e1 is the new 8 character string. It doesn't want to compile, stops at this line (string e1('00',e);) and gives:
error: no matching function for call to 'std::__cxx11::basic_string<char>::
basic_string(int, std::__cxx11::string)'|
My code:
#include <iostream>
#include <string>
#include <bits/stdc++.h>
using namespace std;
/**
* C++ version 0.4 std::string style "itoa":
* Contributions from Stuart Lowe, Ray-Yuan Sheu,
* Rodrigo de Salvo Braz, Luc Gallant, John Maloney
* and Brian Hunt
*/
std::string itoa(int value, int base)
{
std::string buf;
// check that the base if valid
if (base < 2 || base > 16)
return buf;
enum
{
kMaxDigits = 35
};
buf.reserve(kMaxDigits); // Pre-allocate enough space.
int quotient = value;
// Translating number to string with base:
do
{
buf += "0123456789abcdef"[std::abs(quotient % base)];
quotient /= base;
} while (quotient);
// Append the negative sign
if (value < 0)
buf += '-';
std::reverse(buf.begin(), buf.end());
return buf;
}
int main()
{
cout << "Dzien dobry." << endl
<< "Jest OK!\n";
int a, b, c, d, i, j, k, l, m, n, o, p, r, s, t, u, w, v, x, y, z;
cout << "Wprowadz pierwszy oktet: ";
cin >> a;
cout << "Wprowadz drugi oktet: ";
cin >> b;
cout << "Wprowadz trzeci oktet: ";
cin >> c;
cout << "Wprowadz czwarty oktet: ";
cin >> d;
cout << "Wyswietlam adres IP w postaci dziesietnej: " << a << "." << b << "." << c << "." << d << "\n";
char res[1000];
itoa(a, res, 2);
string e(res);
itoa(b, res, 2);
string f(res);
itoa(c, res, 2);
string g(res);
itoa(d, res, 2);
string h(res);
//
x = e.size();
cout << x << "\n";
/*
if (x<8)
{
switch(x)
{
case 1: string e(1);
break;
case 2: string e(3);
break;
case 3: string e(2);
break;
case 4: string e(0);
break;
case 5: string e(4);
break;
case 6: string e(7);
break;
case 7: string e(0);
break;
default: cout << "error";
}
}
*/
string e1('00', e);
cout << e1 << "\n";
cout << "Wyswietlam adres IP w postaci dwojkowej: " << e1 << "." << f << "." << g << "." << h;
return 0;
}
Single quotation marks are for single characters, double quotation marks are for strings, i.e. more than one character, so you need "00".
There is no std::string constructor for the parameters you provide, among other methods, you can use:
string e1;
e1.append("00").append(e);
Or
string e1 = "00";
e1 += e;
Aditional notes:
Avoid using #include <bits/stdc++.h>
Avoid using using namespace std;
Just use + or +=:
std::string foo = "Hello";
std::string bar = foo + " world";
std::cout << bar; // Prints Hello world
You can also modify a string in-place with +=:
std::string foo = "Hello";
foo += " world"; // foo is "Hello world" now
Note that this invalidates any existing iterators you had that pointed to characters inside foo. You can get the new begin and end iterators by just calling begin and end again.
I was recently doing a problem in C++:
Write a program to work out if a series of 5 digits are consecutive
numbers. To make this easier, assumes the digits are a string:
string numbers = "10-9-8-7-6";
Make sure your code works for the following sequence, as well:
string numbers = "1-2-3-4-5";
I solved it, however I saw when I used cin for the string the console window threw some exception & didn't execute the program but on replacing it with getline, it worked perfectly.
Could anyone explain me the reason behind it because logically both should work properly.
The program is:
#include<iostream>
#include<string>
using namespace std;
void change(int x, int y, int &inc, int &dec)
{
if (x - y == 1)
++dec;
else if (y - x == 1)
++inc;
}
int main()
{
string s = "", snum = "";
cout << "enter 5 nos and use \'-\' to separate them: ";
cin >> s;
int i = 0, x = 0, y = 0, inc = 0, dec = 0;
for (char &ch : s)
{
if (ch == '-')
{
++i;
if (i == 1)
{
y = stoi(snum);
cout << y << endl;
}
else
{
x = y;
y = stoi(snum);
cout << x << " " << y << endl;
change(x, y, inc, dec);
}
snum = "";
}
else
snum += ch;
}
x = y;
y = stoi(snum);
cout << x << " " << y << endl;
change(x, y, inc, dec);
if (inc == 4 || dec == 4)
cout << "ORDERED";
else
cout << "UNORDERED";
return 0;
}
If you have to enter everything at the same time such as:
10 9 8 7 6
All on one line then cin does not record all that at the same time.
Concerning cin it only takes the characters before a space (" ") for example. Getline however takes that entire line and uses it. Another way to do the same thing would be to use the cstdio library and have it set up with either using printf or puts to prompt, and then use gets to gather all the information from the puts prompt. This is what I assume why it works.
Example:
cstdio library
char string[50];
printf("Enter a string of text");
gets(string);
cout << string << endl;
*EDIT
After the comment below I realized what you are asking, and if you are assuming the numbers are strings, and they are separated with hyphens and no spaces then it should work fine. It shouldn't be the problem of cin by maybe something else?
If there are spaces involved in your code then what I wrote above EDIT will be a simple solution to THAT problem.
If you need to get a formatted string, I recommend you scanf like this:
if( 5 == scanf("%d-%d-%d-%d-%d", &a, &b, &c, &d, &e) )
//welldone
// work with above 5 int easily :)
else
// Please enter again
This way you don't have to work with string at all and life would be easier.
You can easily check if these 5 are consecutive or not .
If you need not a new solution and want to get your code fixed, tell me in comment.
I am having a problem with remembering a variable for next use and printing it out. I explain it more so understand what am I trying to do in my program.
I have a person walking on a rectangle of size a b. I input starting location x y together with persons starting direction (North = y+1, South = y-1, East = x+1, West = x-1 // in my code it is S,J,V,Z). So my input looks like this:
5 6 // a b
3 3 S // x y s(this stands for starting direction - north)
Now, I input number of moves d to generate for the person where it should move.
I enter number 4, and it can generate from 3 letters: D, L, P (Forward, turn left 90 degrees, turn right 90 degrees).
4 // d
PLDL // moves
Now, the person should be walking by those moves. So if the person location and starting direction is 3 3 S, it should just turn right (my direction is east but same location), then left (direction is north again, same location), then forward (now I move y+1, my direction is still north) and last move is turn left(direction west). So mi final location and direction (output) is:
3 4 Z
Hope you understand it. If is something unclear, just ask in comment.
I am getting weird output now, unreal numbers. I cant figure out how to put together variables and if conditions to solve it. My code takes first, starting direction and location, but later on when I generate moves, it should change to final output based on the generated string. Sadly, it doesnt work as I expect. Do you have any suggestions? My question is kind of wide but I hope we can solve it together.
#include <iostream>
#include <string>
#include <stdlib.h>
#include <string.h>
#include <vector>
using namespace std;
int n; // pocet uloh
int a; // rozmer obdlznika a
int b; // rozmer obdlznika b
int i;
static const char alpha[] = {'D', 'L', 'P'};
char genRandom()
{
return alpha[rand() % strlen(alpha)];
}
// end of generator
// funkcia na pohyb
void pohyb (){
int x[i];
int y[i];
string sD = ""; // starting direction
string mD = ""; // middle direction (stored one for next use)
string eD = ""; // ending direction to print out in output
string d = ""; // number of generated directions eg. d=6 ==> PDDLPPD
for (int i=0; i < d.size(); i++){
if (sD[i] == 'S'){
if(d[i] == 'D'){
y[i] = (y[i]+1);
}else if(d[i] == 'L'){
mD[i] == 'Z';
}else if(d[i] == 'P'){
mD[i] == 'V';
}
}else if (sD[i] == 'J'){
if(d[i] == 'D'){
y[i] = (y[i]-1);
}else if(d[i] == 'L'){
mD[i] == 'V';
}else if(d[i] == 'P'){
mD[i] == 'Z';
}
}else if (sD[i] == 'V'){
if(d[i] == 'D'){
x[i] = (x[i]+1);
}else if(d[i] == 'L'){
mD[i] == 'S';
}else if(d[i] == 'P'){
mD[i] == 'J';
}
}else if (sD[i] == 'Z'){
if(d[i] == 'D'){
x[i] = (x[i]-1);
}else if(d[i] == 'L'){
mD[i] == 'J';
}else if(d[i] == 'P'){
mD[i] == 'S';
}
} // koniec if podmienky
eD = mD[i];
} // koniec for loopu
// vystup
for ( i = 0 ; i < n ; i++ )
{
if(!((x[i]>=0)&&(x[i]<=a) & (y[i]>=0)&&(y[i]<=b))){
cout << x[i] << ' ' << y[i] << ' ' << eD[i] << ' ' << "SPADOL" << endl;
}else{
cout << x[i] << ' ' << y[i] << ' ' << eD[i] << endl;
}
}
} // koniec funkcie pohyb
int main() {
cin >> n;
vector<int> x(n); // x position
vector<int> y(n); // y position
vector<int> d(n); // zombie directions generation ex. DPLDDP
vector<string> sD(n); // starting direction
vector<string> eD(n); // ending direction
while(!((n >= 1)&&(n <=15000)))
{
cout << "max 15000" << flush;
cin >> n;
}
cin >> a >> b;
while(!((a >= 1)&&(a <=100) & (b >= 1)&&(b <= 100)&&(a!=b)))
{
cout << "chyba max 100 alebo a!=b" << endl;
cin >> a >> b;
}
for (i = 0; i < n; i++)
{
cout << "Uloha " << i+1 << ":" << endl;
cin >> x[i];
cin >> y[i];
cin >> sD[i];
while(!((x[i]>=0)&&(x[i]<=a))) {
cout << "Try Again x: " << flush;
cin >> x[i];}
while(!((y[i]>=0)&&(y[i]<=b))) {
cout << "Try Again y: " << flush;
cin >> y[i];}
cin >> d[i];
while(!((d[i]>=1)&& (d[i]<=200))) {
cout << "Try Again d: " << flush;
cin >> d[i];}
for (int counter=0; counter<d[i]; counter++)
{
cout << genRandom();
}
cout << endl;
} // koniec for
pohyb();
system("pause");
}
Sample input:
3
3 5
2 2 S
8
DPLDLPDD
2 4 Z
7
PDDPDPD
2 1 J
8
PPDLDDDD
and output
2 5 S SPADOL // spadol means his location is out of the rectangle
3 4 J
0 2 Z SPADOL
Rather than fix your code, I'm going to give you a number of explanations that should help you understand and fix it yourself.
Firstly, let me adjust your understanding of what a variable is. In a programming language, there are values that need to be stored. Once we store a value, we will need to be able to retrieve it again and so we will need a way to describe where it was stored.
int i = 5;
This tells the compiler to create an instance of the int value type, to assign it the value of 5, and to call it i.
However, C++ is a scoped language. That means that there is a limitation on how visible any given name is.
int x() {
int i;
}
int y() {
i = 5; // ERROR: I not declared in this scope.
}
In the above code, we declared i in one scope - the function body of x - but then tried to use it in another.
C++ scopes are generally distinguished by '{ ... }', for example the following is valid:
#include <iostream>
int i = 0; // globally visible 'i'.
void f() { std::cout << "from f i = " << i << '\n'; }
int main() { // <-- function body scope
int i = 1;
{ // inner scope
int i = 2; // new variable, called 'i', but only inside this scope.
{ // <-- another inner scope
i = 3;
f();
}
} // scope ended, the second 'i' has no gone away.
std::cout << "from end of main i = " << i << '\n';
return 0;
}
The above program prints "0" and then "1".
C++ allows us to do something call "shadowing" - we can use the same name for different variables in different scopes.
Scope also affects the "lifetime" of variables (see http://ideone.com/fXPlB7), but I'm not going to cover that.
Let me demonstrate more clearly the implications - that the variables have a similar name but are NOT the same variable:
int i = 5;
void f(float i)
{
std::cout << "in f, i is " << i << '\n';
}
int main()
{
char i[] = "Hello";
f(3.141);
std::cout << "in main, i is " << i << '\n';
return 0;
}
What does this program print?
Make sure you understand this: i is not changing, but rather which variable i refers to in a given scope.
In your function pohyb, you have the following two lines of code:
string d = ""; // number of generated directions eg. d=6 ==> PDDLPPD
for (int i=0; i < d.size(); i++){
This declares a new variable and within this scope causes the name d to refer to it. d is an empty string.
The next line iterates over all the values in d. How many values are in the empty string? 0. So, the for loop line says this:
int i = 0;
is i < 0?
0 is not < 0, so the loop is never executed.
Your next problem is the difference in C++ between a character-string (C-string) and a character-array.
C++ is based on C, which did not have a 1st-class definition of a "string". Instead, C has a convention that says: "a string is an array of 0 or more chars followed by a zero-value char".
char empty[1] = { 0 }; // valid, empty string. it has 1 element, the 'nul'.
char a[] = { 'a', 0 }; // represents "a", size is 2 chars, 'a' and '\0'
char hello[] = { 'h', 'e', 'l', 'l', 'o', 0 }; // size 6, 5 letters and a nul
char Hello[] = "hello"; // short-cut for writing the above
char ten[] = { '1', '0', 0 }; // '0' and 0 are not the same
char hundred[] = { '1', '0', '\0' }; // '\0' == 0
char ouch[4] = "ouch"; // ERROR: the string is actually 5 chars.
All of the C functions that deal with "strings" (not to be confused with std::strings), operate on this principle -- the only way to tell the length is to count characters until you reach a value of zero.
For your purposes, you actually want an array of characters, but that does not automatically make them a string.
Your code uses strlen to find the number of elements in a char array - this is incorrect, and potentially dangerous for your application. The bytes immediately following the 3 valid elements of alpha could be anything, so strlen might return 3 or it might return very large values.
What you actually want is the C keyword sizeof.
sizeof(X) is a compile-time determination of the size of a thing. When X is a fully qualified array, it returns the size in bytes of X. Be aware that this means you can only use it on an array in the global or local scope: when you pass arrays to functions they are passed by pointer.
#include <iostream>
char hello[] = "hello"; // has size 6: 'h', 'e', 'l', 'l', 'o', 0
void f(char x[])
{
std::cout << "f(x), sizeof x = " << sizeof(x) << '\n';
}
void g()
{
char x[] = "world";
std::cout << "g() sizeof x = " << sizeof(x) << '\n';
}
void h()
{
int x[] = { 1, 2, 3, 4, 5, 6, 7 };
std::cout << "h() sizeof x = " << sizeof(x) << ", but sizeof(x[0]) = " << sizeof(x[0]) << '\n';
}
int main()
{
std::cout << "main() sizeof hello = " << sizeof(hello) << '\n';
f();
g();
h();
return 0;
}
What do you expect the output to be? Paste to ideone if you want to find out.
For your code, the use of a char array looks correct, so you want to use sizeof to determine how many chars are in the array. Remember that sizeof returns the size in bytes, the formally correct way to write this would be:
size_t index = size_t(rand()) % (sizeof(alpha) / sizeof(*alpha))];
return alpha[index];
This will take the total size of alpha and divide it by the size of what type alpha points to/contains (a char). These values are known at compile time so the compiler will do this calculation and emit code equivalent to:
return alpha[rand() % (3 / 1)];
or just
return alpha[rand() % 3];
There are 3 elements in alpha, but C/C++ arrays are 0 indexed, so the modulo will provide us a value [0,3) i.e. 0, 1 or 2.
Lastly, you were concerned about working with if statements. For complex logic, sometimes the best thing to do is to write them out and run thru them by hand. You may want to familiarize yourself with the switch keyword which takes a variable and matches it against potential values:
#include <iostream>
#include <string>
int main()
{
std::string input;
while (std::cin.good()) {
std::cout << "Direction? (n/s/e/w/q): ";
std::getline(std::cin, input);
// if input is empty, input[0] would be undefined behavior.
if (input.empty())
continue;
switch (input[0]) // check the first character only
{
// input[0] is of type char, so we can express our values
// a character literals. we could also write the ascii values,
// e.g. for 'n' we could put "case 110:"
case 'n':
std::cout << "You have entered a dark room.\n";
break; // escape the switch, not the loop.
case 'e':
case 's': // no break, 'e' falls thru
case 'w': // still no break, 'e' and 's' fall thru
std::cout << "You can't go that way.\n";
break;
case 'q':
std::cout << "bye!\n";
return 0;
break;
default:
std::cout << "I asked you to type n, s, e, w or q, but you typed " << input << ".\n";
break;
}
}
return 0;
}
http://ideone.com/s4xana
---- EDIT ----
On "remembering" values between scopes. Within a function body and nested scopes, this happens automatically:
int main() {
int i = 1;
{ // inner scope
std::cout << "inner scope\n";
{ // another inner scope
if (i == 1) {
// this is a scope
std::cout << "i = " << i << '\n'; // prints 1
}
}
}
}
But between functions and modules, you need to make them function arguments.
#include <iostream>
int f(int i, int j, int k) {
std::cout << "f() i = " << i << ", j = " << j << ", k = " << k << '\n';
i = 10;
j = 100;
k = 300;
}
int main() {
int j = 42;
f(j, j, j);
std::cout << "in main: j = " << j << '\n';
return 0;
}
What does this print? Remember: variables are locally scoped. Just because they have the same name as another variable in a different scope does not make them connected.
Think of the following code like this, WARNING: PSUEDO CODE:
define f - takes int as f::i, int as f::j, int as f::k
"f() i = ", f::i, ", j = ", f::j, ", k = ", f::k, '\n';
f::i = 10;
f::j = 100;
f::k = 300;
end f
define main
declare main::j as int
let main::j be 42
call f with f::i = 42, f::j = 42 f::k = 42
"in main: j = " << main::j << '\n';
end main
Now it perhaps makes more sense - even tho we changed j in f it was not the same j as we are seeing in main.
How to overcome this:
C++ provides two methods. The old, 'c' method is to pass the address of a variable, called passing it by pointer. Pointers can get hairy and often confuse new programmers, so instead I'm going to show you the C++ mechanism: reference.
As you just saw above, when you call a function with an argument, C++ creates a new locally-scoped variable and copies the value of the input variable into it:
void f(int n)
{
n += 2;
}
f(5);
Here we see that '5' is not a variable, but a hard coded value. There is no way that 'f' could work otherwise - throughout the program '5' would have become 7.
When we want to say "call f and operate on my LOCAL variable" we use a reference.
void f(int& n)
{
n += 2;
}
int main()
{
int x = 23;
f(x);
// x is now 25
}
It's tempting to think that a reference is somehow just an alias, but that's not how they are implemented. A reference is a clever way of passing the location in memory of an existing variable, but not clever enough to be aware of that variable going away or being relocated in memory.
std::vector<int> v;
v.push_back(5);
int& first = v[0]; // reference to the first element of v at the moment,.
std::cout << "first = " << first << '\n'; // prints 5.
v.reserve(2000); // causes 'v' to relocate in memory
v[0] = 25;
std::cout << "first = " << first << '\n'; // may crash or print 5, but not 25.
The other thing to remember about references is that once they are connected to something, you cannot change the connection:
int a = 5, b = 6;
int& r = a;
std::cout << r;
r = b;
std::cout << r;
std::cout << a;
This prints: 566, not 565 because int& r = a made r a reference to a. When we said r = b, because r is now a reference to a we effectively said a = b.
---- EDIT 2 ----
C and C++ have a modifier keyword, const which is a contract that says you promise not to modify a thing. If you want to write a function that accepts a complex object by reference (to avoid copying strings, etc, which is expensive), but you don't want to change it, you can use the const modifier:
#include <iostream>
#include <string>
void writeln(const std::string& str)
{
std::cout << str << '\n';
}
int main()
{
std::string greeting = "hello";
writeln(greeting);
}
Also, a note on '&'. It doesn't matter to the compiler whether you write string& str or string &str, they mean the same thing. Whether & means 'reference' or 'address of' (for pointers) or 'and' (for logic) depends on the context.
Note: these are written before you post your sample input and output.
When you define alpha as
static const char alpha[] = {'D', 'L', 'P'};
it's really a char array of three elements. However strlen() is a function to count the number of characters before the 1st \0 (NUL) character encountered. So strlen() in your genRandom() will not work as you expect (I guess it returns a random large number.) You should define alpha as
static const char alpha[] = "DLP";
to add an implicit 4th element \0 to alpha.
In your pohyb() you define string varibales sD, mD and d with empty initial values. They have no relationship with vector<int> d and vector<string> sD, mD in your main(). So all your i < d.size(), sD[i] == 'S', d[i] == 'D'... will not work as you expect. You should pass sD, mD and d in your main() to pohyb() as arguments.
Update: OK I'll be more specific. Because string d in pohyb() is unrelated to vector<int> d in main() and remains empty throughout pohyb(), for (int i=0; i < d.size(); i++) will not run even once. Because int x[i], y[i] in pohyb() are unrelated to vector<int> x, y in main() and contain uninitialized (= random) i elements (here i happens to be equal to n when pohyb() is invoked) you see weird ("SPADOL") outputs. Please learn how to pass parameters to a function in C++ first. You will get nowhere until you learn it.
I haven't checked if these two are all you need. They are just obvious mistakes I found so far. You might need a fundamental rework on your program structure.
Modifying my reverse a string function to add recursion. Unfortunately, my program keeps blowing up.
Stepped through my code in Visual Studio and for some reason the watch window will say i is equal to the length of the string (i.e. the terminating condition to exit the while loop). I step over it one last time and it says i is now one less than the string length. Then it stays in the while loop forever.
I know this sounds confusing, so I will give an example. I enter "Spongebob" and it does everything I want it to (i.e. says the length of Spongebob is 9, prints "bobegnopS", increments i to the string length, etc), but then it says i is now 8 (i.e. it was just at 9) and never exits the while loop.
Here is my ReverseString() function:
void ReverseString(char * string, bool stringReversed, int stringLength, int i)
{
i++;
if(!stringReversed)
{
while(*string != '\0')
string++;
}
stringReversed = true;
while(i < stringLength)
{
string--;
std::cout << *string;
ReverseString(string, stringReversed, stringLength, i);
}
}
Here is the call:
case 3:
//Learn By Doing 16.6
{
char string[BUFFER_LENGTH];
bool stringReversed = false;
int base = 0;
int exponent = 0;
std::cout << "\nEnter base: " << std::endl;
std::cin >> base;
std::cout << "\nEnter exponent: " << std::endl;
std::cin >> exponent;
//Print pow
NewLine();
std::cout << base << " to the " << exponent << " is " << pow(base, exponent);
//Reverse string using recursion
std::cout << "\nEnter string: " << std::endl;
std::cin >> string;
NewLine();
int stringLength = strlen(string);
int i = 0;
ReverseString(string, stringReversed, stringLength, i);
}
When you write a recursive function you always need to specify condition when to stop. Imagine you want to write naive factorial recursive implementation. So idea is to calculate it like this:
n! = n * (n-1) *...*2*1
If you look into sequence you can see that you need to stop at value 1. So naive recursive implementation could be this:
int factorial( int n )
{
// stop when we reached 1
// otherwise we never finish
if( n == 1 ) return 1;
// now do the magic
return n * factorial( n - 1 );
}
The fact that you need to return a value or not does not change the fact that you need to put a stop condition, otherwise your recursive function will never stop.
void ReverseString(char * string, bool stringReversed, int stringLength, int i)
{
...
while(i < stringLength)
{
string--;
std::cout << *string;
ReverseString(string, stringReversed, stringLength, i);
}
}
Nothing inside the loop modifies i or stringLength (the function ReverseString takes them by value, not by reference.) So it can never terminate.