Reading string with spaces in c++ - c++

How can I read input line(type string) with whitespace? I tried getline but it goes into infinite loop. Following is my code.
#include <iostream>
#include <cstring>
#define MAX 50 //size of array
//Used G++ 4.6.3 compiler
using namespace std;
int main() {
struct Manager {
string name;
int age;
int working_years;
string phone;
int salary;
}info[MAX];
char inp; //To choose options
int array_pos = 0; //Current position in array of Manager structure
string search_name; //Manager name you want to search
cout << "Press 'i' to insert manager information or 's' to search for manager information by name or 'a' to abort: ";
cin >> inp;
while(inp != 'a') {
int search_num = 0; //array position at which search result is found
int found = 0;
if (inp == 'i' || inp == 's') {
if (inp == 'i') {
int k = array_pos;
cout << "Enter the information of the manager no "<<k+1<<" is : ";
cout << "Enter the Name : ";
//infinte loop occurs
getline(info[array_pos].name, '\n');
//cin >> info[array_pos].name;
cout<<"Enter manager age : ";
cin >> info[array_pos].age;
cout << "Enter manage working years : ";
cin >> info[array_pos].working_years;
cout << "Enter manager phone no. : ";
cin >> info[array_pos].phone;
cout << "Enter manager salary : ";
cin >> info[array_pos].salary;
array_pos++;
}
if (inp == 's') {
cout << "Enter the manager name you want to search : ";
cin >> search_name;
for(int i = 0; i < array_pos; i++) {
//using str1.compare(str2) to compare manager name
if(info[i].name.compare(search_name) == 0) { //manager name found in array of structure
found = 1;
search_num = i;
cout << "Name : " << info[search_num].name << "\n";
cout << "Age: " << info[search_num].age << "\n";
cout << "Working Years: " << info[search_num].working_years << "\n";
cout << "Phone No. : " << info[search_num].phone << "\n";
cout << "Salary : " << info[search_num].salary << "\n";
} //end of if loop for comparing string
} //end of for loop for searching
if(found == 0)
cout << "No Manager by this name exist in record" << "\n";
} //end of if loop
} //end of if loop for searching or insertion
if(inp == 'a')
break;
cout << "Press 'i' to insert manager information or 's' to search for manager information by name or 'a' to abort: ";
cin >> inp;
} //end of while loop
return 0;
}

How can I read input line(type string) with whitespace?
std::string line;
if (std::getline(std::cin, line)) {
...
}
Note that apart from checking the return value of std:getline call, you should also avoid mixing >> operator with std::getline calls. Once you decide reading the file line by line, it seems to be cleaner and more reasonable to just make one huge loop and do the additional parsing while using string stream object, e.g.:
std::string line;
while (std::getline(std::cin, line)) {
if (line.empty()) continue;
std::istringstream is(line);
if (is >> ...) {
...
}
...
}

Simplest way to read string with spaces without bothering about std namespace is as follows
#include <iostream>
#include <string>
using namespace std;
int main(){
string str;
getline(cin,str);
cout<<str;
return 0;
}

Solution #1:
char c;
cin >> noskipws; // Stops all further whitespace skipping
while (cin >> c) { // Reads whitespace chars now.
count++;
}
Solution #2:
char c;
while (cin.get(c)) { // Always reads whitespace chars.
count++;
}

Related

How can I store input after a comma as an integer?

I've been working on a program to display user input in a table and a histogram, I've got those down, but I can't figure out how to take the user input and separate it by a comma and save the first part as a string and the second as an integer. I used streams but it separates it by spaces and the string might need to have spaces in it, so that's not reliable. I also tried substrings but I need the second half to be an int. Any tips are appreciated. Thank you.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
#include <ctype.h>
using namespace std;
int main() {
string title, col1, col2, userInput, one, two;
istringstream inSS;
string lineString;
string author;
int books;
vector<string> vecAuthors;
vector<int> vecBooks;
bool inputDone;
cout<<"Enter a title for the data:"<<endl;
getline(cin, title);
cout<<"You entered: "<<title<<endl;
cout<<"Enter the column 1 header:"<<endl;
getline(cin, col1);
cout<<"You entered: "<<col1<<endl;
cout<<"Enter the column 2 header:"<<endl;
getline(cin, col2);
cout<<"You entered: "<<col2<<endl;
while (!inputDone) {
cout<<"Enter a data point (-1 to stop input):"<<endl;
getline(cin, lineString);
while (lineString.find(',') == string::npos) {
if (lineString == "-1") {
break;
}
cout << "Error: No comma in string.\n" << endl;
cout << "Enter a data point (-1 to stop input):" << endl;
getline(cin, lineString);
}
string::size_type position = lineString.find (',');
if (position != string::npos)
{
while (lineString.find (',', position+1) != string::npos) {
if (lineString == "-1") {
break;
}
cout << "Error: Too many commas in input." << endl;
cout << "Enter a data point (-1 to stop input):" << endl;
getline(cin, lineString);
}
}
one = lineString.substr(0, lineString.find(','));
two = lineString.substr(lineString.find(',') + 1, lineString.size() - 1);
inSS.clear();
inSS.str(lineString);
inSS >> author;
inSS >> books;
if (inSS.fail()) {
if (lineString == "-1") {
break;
}
cerr << "Error: Comma not followed by an integer." << endl << endl;
cout << "Enter a data point (-1 to stop input):" << endl;
getline(cin, lineString);
}
inSS.clear();
inSS.str(lineString);
inSS >> author;
if (author == "-1") {
cout<<"Finished."<<endl;
inputDone = true;
}
else {
inSS >> books;
author.pop_back();
vecAuthors.push_back(author);
vecBooks.push_back(books);
cout << "Data string: " << author << endl;
cout << "Data integer: " << books << endl;
}
}
cout<<setw(33)<<right<<title<<endl;
cout<<setw(20)<<left<<col1<<"|";
cout<<setw(23)<<right<<col2<<endl;
cout<<setfill('-')<<setw(43)<<""<<endl;
cout<<setfill(' ');
for(int i=0; i<vecAuthors.size(); ++i){
cout<<setw(20)<<left<<vecAuthors[i]<<"|"<<setw(23)<<right<<vecBooks[i]<<endl;
}
cout<<endl;
for(int i=0; i<vecAuthors.size(); ++i){
cout<<setw(20)<<right<<vecAuthors[i];
for(int k = 0; k<vecBooks[i]; ++k) {
cout<<left<<"*";
}
cout<<endl;
}
return 0;
}
Code to get the first part to a string and second part to an int:
#include <iostream>
#include <string>
int main()
{
std::string input{};
std::cin >> input;
int commaSlot{};
for (int i = 0; i < input.length(); i++) {
if (input[i] == ',') {
commaSlot = i;
break;
}
}
std::string firstPart = input.substr(0,commaSlot);
int secondPart = std::stoi(input.substr(commaSlot+1));
std::cout << firstPart << " " << secondPart;
}
because what you need is quite custom (you need comma as a separator and not space ) you can get a line and parse it as you want with the getline function of std afterwards you can separate the string on the comma (the simplest way I can think off is a simple for loop but you can use std's algorithm's also) and then you can use the stoi function to convert a string to an int ,all of them together:
std::string row{};
unsigned positionofcomma{};
std::getline(std::cin,row);
for (unsigned i=0;i<row.length();i++)
if (row[i]==','){
positionofcomma=i;
break;
}
std::string numberstring=row.substr(positionofcomma+1, row.length());
int number=std::stoi(numberstring);

How to fix ifstream syntax error, and possible loss of data conversion error in C++?

I have code from the Source.cpp file for my code. I'm in the middle of this lab which I create an inventory that tracks a camera store. It's almost completed, but I am having error C4244 (Possible loss of data using = on like 24) and error C3867 (ios::base_fail/ios::basic_ifstream). I will write "HERE" next to where the error came up since I can't tell you what line. Here is the code in question:
#include<iostream>
#include<string>
#include<fstream>
#include "LinkedList.h"
using namespace std;
int main()
{
LinkedList ll; // Creating object of linked list
struct info record;
char dataToBeRead[100];
ifstream fp;
fp.open("fileInventory.txt");
if (fp.fail) !!!HERE!!!
{
cout << "The file cannot be opened\n";
}
else
{
while (fp.open, dataToBeRead[100] != NULL) !!!HERE!!!
{
char *token = strtok(dataToBeRead, " ");
strcpy(record.camera, token);
token = strtok(NULL, " ");
record.price = atof(token);
token = strtok(NULL, " ");
record.quantity1 = atoi(token); !!!HERE!!! (possible loss of data?)
token = strtok(NULL, " ");
record.quantity2 = atoi(token);
token = strtok(NULL, " ");
ll.addEnd(record);
ll.addReverse(record);
}
int ch = 0;
char camera[50];
float price;
int quantity1;
int quantity2;
do //Must open the menu
{
cout << "1. Display the inventory in alphabetic order:\n";
cout << "2. Display the inventory in reverse alphabetic order:\n";
cout << "3. Add an item to the inventory:\n";
cout << "4. Delete an item from inventory:\n";
cout << "5. Change any info for an item:\n";
cout << "6. Exit:\n";
cin >> ch;
switch (ch)
{
case 1:
ll.showList1();
break;
case 2:
ll.showList2();
break;
case 3:
cout << "Enter camera:\n";
cin >> camera;
cout << "Enter price:\n";
cin >> price;
cout << "Enter quantity1:\n";
cin >> quantity1;
cout << "Enter quantity2:\n";
cin >> quantity2;
strcpy(record.camera, camera);
record.price = price;
record.quantity1 = quantity1;
record.quantity2 = quantity2;
ll.addEnd(record);
ll.addReverse(record);
ll.showList1();
ll.showList2();
break;
case 4:
cout << "Enter camera name to be deleted:\n";
cin >> camera;
ll.removeValue1(camera);
ll.removeValue2(camera);
ll.showList1();
ll.showList2();
break;
case 5:
cout << "Enter the camera name for which you want to edit details:\n";
cin >> camera;
cout << "Enter price:\n";
cin >> price;
cout << "Enter quantity1:\n";
cin >> quantity1;
cout << "Enter quantity2:\n";
cin >> quantity2;
ll.editList(camera, price, quantity1, quantity2);
break;
case 6:
break;
}
} while (ch != 6); // Menu will run until the ch is not 6
ofstream myfile;
myfile.open("newlist.txt");
if (myfile.fail) !!!HERE!!!
{
exit(1);
}
}
return 1;
}
It's clearly an issue with fstream but I don't know what I'm doing wrong. And I'm unsure why there would be a possible loss of data specifically on that line. Thank you in advance for your help!
Needless to say, this line:
while (fp.open, dataToBeRead[100] != NULL)
is not correct.
Also, to test if the file opened successfully or not, you could simply do this:
if (!fp)
{
// file failed to open
}
But overall, the simplest way is to not introduce char arrays at all, and instead use std::string:
std::string dataToBeRead;
while (std::getline(fp, dataToBeRead))
{
//...
}
Given that dataToBeRead is now a std::string, the logic to tokenize needs to change. That is simply done by using std::istringstream and using operator >>.
std::istringstream strm(dataToBeRead);
strm >> record.camera >> record.price >> record.quantity1 >> record.quantity2;
ll.addEnd(record);
ll.addReverse(record);
Thus the entire loop is this:
#include <sstream>
//...
std::string dataToBeRead;
while (std::getline(fp, dataToBeRead))
{
std::istringstream strm(dataToBeRead);
strm >> record.camera >> record.price >> record.quantity1 >> record.quantity2;
ll.addEnd(record);
ll.addReverse(record);
}
This is far more easier and safer than using C-style strtok processing.
You could also skip the entire creation of the string by directly reading the input using operator >>:
while (fp >> record.camera >> record.price >> record.quantity1 >> record.quantity2)
{
ll.addEnd(record);
ll.addReverse(record);
}
You usually want to use this method if the parsing of the data is simple (in your case, it is separated using spaces). If anything more complex than that, then the usage of the istringstream could be utilized.

c++ input for-loop followed by another input

c++ Microsoft visual studio on a windows.
im very new to coding. currently going through Programming -- Principles and Practice Using C++ by Stroupstrup and I came across a difficulty. I am to create a "score chart" with vector name and vector score from the user input. I used for-loop to get the input. now I am to modify the program so that with 2nd input from the user I can search the list and "cout<<" the score for a person. the problem is the the program completely ignores the 2nd "cin>>" command.
I search online and could not find a reasonable answer to this problem. Is there any special interaction between a for-loop input being terminated and another input (not looped)
syntax:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<string> name;
vector<int> score;
string temp2;
int i;
for (string temp; cin >> temp >> i;) //input terminated with "Ctrl+Z"
name.push_back(temp), score.push_back(i);
for (int i = 0; i < name.size(); ++i) {
for (int j = i + 1; j < name.size(); ++j) {
if (name[i] == name[j]) {
name[j] = "error";
score[j] = 0;
}
}
}
for (int i = 0; i < name.size(); ++i) {
cout << name[i] << "------" << score[i] << "\n";
}
cout << "name"; //this line shows in the console
cin >> temp2; //but I cannot prompt the user to input again?
return 0;
}
CTRL-Z is interpreted as "End-Of-File", such that any subsequent access to this stream will not read in items any more. The only secure way is to change program logic such that the list of names is terminated by, let's say "END", and not a CTRL-Z. Then you can continue in a save manner.
Often input from a terminal is read in line by line and parsed afterwards. This makes error handling easier. See the following code following such an approach:
#include <sstream>
int main() {
string line;
map<string,int> scoreboard;
cout << "enter name score (type END to finish):" << endl;
while (std::getline(cin, line) && line != "END") {
stringstream ss(line);
string name;
int score;
if (ss >> name >> score) {
scoreboard[name] = score;
} else {
cout << "invalid input. Type END to finish" << endl;
}
}
cout << "enter name:" << endl;
string name;
if (cin >> name) {
auto item = scoreboard.find(name);
if (item != scoreboard.end()){
cout << "score of " << name << ":" << item->second << endl;
}
else {
cout << "no entry for " << name << "." << endl;
}
}
}

C++ user input to string array infinite loop

I'm trying to parse a user input string into an array. Example: user inputs "hello to you" array[0]="hello" array[1]="to" array[2]="you' After I prompt the user to input some words, the program seems to infinitely loop. I have also tried using a vector, so it may be my logic in another area. I'm very rusty when it comes to the C language, so please excuse my ignorance. Any help would be greatly appreciated!
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct FATNode;
struct FileNode;
class FileList;
class FAT
{
FATNode* head;
};
class FileList
{
FileNode* head;
//methods
public:
int createfile()
{
string word[2];
cout << "Please input file name, followed by file size: ";
int i = 0;
for (string input; cin >> input; i++)
word[i] = input;
for(i=0; i<2; i++)
cout << word[i] << ' ';
return 0;
}
};
struct FileNode
{
string filename;
int filesize;
FAT t1;
FileNode* next;
};
struct FATNode
{
int sectornumber;
FATNode* next;
};
main()
{
FileList myFileSystem;
char start;
int cmd;
bool cont = true;
while(cont == true)
{
cout << "Initializing disk.\n" << "To access menu, type 'Y'. To exit, type 'N': ";
cin >> start;
if(start == 'y' || start == 'Y')
{
cout << "What command would you like to execute on the disk?" << endl;
cout << "1. Format disk\n2. Create file\n3. Delete file\n";
cout << "4. List\n5. Read file\n6. Overwrite file\n7. Append to file\n8. Disk status\nSelection: ";
cin >> cmd;
switch(cmd)
{
case 1 :
break;
case 2 :
myFileSystem.createfile();
break;
default :
cout << "Invalid command" << endl;
}
}
else if(start == 'n' || start == 'N')
{
cont = false;
}
else
{
cout << "Invalid input." << endl;
}
}
}
Your loop condition is cin >> input. This expression returns cin, which can be implicitly converted into a boolean (http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool). However, cin only becomes false, if there's an error or if you have reached end of file (EOF). You can signal EOF by pressing Ctrl+D.
Note also, that you are using a fixed-size array to store information that you get from the user. That's bad, because if the user enters more than 2 words, the array word will overflow. That's undefined behaviour.
If you just want a file name, followed by a file size, why don't you just use:
std::string filename;
std::size_t filesize;
std::cin >> filename >> filesize;

Finding a word in C++

I'm able to find the word in my list but I would like to display whatever number there is after the word has been found. My list has names followed by their GPA.
Example...
michael 2.3
Rachel 2.5
Carlos 3.0
I would like to add the feature of displaying the number located after the name once it's found, I declared as int GPA but I'm not sure how to incorporated in my program.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
string name;
int offset;
string line;
int gpa;
ifstream read_file;
read_file.open("alpha.dat");
cout << "Please enter your name: \n";
cin >> name;
if (read_file.is_open())
{
while (!read_file.eof())
{
getline(read_file, line);
if ((offset = line.find(name)) != string::npos)
{
cout << "the word has been found: \n";
// cout << name << gpa; example to display
}
}
read_file.close();
return 0;
}
As far as I can tell, you just need to output the line that you read from file:
while( getline(read_file, line) )
{
if ((offset = line.find(name)) != string::npos) cout << line << endl;
}
Note that this isn't the best way to find the name. For example, what if the user enters Carl? It will be found as part of the string Carlos. Or indeed, if they enter 2, it will match parts of the GPA for multiple people.
What you can do here is use a string stream to read the name out. Let's assume it contains no spaces, which would make it conform to how you are reading the user's name in. You need to include <sstream>, by the way. Note that you can read out the GPA as part of this same mechanism.
istringstream iss( line );
string thisname, gpa;
if( iss >> thisname >> gpa ) {
if( thisname == name ) cout << name << " " << gpa << endl;
}
Finally, you may want to consider ignoring case when comparing strings. The cheeky way is to just use the old C functions for this. I know there are C++ methods for this, but none are as simple as good old stricmp from <cstring>:
if( 0 == stricmp(thisname.c_str(), name.c_str()) ) {
cout << name << " " << gpa << endl;
}
You can split line using stringstream, and store it into a vector, like this:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <vector>
using namespace std;
int main()
{
string name;
int offset;
string line;
int gpa;
ifstream read_file;
read_file.open("alpha.dat");
cout << "Please enter your name: \n";
cin >> name;
if (read_file.is_open())
{
while (!read_file.eof())
{
getline(read_file, line);
if ((offset = line.find(name)) != string::npos)
{
cout << "the word has been found: \n";
stringstream iss(line);
vector<string> tokens;
string str;
while (iss >> str)
tokens.push_back(str);
cout << tokens[0] << tokens[1];
}
}
read_file.close();
return 0;
}
}
You can replace getline(read_file, line)... with:
read_file >> name >> gpa;
if (name == search_name)
cout << name << " " << gpa << endl;