how to store user input into array in C++ - c++

I am new to C++, and want to ask this basic question
what i want: user input data like 2:3American, 4:2China (this means my country team wins 2 points lose 3 points againts American. my country team win 4 points and China team win 2 points)
in console:
please input the result for your team against other teams, input negative number to exit
2:3American
4:2China
-1
result win:1
lose:1
draw:0

If there is no specific encoding is given to you by some authority, use as simple as possible. A better was "2 3 American 4 2 China". So that you only deal with a simple for loop.
The result line is not calculated. Convert each string to integer to calculate.
int main( int argc, char* argv[]) {
std::vector<std::string> arguments(argv + 1, argv + argc);
std::cout << "arguments contains \n";
for (std::vector<std::string>::iterator it = arguments.begin() ; it != arguments.end(); ++it) {
int firstPos = it->find_first_of(":");
int secPos = 0;
std::string firstInteger = it->substr(0,firstPos);
std::string secondInteger;
if ( firstInteger.compare("-1") == 0 ) {
std::cout << "breaking \n";
return 0;
} else {
std::cout << " f=<" << firstInteger << ">";
secPos = it->find_first_not_of( "012345678:", firstPos);
if ( secPos == std::string::npos )
std::cout << "not found";
std::cout << " s=<" << it->substr(firstPos+1 ,secPos-firstPos-1 ) << "> ";
std::string teamName = it->substr(secPos);
std::cout << teamName ;
std::cout << std::endl;
}
}
std::cout << '\n';
return 0;
}

I've written a code similar to this problem a long time ago. made a small change to solve your problem.
So i think this is what you want
INPUT "2:3American 4:2China -1" (SINGLE LINE)
OUTPUT as expected
#include <iostream>
using namespace std;
size_t non_int(int index,string* s)
{
int i=index;
for( i=index;i<s->length();i++){
if(s->at(i) >= '0' && s->at(i) <= '9')
{
// cout << s->at(i) << " is a Digit";
}
else{
return (i-1)<index?(std::string::npos):(i-1);
}
}
return (i-1)<index?(std::string::npos):(i-1);;
}
int main()
{
cout << "Please input the match result such as 2:3American " << endl;
string str;
std::getline (std::cin,str);
//cout<<str;// i want to see did the first user input stored in array. But seems the console..does not print out temp[0] and just skipt it
int win,lose,draw=0;
std::size_t found = 0;
string s1,s2;
int i1,i2;
std::size_t f1,f2;
while( found !=std::string::npos)
{
f1 = str.find(":",found);
if (f1!=std::string::npos){
i1 = stoi(str.substr(found,f1-found));
f2 = non_int(f1+1,&str);
if (f2!=std::string::npos){
i2 = stoi(str.substr(f1+1,f2-f1));
if(i1>i2) win++;
else if(i1<i2)lose++;
else draw++;
}
else {
cout<<"ERROR :invalid input ";
}
}
else {
//exit on -ve input
// cout<<"ERROR 45 ";
}
found = str.find(" ",found+1);
}
cout<<"win:"<<win<<"lose:"<<lose<<"draw:"<<draw<<endl;
return 0;
}

Step 1:
Define a class that represents an input token.
struct Segment
{
int myCountryScore;
int otherCountryScore;
std::string otherCountry;
};
Step 2
Define an input function that reads a Segment from a stream.
std::istream& operator>>(std::istream& s, Segment& data)
{
Segment tmp;
char sep;
int firstNumber;
bool good = false;
if (s >> firstNumber && firstNumber >= 0)
{
tmp.myCountryScore = firstNumber;
if (s >> std::noskipws >> sep >> tmp.otherCountryScore >> tmp.otherCountry >> std::skipws) && (sep == ':'))
{
// The read worked. Copy it to the output object.
data = tmp;
good = true;
}
}
if (!good) {
// If there was an error reading.
// Or we reached the end (negative number read)
// Then set the state of the stream to failure mode.
s.setstate(std::ios::failbit);
}
return s;
}
Step 3
Write a loop that reads Segments from a stream in a loop.
Segment object;
while(std::cin >> object) {
// You have correctly read an object
// Add your code to handle it here.
}
Step 3 Alternative.
Rather than read the Segment one by one you can copy them into a vector simply using a stream iterator.
std::vector<Segment> data(std::istream_iterator<Segment>(std::cin),
std::istream_iterator<Segment>());

Related

Reading stack pop/push operations by text-file input

I have a text file with the following contents:
2
S 8
push 2 push 3 push 5 push 7 pop print push 6 print
S 4
pop print push 1 print
An assignment gives:
The first line of the input file means the number of test cases. For each test case, the first character means which container adapter (Stack or Queue) that you need to use Linked lists to implement. The correct output should be:
The values in the stack : 2 3 5
The values in the stack : 2 3 5 6
The values in the stack :
The values in the stack : 1
I've written some working functions for stack and queue struct, though I am working on the input of the stack function first.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void push(int);
int pop();
void printStack();
struct Stack {
int s[100];
int top;
Stack() { top = -1; }
};
Stack st;
void push(int n) {
if (st.top == 99) {
cout << "Stack full" << endl;
}
else {
st.s[++st.top] = n;
}
}
int pop() {
if (st.top == -1) {
cout << "Stack is empty" << endl;
}
else {
return st.s[st.top--];
}
}
void printStack() {
cout << "Elements";
for (int i = 0;i <= st.top;i++) {
cout << st.s[i] << ' ';
}
cout << endl;
}
void clearStack() {
st.top = -1;
}
The main part of the code is giving me trouble. I want to read every token of the text file while keeping the line structure; e.g. being able to parse by order of line. However, I do not know the length of each line, only the number of lines. How may I read the file correctly and finish this assignment?
int main() {
std::ifstream file("input1.txt");
std::string item_name;
int numTestCases;
vector<string> file_content{};
while (std::getline(file, item_name))
{
//cout << item_name << "\n";
char str[252];
strcpy(str, item_name.c_str());
char* pch;
//cout << "str0:" << str[0] << "\n";
file_content.push_back(str);
}
cout << "printing file content:" << endl;
for (int i = 0;i < file_content.size(); i++) {
cout << file_content[i] << endl;
}
}
Okay, you basically have two distinct problems.
Read your input file so you know what actions to perform.
Implement both Stack and Queue.
So start by breaking them up. I looked at your stack code. Your problem says to use linked lists, which isn't what you're doing. Maybe that's just because you haven't gotten that far yet.
Code like this would give you the number of test cases.
std::string numCasesStr;
if (!getline(file, numCasesStr)) {
cout << "early end of file detected\n";
return;
}
int numCases = std::stoi(numCasesStr);
At this point, you can now do this:
for (int testCase = 0; testCase < numCases; ++testCase) {
std::string typeAndCountStr;
if (!getline(file, typeAndCountStr)) {
cout << "early end of file detected\n";
return;
}
char typeC = typeAndCountStr.at(0);
if (typeC == 'S') {
...
}
else if (typeC == 'Q') {
...
}
}
The harder part is parsing the next line. You're going to get input in a similar fashion, but then you have to break it into pieces. This is called tokenizing. Basically you split it at each space. What's useful is the find method on a string.
do {
size_t lastPos = 0;
size_t pos = str.find(' ', lastPos);
string thisArg;
if (pos != string::npos) {
thisArg = str.substr(lastPos, pos);
lastPos = pos + 1;
}
else {
thisArg = str.substr(lastPos);
}
// At this point, thisArg contains one argument. You still have more
// to do, but this is one way to split your string into pieces.
} while (lastPos != string::npos);
What I do with that is stuff the individual pieces into a std::vector<std::string> and now it's a lot easier to deal with. You can traverse the vector, looking at each string, and depending upon what it is, you know if you have to grab the next item in the list (like push 8 -- you get push and then you get the 8) or just use the current item.
Overall -- break the problem down into smaller pieces. For main:
Get the number of test cases
Loop from 0..testCaseCnt
Get the type of tests (stack or queue)
Get the next input
Split it into tokens broken at each space
Traverse the tokens and Do The Right Thing (tm).
Code for main to read inputs:
int main() {
int numTestCases;
vector<string> file_content{};
fstream ifs;
ifs.open("input2.txt");
if (!ifs.is_open()) {
cout << "Failed to open file.\n";
}
else {
ifs >> numTestCases;
char type;
int numberOps;
//ifs >> type;
cout << numTestCases;
for (int j = 0;j < numTestCases;j++) {
ifs >> type;
ifs >> numberOps;
if (type == 'S') {
Stack st;
clearStack();
for (int i = 0;i < numberOps;i++) {
string operation;
ifs >> operation;
if (operation == "push") {
int pushed;
ifs >> pushed;
push(pushed);
}
if (operation == "pop") {
pop();
}
if (operation == "print") {
printStack();
}
}
}
}
ifs.close();
}
}

When I input a number in char type, why i can't get a whole number?

I input a number in char type variable. like 12 or 22. but, console show me a 1 or 2.
How i get a whole number 12 ,22 in console?
#include <iostream>
int main()
{
using namespace std;
char a = 0;
cin >> a;
cout << a << endl;
return 0;
}
Here is console result.
12
1
C:\Users\kdwyh\source\repos\MyFirstProject\Debug\MyFirstProject.exe(프로세스 18464개)이(가) 종료되었습니다(코드: 0개).
이 창을 닫으려면 아무 키나 누르세요...
The reason I don't use int, string and something is because I want to get both number and Character in one variable.
So I want to see the results of combined numbers and character at the same time.
in that process i can't get a whole number.
#include <iostream>
using namespace std;
int index = 0;
constexpr int pagenum = 10;
void chapterlist(void);
void nextlist(void);
void beforelist(void);
void movechapter(char a);
int main(void)
{
char userin = 0;
bool toggle = 0;
cout << "결과를 볼 챕터를 고르시오." << endl;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cin >> userin;
if (userin == 'n')
{
backflash:
while(toggle == 0)
{
nextlist();
cin >> userin;
if (userin == 'b')
{
toggle = 1;
goto backflash;
}
else if (userin == 'n')
continue;
else
{
system("cls");
movechapter(userin);
break;
}
}
while(toggle == 1)
{
beforelist();
cin >> userin;
if (userin == 'n')
{
toggle = 0;
goto backflash;
}
else if (userin == 'b')
continue;
else
{
system("cls");
movechapter(userin);
break;
}
}
}
else
{
system("cls");
movechapter(userin);
}
return 0;
}
void chapterlist(void)
{
int x = 0;
for (x = index + 1; x <= index + 10; x++)
cout << "Chapter." << x << endl;
}
void nextlist(void)
{
system("cls");
cout << "결과를 볼 챕터를 고르시오." << endl;
index = index + pagenum;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cout << "이전 페이지로 이동: b" << endl;
}
void beforelist(void)
{
system("cls");
cout << "결과를 볼 챕터를 고르시오." << endl;
index = index - pagenum;
chapterlist();
cout << "다음 페이지로 이동: n" << endl;
cout << "이전 페이지로 이동: b" << endl;
}
void movechapter(char a)
{
cout << "선택한 Chapter." << a << "의 결과입니다." << endl;
}
In movechapter(), console show me a is 1 or 2, not 12, 22.
First, you have to understand what achar type is.
Character types: They can represent a single character, such as 'A' or '$'. The most basic type is char, which is a one-byte character. Other types are also provided for wider characters.
To simplify that, char can only hold one character.
Where as with your code, "12" is actually 2 separate characters, '1' and '2', and that's the reason it would not work.
Instead of declaring a as a char type, you could declare it as an int type, which is a type designed to hold numbers. So you would have:
int a = 0;
However, do note that int often has a maximum value of 2^31.
Or you could use std::string to store character strings. However, do note that if you wish to do any calculations to your string type, you would need to convert them to a number type first:
int myInt = std::stoi(myString);
Edit:
So I have re-checked your code after your update, there is nothing wrong with using std::string in your case. You can still check if user have input n or b by:
if (userin == "n")
Note that you would use double quotation mark, or "letter", around the content that you want to check.
On the other hand, you could use:
if(std::all_of(userin .begin(), userin.end(), ::isdigit))
To check if user have input a number.
Although char is just a number, it's presumed to mean "single character" here for input. Fix this by asking for something else:
int a = 0;
You can always cast that to char as necessary, testing, of course, for overflow.
You should be reading characters into a string, and then converting that string into an int. It would also probably make more sense to use something like getline() to read input, rather than cin >> a.
#include <string>
#include <iostream>
#include <stdexcept>
#include <stdio.h>
int main() {
std::string input_string;
/* note that there is no function that will convert an int string
to a char, only to an int. You can cast this to a char if needed,
or bounds check like I do */
int value;
while(1) {
getline(std::cin, input_string);
/* std::stoi throws std::invalid_argument when given a string
that doesn't start with a number */
try {
value = std::stoi(input_string);
} catch (std::invalid_argument) {
printf("Invalid number!\n");
continue;
}
/* You wanted a char, the max value of a `char` is 255. If
you are happy for any value, this check can be removed */
if (value > 255) {
printf("Too big, input a number between 0-255\n");
continue;
}
break;
}
printf("Number is %hhu\n", value);
}

Can't solve floating point exception in c++

This is my code.
#include <iostream>
using namespace std;
typedef struct
{
int polski;
int wf;
int matma;
}oceny;
int funkcja_liczaca(int suma, int ile_liczb, int ktory_przedmiot, oceny &temporary);
int main()
{
int suma = 0;
int temp[3];
int ile_liczb_zostalo_wprowadzonych = 0;
oceny database;
string teksty[3] = {"polski: ", "wf: ", "matma: "};
for (int i=0; i!=3; i++)
{
cout << teksty[i] << endl;
while(temp[i]!=0)
{
cin >> temp[i];
if(cin.good()) //floating point exception here. the code don't even step into this one.
{
{
suma = temp[i] + suma;
ile_liczb_zostalo_wprowadzonych++;
if(temp[i]==0){ile_liczb_zostalo_wprowadzonych--;}
}
}else cout << "error";
};
funkcja_liczaca(suma, ile_liczb_zostalo_wprowadzonych, i, database);
suma = 0;
ile_liczb_zostalo_wprowadzonych = 0;
}
cout << "output of struct members in main() \n";
cout << database.polski << endl;
cout << database.wf << endl;
cout << database.matma << endl;
return 0;
}
int funkcja_liczaca(int suma, int ile_liczb, int ktory_przedmiot, oceny &temporary)
{
if(ktory_przedmiot==0){temporary.polski=suma/ile_liczb;cout << temporary.polski << endl;}
if(ktory_przedmiot==1){temporary.wf=suma/ile_liczb;cout << temporary.wf << endl;}
if(ktory_przedmiot==2){temporary.matma=suma/ile_liczb;cout << temporary.matma << endl;}
}
It counts arithmetic average of inputed numbers untill user input 0 which ends loop. then the arithmetic average of thoose numbers is counted in the funkcja_liczaca() and it's saved into the members of struct oceny.
everything works fine but i want to implement something like "stream" check while inputing from keyboard to prevent inputing bad variables into integer type variable.
so inputing 'g' into temp[i] is causing floating point exception. the question is why? cin.good() and cin.fail() is not working.
When you want to deal with errors in the input stream, it's better to read the input line by line as a string and then attempt to extract your data from the string. If extraction of the data from the string is successful, proceed to process the data. Otherwise, attempt to read the next line of text. Here's the core logic for that.
while ( true )
{
cout << teksty[i] << endl;
std::string line;
if ( !getline(cin, line) )
{
// Problem reading a line of text.
// Exit.
exit(EXIT_FAILURE);
}
// Construct a istringstream object to extract the data.
std::istringstream istr(line);
if ( istr >> temp[i] )
{
// Extracting the number was successful.
// Add any additional checks as necessary.
// Break out of the while loop.
break.
}
// Bad input. Continue to the next iteration of the loop
// and read the next line of text.
}

How do I change the int variable in a cycle and if so is there a more efficient way?

First post ever on this site so spare my life , please.
I'm trying to do a little encryption and decryption program imitating the Enigma cipher/machine from the WW2 (enough history lessons)
So I'm trying to input a number and a letter like so : 1h 2e 3l 4l 5o ;
Because I don't use a cycle I need to write for every variable that I'm adding the number , but what do I do if I have less letters than variables?The only way I can think of is using a cycle which checks if the input is a letter or not.That's why the current code I've written only can be used for specific amount of numbers and letters...
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int opt;
cout<<"Enter 1 for encryption and 2 for decryption. "<<endl;
cin>>opt;
if(opt == 1)
{
int setting1,setting2,setting3,setting4;
char a,b,c,d;
cout<<"_________________________________________________"<<endl;
cin>>setting1>>a>>setting2>>b>>setting3>>c>>setting4>>d;
a+=setting1;
b+=setting2;
c+=setting3;
d+=setting4;
cout<<(char)a<<" "<<(char)b<<" "<<(char)c<<" "<<(char)d<<endl;
}
if(opt == 2)
{
int setting1,setting2,setting3,setting4;
char a,b,c,d;
cout<<"_________________________________________________"<<endl;
cin>>setting1>>a>>setting2>>b>>setting3>>c>>setting4>>d;
a-=setting1;
b-=setting2;
c-=setting3;
d-=setting4;
cout<<(char)a<<(char)b<<(char)c<<(char)d<<endl;
}
if(opt !=1 && opt !=2)cout<<"ERROR!"<<endl;
std::cout << "Press ENTER to continue..."<<endl;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(),'\n');
return 0;
}
Also I was told that the last 2 lines would prevent the .exec from closing after it's done doing it's thing.
I recommend inputting your data in loops (cycles). But before that is accomplished, I suggest using a structure (or class) with an overloaded stream extraction operator.
struct Number_Letter
{
int number;
char letter;
friend std::istream& operator>>(std::istream& inp, Number_Letter& nl);
};
std::istream& operator>>(std::istream& inp, Number_Letter& nl)
{
inp >> nl.number;
if (inp)
{
inp >> nl.letter;
if (!isalpha(nl.letter))
{
// Error recovery for not reading a letter
}
}
else
{
// Error recovery for failing to read number.
}
return inp;
}
Your input loop would be something like:
Number_Letter nl;
while (std::cin >> nl)
{
// process the data
}
For cryptography, you may want to keep the data as a string:
std::string message;
getline(cin, message);
for (unsigned int i = 0; i < message.length(); i += 2)
{
if (!isdigit(message[i]))
{
cerr << "Invalid message type at position " << i << endl;
break;
}
if (i + 1 > message.length())
{
cerr << "Missing letter at end of message.\n";
break;
}
if (!isalpha(message[i+1]))
{
cerr << "Invalid message type at position " << i << endl;
break;
}
}
It sounds like you're trying to check for an unknown sequence of character/integers and need a loop to do the check?
int opt;
cout<<"Enter 1 for encryption and 2 for decryption. "<<endl;
cin>>opt;
if(opt != 1 && opt != 2)
{
cout << "Error" << endl;
return -1;
}
int integer;
char character;
char again;
do
{
cout<<"_________________________________________________"<<endl;
cin>>integer>>character;
if(opt == 1) {
character+=integer;
} else if(opt == 2) {
character-=integer;
}
cout << character <<endl;
cout << "Again (Y)?: ";
cin>>again;
}while(again == 'Y' || again == 'y');
std::cout << "Press ENTER to continue..."<<endl;
std::cin.ignore( std::numeric_limits<std::streamsize>::max(),'\n');
return 0;

Is this the correct approach to do input validation with floating point values?

After spending a good amount of time researching input validation, I combined a few ideas and came up with this:
Function to check a string for a valid double...
bool isDouble(double& destination, string& source)
{ // 64 bit
bool goodValue = false;
if (!source.empty()) {
errno = 0;
char *garbage = nullptr;
destination = strtod(source.c_str(), &garbage);
if (*garbage == '\0' && errno != ERANGE)
goodValue = true;
}
return goodValue;
}
Function to check a string for a valid 32 bit integer...
bool isLong(long& destination, string& source)
{ // 32 bit (base 10)
const short BASE = 10;
bool goodValue = false;
if (!source.empty()) {
errno = 0;
char* garbage = nullptr;
destination = strtol(source.c_str(), &garbage, BASE);
if (*garbage == '\0' && errno != ERANGE)
goodValue = true;
}
return goodValue;
}
Sample Implementation
using namespace std;
int main() {
string buffer;
double value;
cout << "Enter a value: ";
getline(cin, buffer, '\n');
if (isDouble(value, buffer))
cout << "Value: " << value << endl;
else
cout << "ERROR: Invalid input\n";
return 0;
}
Can anyone comment on if I am overlooking anything with this approach?
I'm not sure about "the" correct way, but it's certainly not how I'd do it. First and probably most obvious, this chunk of code:
for (i = 0, d = 0; i < BUFFSIZE && buffer[i] != 0 && buffer[i] >= '0' &&
buffer[i] <= '9' || (buffer[i] == '.' && d == 0); i++)
if (buffer[i] == '.') ++d;
is duplicated in a couple of places (at least I think the other instance is identical, and probably should be anyway).
Second, you don't appear to allow numbers like 1e23 or -1.2, which are usually accepted as floating point.
Offhand, I think I'd use strtod to attempt to convert the input. You can use its second parameter to detect whether a conversion reached the end of the input string (if not, you'll know at least part of the input wasn't accepted). You'll then (apparently) want to check that the returned value was in the desired range.
Perhaps the strtod() function can be of help here, as it tells you how much has been converted:
const char * buf = get_raw_data(); // somehow
char * endptr;
const double value = strtod(buf, &endptr);
if (endptr != buf + std::strlen(buf)) { /* ... error ... */ }
As the source for buf you could tokenize your input with std::string token; std::cin >> token; or something like that and use token.c_str().
If it's an exercise you want, that's understandable. But otherwise, you can use istringstream to avoid reinventing the wheel:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main () {
int n,val;
string stringvalues;
stringvalues = "3.14159254 f01fhasfljk";
istringstream iss(stringvalues);
float x,y;
iss >> x;
cout << x * 2 << endl;
iss >> y;
if ( ! iss.fail() )
{
cout << y * 2 << endl;
}
else
{
cout << "second value not a number..." << endl;
}
return 0;
}