How can I separate user inputted string and store it into an array - c++

I was wondering if you could help me and figure this out without using something like strtok. This assignment is meant for me to build something that will accept input and direct the user to the right area. I want to get something like....
Help Copy
and it stores it as
array[1] = Help
array[2] = Copy.
I tried to do something like cin>>arr[1]; and cin>>arr[2] but at the same time what if the user enters copy then I am not sure how to do it cause if I put just one cin then what if the user puts help copy.
Basically I am not sure how to accept any size input and store anything they put in as elements in an array.
I would try something like cin.get or getline but they don't seem to really help me and my cin idea was not helpful at all.
This is what I have so far.
int main()
{
string user;
cout<<"Hello there, what is your desired username?"<<endl;
cin >> user;
system("cls");
cout<<"Hello, " << user << "! How are you doing?"<<endl<<endl;
cout<< user << ": ";
return 0;
}

You can do it like this:
Read the entire line using getline
Make an input string stream from that line
Read the content of that string stream into a vector<string>. It will grow automatically to accommodate as many inputs as the user enters
Examine the size of the resultant vector to see how many entries the end-user made
Here is how you can do it in code:
// Prepare the buffer for the line the user enters
string buf;
// This buffer will grow automatically to accommodate the entire line
getline(cin, buf);
// Make a string-based stream from the line entered by the user
istringstream iss(buf);
// Prepare a vector of strings to split the input
vector<string> vs;
// We could use a loop, but using an iterator is more idiomatic to C++
istream_iterator<string> iit(iss);
// back_inserter will add the items one by one to the vector vs
copy(iit, istream_iterator<string>(), back_inserter(vs));
Here is a demo on ideone.

std::vector<std::string> myInputs;
std::cout << "Enter parameters: ";
std::copy(std::istream_iterator<std::string>(std::cin), std::isteram_iterator<std::string>(), std::back_inserter(myInputs));
// do something with the values in myInputs
If the user presses Enter in between each input, this will go until they cease the input (Crtl-D on Windows). If you want them to put all the parameters on a single line, you can read the input into a single string and then split the string up by spaces (or whatever delimiter you wish to use).

Related

searching a name in the csv file on C++

I am a young programmer who is trying to learn c++. i have a working csv.file. but i want to search for a specific number assigned to the name and then displays the name of what i'm looking for. i have the file here:
1,Bulbasaur,grass
2,Ivysaur, grass
3,Venusaur, grass
4,Charmander, fire
5,Charmeleon, fire
6,Charizard, fire
7,Squirtle, water
8,Wartortle, water
9,Blastoise, water
Code
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream ip("pokedex.csv");
string pokedexnum[9];
string pokemonName[9];
string pokemonType[9];
cout<<"please enter a pokemon number:"<<" ";
cin>>pokemonType[0];
while (ip.good()){
getline( ip, pokedexnum[0]);
getline( ip, pokemonName[0]);
getline( ip, pokemonType[0]);
}
cout<<"the pokemon that is:"<< " "<<pokedexnum[0]<< "is the pokemon called:"<< pokemonName[0];
ifstream close("pokedex.csv");
return 0;
}
when it runs
please enter a pokemon number: 1
the pokemon that is: is the pokemon called:8,Wartortle, water
could you please point out what i am doing wrong?
Among the issues in this code:
You're not using std::getline correctly for comma-separated data. The result is each pass is consuming three lines from your input file; not three values from each line.
You're also not using ip.good() correctly as a while-condition.
You're retaining your test value in the array, which will be overwritten on the first iteration pass, so it is lost.
You're ignoring potential IO failures with each std::getline invoke.
You're overwriting slot-0 in your arrays with each loop iteration.
Minor, ifstream close("pokedex.csv"); clearly isn't doing what you think it is. That just creates another fstream object called close on the given file name.
The later may be intentional for now, but clearly broken in the near future.
In reality, you don't need arrays for any of this. All you're doing is reading lines, and seem to want to test the input number against that of the CSV data first column, reporting the line that you find, then ending this.
So do that:
Read the input value to search for.
Open the file for scanning.
Enumerate the file one line at a time.
For each line from (3), use a string stream to break the line into the comma separated values.
Test the id value against the input from (1). If the same, report the result and break the loop; you're done.
The result is something like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdlib>
int main()
{
std::cout<<"please enter a pokemon number: ";
long num;
if (std::cin >> num && num > 0)
{
std::ifstream ip("pokedex.csv");
std::string line;
while (std::getline(ip, line))
{
std::istringstream iss(line);
std::string id, name, skill;
if (std::getline(iss, id, ',') &&
std::getline(iss, name, ',') &&
std::getline(iss, skill))
{
char *endp = nullptr;
long n = std::strtol(id.c_str(), &endp, 10);
if (id.c_str() != endp && n == num)
{
std::cout << "The pokemon that is: " << num << " is called: " << name << '\n';
break;
}
}
}
}
}
Admittedly untested, but it should work.
Whether you want to store the items in arrays at this point is entirely up to you, but it isn't needed to solve the somewhat abstract problem you seem to be attempting, namely finding the matching line and reporting the name from said-same. If you still want to store them in arrays, I suggest you craft a structure to do so, something like:
struct Pokemon
{
int id;
std::string name;
std::string skill;
};
and have a single array of those, rather than three arbitrary arrays that must be kept in sync.
Four issues jump out at me:
You store the user's input into pokemonType, but then also use pokemonType for reading data from your CSV file. The file input is going to overwrite the user input.
Your file input loop always references index 0. All of the lines from your data file are going into element 0. That's the main reason that even if the user inputs 1, the output is from the last line of the data file.
Your file reading loop is structured like you want to put one part of each data line into a different array, but what you've written actually reads three lines on every iteration, storing those lines into the three different arrays.
This isn't affecting your output, but the code ifstream close("pokedex.csv"); is written like you want to close the file stream you opened, but I do believe what this line actually does is create a new ifstream called close, and opens pokedex.csv attached to it. In other words, it's just like your other line ifstream ip("pokedex.csv"); but with close as the variable name instead of ip.
You are going to want to look into something called "string tokenization". Start with some web searches, apply what you read about to your code, and of course if you hit another snag, post a new question here to Stack Overflow, showing (as you did here) what you tried and in what way it isn't working.
Elaborating on #3, here's what how your data file is being read:
at the end of the 1st iteration of the file-reading loop, ...
pokedexnum[0] is "1,Bulbasaur,grass"
pokemonName[0] is "2,Ivysaur, grass"
pokemonType[0] is "3,Venusaur, grass"
at the end of the 2nd iteration of the file-reading loop, ...
pokedexnum[0] is "4,Charmander, fire"
pokemonName[0] is "5,Charmeleon, fire"
pokemonType[0] is "6,Charizard, fire"
at the end of the 3rd iteration of the file-reading loop, ...
pokedexnum[0] is "7,Squirtle, water"
pokemonName[0] is "8,Wartortle, water"
pokemonType[0] is "9,Blastoise, water"
And that's why
<< "is the pokemon called:"<< pokemonName[0];
outputs
is the pokemon called:8,Wartortle, water

I can`t enter values when I run my code

void Manager::ManagerView1()
{
system("cls");
string Ipass;
string Opass;
ifstream Password("Password.txt", ios::in);
if (!Password)
{
cerr << "Check File Integrity";
}
else
{
while (!Password.eof())
{
getline(Password,Ipass);
cout << "Enter Password :\n";
cin >> Opass;
if (Opass == Ipass)
{
cout << "Passwords Match";
}
}
}
}
Text inside the "Password.txt":
Abhik Ray 1123
The password is being read properly, I have already checked that.
When I run the code it lets me enter the password but then the Passwords match doesn't show up as it should. And then it again asks for the password where I am unable to enter it. And then it just quits.
What should I change?
You have several problems, like trying to match only one line from the password file at a time.
The reason for the message is that if (Opass == Ipass) compares the addresses of the character arrays, not their contents.
If you had used std::string to store the strings, the comparison would have worked, but with C style strings you need to use if(strcmp(Opass, Ipass) == 0).
You might also want to check this question for how to terminate the loop:
Why is iostream::eof inside a loop condition considered wrong?
In the new version of the code with cin >> Opass; the >> will only read one word at a time (it stops at each space). So if you type Abhik Ray 1123 you will only get Abhik in Opass, and the rest of the line will remain in the input buffer until the next read.
That's also why it doesn't ask for the next input, it just reads the following words that are already there.
To read a whole line of input, you need to use getline(cin, Opass);, just like when you read from the textfile.
Opass and Ipass are pointers and by doing Opass == Ipass you check if they point to the same area in the memory.
You have to use strcmp to compare their values.

Detect a newline character with getline or istringstream

In my program, I'm asking the user for input via getline, and then in a separate class, splitting the string into three different strings which I will then check via a list of pre-determined values.
The way it works now, if someone enters an invalid command, I display "INVALID"
The problem I'm having is with a string containing only spaces or only a single newline character.
Here is what I'm trying to do:
std::string command; // command user enters
getline(std::cin, command); // user input here
std::string tempCheck; // if we have a value in here other than empty, invalid
// use istringstream to grab the words, max of 3
std::istringstream parse{fullCommand}; // parse command into words
if(fullCommand.empty()){ // nothing has been input
std::cout << "INVALID" << std::endl;
return;
}
parse >> command; // stores first word (the command)
parse >> actionOne; // stores second word as parameter
parse >> actionTwo; // stores third word as parameter
parse >> tempCheck;
if(!tempCheck.empty()) {
std::cout << "INVALID" << std::endl;
return;
}
The variable tempCheck basically means that if it goes over three words (the limit I want for commands), then it is INVALID. I also thought that having an empty string would work, but it just ends up in an infinite loop when nothing is input, but I just hit enter.
Here is what I expect my input to be doing (bold is output):
CREATE username password
**CREATED**
LOGIN username password
**SUCCEEDED**
ASDF lol lol
**INVALID**
**INVALID**
REMOVE username
**REMOVED**
**INVALID**
QUIT
**GOODBYE**
Here is what is happening:
CREATE username password
**CREATED**
// newline entered here
And it goes into a seemingly infinite loop. I can still type things, however, they don't actually affect anything. For example typing QUIT does nothing. But, if I restart my program and just type "QUIT" without trying to only use a newline character or only use a space, I get the expected output:
QUIT
**GOODBYE**
So, how do I tell either getline, or my istringstream, that if a user just enters a bunch of spaces and then hits enter, OR if the user just hits enter, display invalid and return? And is there anyway to do this with just getline or istringstream?
Alex, the following code may be helpful:
std::string strip(std::string const& s, std::string const& white=" \t\n")
{
std::string::size_type const first = s.find_first_not_of(white);
return (first == std::string::npos)
? std::string()
: s.substr(first, s.find_last_not_of(white)-first+1);
}
You may apply it before creating the istringstream:
std::istringstream parse{strip(fullCommand)};
The above code was borrowed and slightly modified from the old well-known technique.

Parse from a file, where one of the columns has multiple value

I'm trying to load the information from a text file into a vector. However, one of the columns has multiple values in it, and I'm having problem trying to retrieve the information from there. Below is my snippet code.
The text file will have format like this:
First column will be the name, and second column will be all the classes that he is taking right now. For the second column, I create a vector to hold it, but I don't know how to do a while loop condition for it. Can anyone help me please ?
mtingley |art, music, math, history
while(getline(inUsers, textLine))
{
Student s;
string delimeter;
// put the line into buffer string
istringstream textStream(textLine);
// get userName
textStream >> userName;
// read the buffer string till '|'
getline(textStream, delimeter, '|');
cout << userName << endl;
s.SetUserName(userName);
while() // need condition in this while loop
{
textStream >> subject;
getline(textStream, delimeter, ',');
vCourse.push_back(subject);
}
}
There is a good example here: http://www.daniweb.com/software-development/cpp/threads/53349/getline-with-multiple-delimiters

C++ cout print twice in do while loop

The system did this:
Please input the Full Name of the user:Please input the Full Name of the user:
It output the string "Please input the Full Name of the user:" twice , how do i change the code to make it just cout once
string fullname = "";
do
{
cout << "Please input the Full Name of the user: ";
getline (cin,fullname);
}while(fullname.length()<1);
C++ What is causing the system to output twice
You could try flushing your input stream to get rid of leftover newlines:
std::cin.ignore(x);
(with x being the number of characters to ignore, e.g. INT_MAX).
Simple solution would be to move the std::cout statement outside of the do-while loop.
string fullname = "";
cout << "Please input the Full Name of the user: ";
do
{
getline (cin,fullname);
}while(fullname.length()<1);
You are performing an input operation without checking the result, which is a hard programming and understanding error. Do this instead:
for (std::string line; ; )
{
std::cout << "Name: ";
if (!std::getline(std::cin, line) || !line.empty()) { break; }
}
The first condition checks whether the input succeeded (which is false when the input stream is closed), and the second checks whether the read line is non-empty. The short-circuit semantics of || make the second check legal.
As others have pointed out the problem is that you have an extra '\n' character on the input stream.
Contrary to the popular answer I don't think flushing (ignore()) the current input is a good solution. You are treating the symptom not the problem. If you are using ignore() you are potentially throwing away user input that you might actually want or something that could have detected an error from the user:
> Input Your age
> 36xxxx
// If you use
std::cin >> age;
// Then sometime later in your code you use
// ignore to make sure that you have "correctly" skipped to the next new line
std::ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// You have now just ignored the fact that the user typed xxx on the end of the input.
// They were probably doing that to force an error in the code or something else erroneous
// happened but you just missed it with std::ignore()
The best solution is not to get into this situation.
This problem is caused by using a combination of operator<<() and std::getline() to parse user input. I love using operator<<() to parse normal or regular input; but manual user input (ie Question/Answer) is harder to predict and users input is line based (there input ends at the '\n' character because the buffer is flushed when they hit <enter>).
As a result when I parse manual user input I always use std::getline(). This way I know I got the whole of their answer. It also allows me to validate the input to make sure there was not a typing error.
std::cout << "What is your age\n";
std::string line;
std::getline(std::cin, line); // Get user input
// Use stream for easy parsing.
std::stringstream linestream(line);
// Get value we want.
linestream >> age;
// Validate that we have not thrown away user input.
std::string error;
linestream >> error;
if (error.length() != 0) { /* do stuff to force user to re-input value */ }