getline() omits first letter of my output from array. - c++

I'm coding a simple Mad Libs program for school. The code I'm posting iterates through an array searching for certain prompts. Once found it uses the prompt to ask a question and records the answer. The array that holds my answers however, is omitting the first letter of every word except for the very first variable. Here is my code and a copy of the output from the array. It's shite I know, but I'm learning.
char buffer[256];
int y = 0;
//iterates through array looking for answers
for(int i = 0;i <= 256;i++)
{
if(storyArray[i][0] == '<' && isalpha(storyArray[i][1]))
{
for(int x = 0; storyArray[i][x]; x++)
{
switch(storyArray[i][x]){
case '<':
cout << "\t";
x++;
putchar(toupper(storyArray[i][x]));
break;
case '>':
cout << ": ";
cin.ignore();
cin.getline(buffer,256);
strcpy(answerArray[y],buffer);
y++;
break;
case '_':
cout << " ";
break;
default:
cout << storyArray[i][x];
break;
}
}
}
}
Output:
Arrayitem1
rrayitem2

You're telling it to miss the first character. That's what this does:
cin.ignore();
Take that out and you'll be fine.

Related

C++; Is there a way to get my Switch function to reject a valid and invalid answer together?

So I've been learning how to use the "switch" statement recently. I decided to do some practice exercises. The code I show in my sample code below is one I came up with myself as a solution for a "Cola Machine" beginner exercise I found on a website "cplusplus". The exercise problem text can be found as a multi-line comment at the top of my code. Though, I did decide to try to make my code do more than what was required of the exercise.
For the most part, this code works exactly how I want it to. At first I even struggled to figure out how to get the code to repeat the user input in the line switch (cin.get()), if they had entered an invalid answer, but I solved this issue by nesting the "switch" statment inside of a "for" statement, for (int x = 0; x < 1; x++), and having the invalid answers decrement the counter ( x--; ). Not sure if that's a practical solution, but it's the one I came up with.
The only time my program doesn't run as intended is when a multiple character input that contains both valid answers and invalid answers is entered into the program (i.e. "-1" or "17"). The latter example outputs the statement for only the valid part of the answer, the statement for case '1', where as the former example outputs the statements for invalid answers and valid answers, so the default case and case '1'. Example for input "-1"
I'm wondering if that's just a problem that is inherent to using using "switch" statements in general, or if there's a practical solution I've yet to learn. I'm using a book to learn how to code, "C++ How To Program" by H.M. Deitel/P.J. Deitel, and they had given me a sample code for a letter grade counting program that can be found in my previous question on here. And I found that this same problem occurs in that sample code.
I'd be happy to hear any and all solutions, thank you ! :)
/* Write a program that presents the user w/ a choice of your 5 favorite beverages (Coke, Water, Sprite, ... , Whatever).
Then allow the user to choose a beverage by entering a number 1-5.
Output which beverage they chose.
>> Modify the program so that if the user enters a choice other than 1-5 then it will output "Error. choice was not valid, here is your money back." */
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
int main()
{
string drink1 = "Water", drink2 = "Coke", drink3 = "Pepsi",
drink4 = "Orange Juice", drink5 = "Powerade";
string choose_text = "\n\nChoose your preferred drink: ", chosen_text = "\nYou have chosen: ";
cout << "1.) " << drink1.append(17 - drink1.length(), ' ') << "2.) " << drink2.append(17 - drink2.length(), ' ')
<< "3.) " << drink3.append(17 - drink3.length(), ' ') << "4.) " << drink4.append(17 - drink4.length(), ' ')
<< "5.) " << drink5.append(17 - drink5.length(), ' ') << choose_text;
for (int x = 0; x < 1; x++) {
switch (cin.get()) {
case '1':
cout << chosen_text << drink1 << endl;
break;
case '2':
cout << chosen_text << drink2 << endl;
break;
case '3':
cout << chosen_text << drink3 << endl;
break;
case '4':
cout << chosen_text << drink4 << endl;
break;
case '5':
cout << chosen_text << drink5 << endl;
break;
case '\n': case ' ':
x--;
break;
default:
cout << "\nError. Choice was not valid.\nPlease enter an option 1 - 5." << choose_text;
x--;
break;
}
}
return 0;
}
You can do this:
int answer;
cin >> answer;
That will retrieve an integer value from the user instead of a single character. That solves part of your problem.
Now, let's look at your loop. Ick. Let's try this:
bool keepWorking = true;
do {
keepWorking = false;
int answer;
cin >> answer;
switch (answer) {
...
set keepWorking to true on the bad answers
}
} while (!cin.eof() && keepWorking);

A few errors - trying to convert Roman entry to Decimal

Just going to change my question for now - I could just use some guidance as to why I have three compiler errors in my program, not quite sure what I did wrong/am missing - I have added comments into the code just to state where they are. Thanks
#include <iostream>
#include <string>
using namespace std;
class romanType
{
public:
void setRomanNum(string store);
// this function will store the Roman numeral
int convertNum(char rNum);
// this function will convert the Roman numeral to a decimal
void decimalPrint(int total);
// this function will print the decimal number
void romanPrint(char rNum);
// this function will print the Roman numeral
int getNum(char letter);
// this function will get the number input
romanType(int store);
//Constructor with parameter
romanType();
char roman[7];
string num;
int length = 0;
string dNum;
int equals;
};
romanType::romanType(int store)
{
dNum = 1;
}
void romanType::setRomanNum (string store)
{
dNum = store;
}
void romanType::romanPrint(char rNum)
{
cout << "The Roman numeral is: " << roman << endl;
}
void romanType::decimalPrint(int total)
{
cout << "The Decimal number is: " << equals << endl;
}
int romanType::convertNum (char rNum)
{
int letter;
int totalNum = 0;
for (int i = 0; i< dNum.length(); i++)
// "loop will run at most once (loop increment never executed)"?
{
switch (roman[i])
{
case 'M':
totalNum+= 1000;
break;
case 'D':
totalNum += 500;
break;
case 'C':
totalNum += 100;
break;
case 'L':
totalNum += 50;
break;
case 'X':
totalNum += 10;
break;
case 'V':
totalNum += 5;
break;
case 'I':
totalNum += 1;
break;
}
totalNum = totalNum + letter;
equals = totalNum;
return equals;
}
};
// "control may reach end of non-void function"
int main()
{
romanType output;
int rNumeral;
char entry;
cout << "Please enter a Roman numeral (Capitalized only): " << endl;
cin >> rNumeral;
cout << "Print Decimal or Roman Numeral? Type 1 for Decimal, 2 for Roman Numeral: " << endl;
cin >> entry;
if (entry == '1')
{
cout << "You chose to view the decimal conversion." << endl;
output.decimalPrint(rNum);
// How do I output the decimal conversion from the void romanType::decimalPrint(int total) function?
}
else if (entry == '2')
{
cout << "You chose to view the Roman numeral." << endl;
output.romanPrint(rNumeral);
}
else
cout << "Error: bad input" << endl;
return 0;
exit(1);
}
The mistake in the algorithm is that the Roman system is non-positional. See en.wikipedia.org/wiki/Roman_numerals and en.wikipedia.org/wiki/Subtractive_notation. You can't just add up consequent digits (i.e. letters) but you also have to identify and account for the cases when subtraction takes place.
why am I getting the error "no matching constructor for initialization of "roman type"?
Because the only provided constructor is not the default one, but takes one parameter of type int. Since such a constructor was provided, the default constructor wasn't generated by the compiler. Define romanType::romanType() or change the existing one to romanType::romanType(int i = 0) (add a default parameter). See Is there an implicit default constructor in C++? and why default constructor is not available by default in some case
expected expression?
Provide braces around the preceding else block. More than one statement -> braces required.
if (entry == '1') {
cout << "You chose to view the decimal conversion." << endl;
output.decimalPrint(rNum);
} else if (entry == '2')
cout << "You chose to view the Roman numeral." << endl;
output.romanPrint(rNumeral);
}
"control may reach end of non-void function"
This is a warning only, but it will turn into an error if you include the -Werror flag that tells the compiler to treat all warnings as errors.
Ok I was wrong on this one. Actually the trick is that it is (in theory) possible that the romanType::convertNum(int) function follows a route where the for loop will never get executed and thus no return statement will be executed either. That's bad since the function is declared to return int hence there must be present an explicit return statement that (surprise) would return a value. Move the return out of the loop. This error is also closely related to the next one, discussed below.
"loop will run at most once (loop increment never executed)"?
This is because the return statement is placed incorrectly: inside the for loop not outside of it, and inside the function body. Hence the loop runs once and the function returns. Move the return statement. Credit to #ATN_LR_boom for noticing this!
Also, please get in the habit of formatting code properly. It will save you a lot of headache down the way.
Other than that, I'd use a std::map for the conversion function, it's shorter and more clear to the reader compared to the switch statement. Something along the lines of
int romanType::convertNum(int rNum) {
const static std::map<char, int> conversion = {
{'M', 1000},
{'D', 500},
// more mappings
{'I', 1}
};
if ((auto it = conversion.find(rNum)) != conversion.end())
return it->second;
else
return -1;
}
Your logic for the switch is wrong, try something like this:
int totalNum = 0;
for (int i = 0; i< dNum.length(); i++)
// the loop ran once because you were returning values when catching a letter
{
switch (roman[i])
{
case 'M': // roman[i] is a char, the cases should try to catch chars
totalNum += 1000; // increment your global number
break;
case 'D':
totalNum += 500;
break;
...
}
return totalNum;

C++ switch statement odd output

I'm working on a final assignment for an Intro to C++ course. What I've coded so far works, but it's producing some interesting output that I'm looking for clarification on. Here's my code:
(Caveat: Yes, I know using void main() sucks, but we're using Visual Studio in class, and this is the instructors preference.)
#include <string>
#include <iostream>
using namespace std;
void conversion(int);
void main()
{
int decimal_number, answer;
cout << "Please enter a whole decimal number (e.g. 20): ";
cin >> decimal_number;
if (decimal_number == 0)
{
answer = 0;
cout << "The hexadecimal value of your number is: " << answer;
getchar();
getchar();
}
else if (decimal_number < 0)
{
cout << "INVALID ENTRY" ;
getchar();
getchar();
}
else if (decimal_number > 0)
{
conversion(decimal_number);
}
getchar();
getchar();
}
void conversion (int decimal_number)
{
int count = 0, remainder, reverse_order;
char hexadecimal_number[10] = { NULL };
while (decimal_number != 0)
{
remainder = decimal_number % 16;
switch (remainder)
{
case 0:
hexadecimal_number[count] = '0';
count++;
break;
case 1:
hexadecimal_number[count] = '1';
count++;
break;
case 2:
hexadecimal_number[count] = '2';
count++;
break;
case 3:
hexadecimal_number[count] = '3';
count++;
break;
case 4:
hexadecimal_number[count] = '4';
count++;
break;
case 5:
hexadecimal_number[count] = '5';
count++;
break;
case 6:
hexadecimal_number[count] = '6';
count++;
break;
case 7:
hexadecimal_number[count] = '7';
count++;
break;
case 8:
hexadecimal_number[count] = '8';
count++;
break;
case 9:
hexadecimal_number[count] = '9';
count++;
break;
case 10:
hexadecimal_number[count] = 'A';
count++;
break;
case 11:
hexadecimal_number[count] = 'B';
count++;
break;
case 12:
hexadecimal_number[count] = 'C';
count++;
break;
case 13:
hexadecimal_number[count] = 'D';
count++;
break;
case 14:
hexadecimal_number[count] = 'E';
count++;
break;
case 15:
hexadecimal_number[count] = 'F';
count++;
break;
default:
cout << decimal_number << "+++ " << hexadecimal_number;
cout << "INVALID ENTRY";
getchar();
getchar();
}
decimal_number = decimal_number / 16;
}
cout << "The hexadecimal value of your number is: ";
for (reverse_order = count -1; reverse_order >= 0; reverse_order--)
{
cout << hexadecimal_number[reverse_order];
}
getchar();
getchar();
}
So, like I said: my code works. I can take any number input as a decimal, and convert it to its hexadecimal equivalent. However, I've found that I've had to include an IF statement within the main function of the code, because if the user inputs anything other than a decimal number into the decimal_number variable, the program will store a string of decimal numbers, into decimal_number, and I have no idea where those numbers come from. They don't appear to be the ASCII equivalents of anything.
... If none of this makes any sense, I'm sorry. just input cout << decimal_number after the line cin >> decimal_number, then run the code and see what weird number comes out. I hope that makes things clearer.
Anyway, my instructors stumped, and I'm stumped. I've got the above workaround in place that the instructor will accept, but for my own sanity, I just want to figure out what's going on. Any help or pointers is appreciated. Cheers!
You can test whether the result of cin >> decimal_number succeeded, like
if(!(cin>>decimal_number))
throw std::runtime_error("Oops, not a decimal number!");
This is a bit too extreme, you can also validate the input:
while(!(cin>>decimal_number))
{
std::cout << "Not decimal, input again ";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
If you're not performing this kind of validation, then you leave the stream in an invalid state whenever reading a non-decimal, and the variable you think you're reading into will end up un-initialized.
However, I've found that I've had to include an IF statement within the main function of the code, because if the user inputs anything other than a decimal number into the decimal_number variable, the program will store a string of decimal numbers, into decimal_number, and I have no idea where those numbers come from.
Well, you did not initialise decimal_number to anything, and you do not have any error checking around the cin >> decimal_number call. So I'm not sure what else you expected but an unspecified value for decimal_number!
Your instructor should know this. It's worrying that, on top of teaching you to write code that is ill-formed per the International Standard (void main!!), they failed to discover this problem or note that you have no error checking.
What's the point of the assignment?
The conversion can be simplified to:
cout << hex << decimal_value << endl;
Or if you need it in a string:
std::string convert_decimal_to_hex_string(int decimal_value)
{
std::ostringstream output;
output << hex << value;
return output.str();
}
I believe the class should show you how to use std::string and existing language features (such as the hex manipulator). Using char for a string is dangerous.
Also, since you don't know the size or limit of the decimal values, you will need to dynamically allocate (i.e. during run-time) the array holding the characters. Think about allocating 2 characters and entering the value 1024; buffer overflow.
Change your program to use std::string. Refrain from character (C-Style) arrays.

Cannot return to userinput line and cannot print out the board

I have been working for an hour on this function. I try to get the return to go back to the user question "Enter the size board" when it goes to 2nd for statement, but it ends the program instead. Other issue is the program stops on the line, "int makeBoard[row][column];" when I ran the debug so therefore it causes not to print out the board. Whats up with that??
void showBoard()
{
int i;
int boardSize;
if(i > 3 || i < 13)
{
cout << "Enter the size board you want, between 4 and 12: ";
cin >> i;
cout << "The number you entered is: " << i;
if(i < 4 || i > 12)
{
cout << "\nYou entered the invalid number, read the direction again.\n";
return;
}
cout << " ";
cout << "\nGame ends when you reach 1024.\n";
}
int row = boardSize;
int column = boardSize;
int x, y;
int makeBoard[row][column];
for(x = 0; x < row; x++)
{
for(y = 0; y < column; y++)
{
makeBoard[x][y] = '.';
printf(" %c", makeBoard[x][y]);
}
printf("\n\n");
}
}
The following, critical, variables are not initialize: i and boardSize.
If you do manage to get past the first if statement, nothing initializes the boardSize variable.
Edit 1:
The variable i is only used to annoy the program. It is not assigned to anything.
Edit 2:
Your board is declared to be signed integers, but you assign it characters. Shouldn't it be declared a board of characters?
Edit 3: -- Printing the board
If you add an additional column to the board, you could use the last column to hold '\n'. That way you would only need one print statement for each row.
Edit 4: putchar vs. printf
If you know you are printing a character, use putchar rather than printf. The printf function has extra overhead because it has to parse the formatting string. The putchar function takes the character and writes it to the output; no formatting required, more efficient.
If you propagate this idea, you could append another row. The first column of this row would contain '\0'. This change, combined with the above, allows you to print the board with one print statement and no for loop. Wow!
The input you have asked to the user ,was for variable "i". Whereas,row and coloumn are given value of uninitialized variable "Boardsize".
You need to put "Boardsize" at the place of the "i" or vice versa.
and also in the conditional statement for handling error, you have used return ,whereas you are not returning any value....so for that case I recommend you to use "cin>>boardsize; " at the place of "return" to handle error more precisely.
Makeboard array needs to be of char type to print '.' or as int, the block will print "46",which is ASCII value of '.'
int main() {
int boardSize;
if(boardSize > 3 || boardSize < 13) {
cout << "Enter the size board you want, between 4 and 12: ";
cin >> boardSize; // take input for boardsize ,not i
cout << "The number you entered is: " << boardSize;
if(boardSize < 4 || boardSize > 12)
{
cout << "\nYou entered the invalid number, read the direction again.\n";
cin>>boardSize; // change return by this statement
}
cout << " ";
cout << "\nGame ends when you reach 1024.\n";
}
int row = boardSize; //earlier the problem was in this line
int column = boardSize; //also here
int x, y;
char makeBoard[row][column]; // also you need this array of char data type to print '.'
for(x = 0; x < row; x++) {
for(y = 0; y < column; y++) {
makeBoard[x][y] = '.';
cout<<makeBoard[x][y];
}
printf("\n\n");
}
getch();
return 0;
}
It seems to me as if you don't understand exactly what the 'return' keyword is designed to do. Similarly, your code has many mistakes in it. I'd suggest reading a tutorial or C++ book.
Return is designed to exit the current function (i.e. if you have return at the beginning of the function, it would literally do nothing).
Also, it's a mistake to not initialize your variables upon declaring them. Instead of int i; consider int i=-1;. Otherwise, the result will be undefined. i could be equal to 10 or 100000 or -20002393.
int i=-1;
while(true) // Do this forever
{
cout << "Enter the size board you want, between 4 and 12: ";
cin >> i;
cout << "The number you entered is: " << i;
if(i < 4 || i > 12)
{
cout << "\nYou entered the invalid number, read the direction again.\n";
}
else break; // You can leave the loop!
}
cout << " ";
cout << "\nGame ends when you reach 1024.\n";
This isn't the best way to do it, but I hope it gives you an idea. Also, please go through some tutorials before you post rather basic questions. It doesn't appear as if you have a basic understanding of C++ at this time. But, best of luck and hope I could help!

C++: Get char after space character instead or return carriage

Okay this is similar to my last question but what I ended up doing was way too complex for something as simple as this. I simply need to get a single character or number (I will know which of these I am receiving) from the console after I press space, instead of pressing enter. I'm sure there must be a way to have the terminal read input after a space instead of a '\n'. I need to read inputs from the console in which the succeeding data types will vary depending on what the first input is, and I think reading the entire line, parsing it into strings, then parsing some of those into ints is a bit unnecessary.
So Is this actually not possible in C++ or have I just not found it yet?
EDIT:
For anyone who has had this problem I'm posting my solution, because I feel like an idiot now.
#include <iostream>
using namespace std;
int main() {
int command = 0, x = 0, y = 0, z = 0;
char c;
do {
cin >> command;
switch(command) {
case 1:
cin >> c >> x;
cout << c << " " << x << endl;
break;
case 2:
cin >> x >> y >> z;
cout << x << " " << y << " " << z << endl;
break;
}
} while (command); //Exits when command = 0;
return 0;
}
The following cin's inside the switch statement will read from the same buffer as the first cin, so there is no need to read what the command is beforehand anyway. As you can see this works fine for different types and amounts of inputs after the first cin, so there's no need to use any other solution.
Just posting this for anyone else who may have the same problem, and not a great understanding of the way cin works.
Just issue multiple calls to getchar() (or getch()) in a loop and check the input every iteration.
Something like this (untested but should work):
int loop = 1
int spacehit = 0
char last_c = 0;
while(loop)
{
char c = getchar();
switch(c)
{
case ' ':
spacehit = 1;
printf("hit '%c' before 'space'!\n", last_c);
break;
case 'x':
printf("hit 'x' after 'space'!\n");
spacehit = 0;
break;
case 27: // escape
loop = 0;
break;
default:
// do something, e.g. append the key in c to a string
break;
}
last_c = c;
}
Edit: Added some code to print the char before hitting space in case that's what you were looking for.