I have a program that takes input for names and outputs the last names in a string. The task I have now is to include FileIO in it. Specifically, "get user input for the filename, and then read the names from the file and form the last name string."
When I run the program, the console will show the name string from the text file. But only initially. As you keep entering names, that string disappears. Also, my user input for file name seems to be doing nothing, because I can enter anything and it still show the string of last names from the text file.
Here is what I have so far. Included all of it, just to make sure.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
// function declerations
int Menu();
void getName(vector<string> &names, int &count);
void displayName(vector<string> &names, int count);
string getLastNames(vector<string> &names, int count);
int main()
{
vector<string> names;
int count = 0;
int choice = Menu();
ifstream File;
string line;
cout << "Enter file name: ";
getline(cin,line);
File.open("File.txt");
while(File.good()){
getline(File,line);
cout << line << endl;
}
File.close();
while (choice != 0)
{
// switch statement to call functions based on users input
switch (choice)
{
case 1: {
getName(names, count);
} break;
case 2: { displayName(names, count); } break;
case 3: {
cout << getLastNames(names, count) << endl;
} break;
case 0: {
return 0;
} break;
}
choice = Menu();
}
return 0;
}
// function definition for vector of strings
void getName(vector<string> &names, int &count)
{
string name;
// get input for name
cout << "Enter name: ";
getline(cin, name);
// find position of space in string
int pos = name.find(' ');
// reverse order of name
if(pos != -1) {
string first = name.substr(0, pos);
string last = name.substr(pos+1);
name = last + "," + first;
}
// add name to end of vector
names.push_back(name);
count++;
}
// give user option of what to do
int Menu() {
int choice;
cout << "1. Add a name" << endl;
cout << "2. Display names " << endl;
cout << "3. Show all Last Names" << endl;
cout << "0. Quit" << endl;
cout << "Enter a option: ";
cin >> choice;
// if outside of above choices, print 'choice not on list'
while (choice < 0 || choice > 3)
{
cout << "Choice not on list: ";
cin >> choice;
}
cin.ignore();
return choice;
}
// defining function that gets last names
string getLastNames(vector<string> &names, int count) {
stringstream ss;
for (int i = 0; i<count; i++)
{
int pos = names[i].find(',');
if (pos != -1) {
ss << "\"" << names[i].substr(0, pos) << "\", ";
} else {
ss << "\"" << names[i] << "\", ";
}
}
return ss.str();
}
// display the names
void displayName(vector<string> &names, int count)
{
if (count == 0)
{
cout << "No names to display" << endl;
return;
}
for (int i = 0; i<count; i++)
{
cout << names[i] << endl;
}
}
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);
So I am working on a switch inside of a while loop. And it is not behaving properly. When I select 'l' and load the file it lets me select again, then when I try and press 'p' to print it, it just keeps looping over the selection prompt. I am pretty sure it is because choice != 'q', but don't know how to fix it.
Thank you for any help.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
//create a struct called Weather
struct Weather {
int month;
int date;
int high;
int avg;
int low;
double precip;
string event;
};
//function prototypes
int loadData(ifstream &file, Weather days[1000]);
void printData(Weather days[1000], int count);
int main() {
// declare variables
Weather days[1000];
ifstream inFile;
string checker;
char choice = '0';
int month = 0, count;
string path;
cout << "Welcome to the weather analyzer!" << endl;
while (choice != 'q') {
cout << "Would you like to (l)oad data, (p)rint data, (s)earch data, (o)rder the data, or (q)uit? ";
cin >> choice;
cout << endl;
switch (choice) {
case 'l':
// promt user for file path
cout << "Please enter the file path: ";
cin >> path;
// open the file
inFile.open(path);
// checks to see if file successfully opened and terminates if not
if (!inFile) {
cout << "Bad Path";
getchar();
getchar();
return 0;
}
loadData(inFile, days);
count = loadData(inFile, days);
break;
case 'p':
printData(days, count);
break;
case 's':
case 'o':
case 'q':
cout << "Good bye!";
break;
default:
cout << "Invalid option";
}
}
// Close file.
inFile.close();
// Pause and exit.
getchar();
getchar();
return 0;
}
//loading function
int loadData(ifstream &inFile, Weather days[1000]) {
string checker;
int month = 0;
int i; //i varaiable keeps track of how many lines there are for the print function
for (i = 0; !inFile.eof(); i++) {
inFile >> days[i].date; // gets date and checks if it is 2017 with if loop
if (days[i].date == 2017) {
getline(inFile, checker);
getline(inFile, checker);
inFile >> days[i].date; //gets correct date value
month++;//increments month counter
}
days[i].month = month;//gets and stores data from file into days
inFile >> days[i].high
>> days[i].avg
>> days[i].low
>> days[i].precip;
getline(inFile, days[i].event);
}
return i; //returns amount of days
}
// printing function
void printData(Weather days[1000], int count) {
for (int i = 0; i < count; i++) {
cout << days[i].month << " "
<< days[i].date << " "
<< days[i].high << " "
<< days[i].avg << " "
<< days[i].low << " "
<< days[i].precip << " "
<< days[i].event << " ";
cout << endl;
}
}
After reading the user input with cin, you probably want to flush the cin buffer:
cin.clear();
cin.ignore(INT_MAX);
I have written this code and I am supposed to read in a txt file and read every other line in the txt file to the string array bookTitle[ARRAY_SIZE] and the other every other line to bookAuthor[ARRAY_SIZE]. Here is my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int ARRAY_SIZE = 1000;
string bookTitle [ARRAY_SIZE];
string bookAuthor [ARRAY_SIZE];
int loadData(string pathname);
void showAll(int count);
//int showBooksByAuthor (int count, string name);
//int showBooksByTitle (int count, string title);
int main ()
{
int number, numOfBooks;
char reply;
string bookTitles, authorName, backupFile;
cout << "Welcome to Brigham's library database." << endl;
cout << "Please enter the name of the backup file:";
cin >> backupFile;
numOfBooks = loadData (backupFile);
if (numOfBooks == -1) {
cout << endl;
} else {
cout << numOfBooks << " books loaded successfully." << endl;
}
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All:";
cin >> reply;
do {
switch (reply) {
case 'a':
case 'A':
cout << "Author's name: ";
cin >> authorName;
showBooksByAuthor (numOfBooks, authorName);
cout << endl;
break;
case 'q':
case 'Q':
cout << endl;
break;
case 's':
case 'S':
showAll(numOfBooks);
break;
case 't':
case 'T':
cout << "Book title: ";
cin >> bookTitles;
showBooksByTitle(numOfBooks, bookTitles);
cout << endl;
break;
default:
cout << "Invalid input" << endl;
break;
}
} while (reply != 'q' && reply != 'Q');
while (1==1) {
cin >> number;
cout << bookTitle[number] << endl;
cout << bookAuthor[number] << endl;
}
}
int loadData (string pathname){
int count = 0, noCount = -1;
ifstream inputFile;
string firstLine, secondLine;
inputFile.open(pathname.c_str());
if (!inputFile.is_open()) { //If the file does not open then print error message
cout << "Unable to open input file." << endl;
return noCount;
}
for (int i = 0; i <= ARRAY_SIZE; i++) {
while (!inputFile.eof()) {
getline(inputFile, firstLine);
bookTitle[i] = firstLine;
getline(inputFile, secondLine);
bookAuthor[i] = secondLine;
cout << bookTitle[i] << endl;
cout << bookAuthor[i] << endl;
count++;
}
}
return count;
}
void showAll (int count) {
for (int j = 0; j <= count; j++) {
cout << bookTitle[j] << endl;
cout << bookAuthor[j] << endl;
}
}
So I have the loadData function which I am pretty sure is my problem. When I have it print out each string[ith position] while running the loadData function it prints out each title and author just as it appears in the txt file. But then when I run the void showAll function which is supposed to be able to print the entire txt doc to the screen it doesn't work. Also just I checked to see if the strings were actually stored in memory and they were not. (After my do while loop I have a while loop that accepts input of type int and then prints the string array of the [input position]. This prints nothing. So what do I have to do to actually store each line to a different position in the string array(s)? Feel free to correct my code but it isn't pretty yet considering I still have two functions that I haven't done anything too. (Commented out).
You main problem is that you try to read you data using two loops rather than just one! You want read until either input fails or the array is filled, i.e., something like this:
for (int i = 0;
i < ARRAY_SIZE
&& std::getline(inputFile, bookTitle[i])
&& std::getline(inputFile, bookAuthor[i]); ++i) {
}
The problem with the original code is that it never changes the index i and always stores values into the cell with index 0. Since the input isn't checked after it is being read, the last loop iteration fails to read something and overwrites any earlier stored value with an empty value. Once reading of the stream fails the outer loop iterates over all indices but doesn't do anything as the check to the inner loop is always false.
So I know this is probably me going out on a limb but I am very new to C++ and am having difficulties writing this program. So anyways basically I have this program that is like a simple weather station. It prompts the users to input a name and how many weather histories they would like to store which sets the size of the array. After that they can input values for the weather data, print the current data, and print the ones in the history. But the issue I am having is that when the array is full and the user wants to enter more data it should simply copy all the values of the array over to the left deleting the first value at spot 0 and places new value at end. The weirdest thing is that when I run this and enter a odd number array size like 3 or 1 it works fine like it should and shifts values. But when I run it with an array value the is even like 2 or 4 it crashes. I tried debugging it but could not come across where the mistake is. Any help? Its all sloppy sorry, but I was also forced to declare everything in main and make pointers.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
void askName(string &weatherString){
int size = 0;
//Asks the user to input a name for weather statation
cout << "Please enter the name of the Weather Station, then press enter." << endl;
getline(cin, weatherString);
size = weatherString.length(); //gets tge length of the string just inputed
//loop is to limit the amount of characters the user can input
while (size >= 31) {
cout << "The maximum characters allowed is 30, please try again.";
cout << "Please enter the name of the Weather Station, then press enter." << endl;
getline(cin, weatherString);
size = weatherString.length(); //gets the amount of charaters from the string
}
}
void arraySize(int &i){
string myString;
loop:
while (cout << "How many histories would you like to store?" << endl && getline(cin, myString) &&
!(stringstream(myString) >> i)) {
cout << "That is an Invalid input, press enter to try again.\n";
cin.clear(); //clears invalid
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discards the
}
if (i <= 0){
cout << "Value needs to be greater than 0, try again." << endl;
goto loop;
}
}
void printWelcome(string &weatherString){
//Once the weather station name is subbmitted it is then printed
cout << "\nWelcome to The " + weatherString + " Weather Station" << endl;
}
int getTemperature(int ¤ttemp, int &i, int temp[], int &n){
string myString;
cout << "\n";
//Tells user to input temperature but checks to make sure it is a valid input
temploop:
while (cout << "Please enter the current temperature (In degrees Fahrenheit), then press enter." << endl && getline(cin, myString) &&
!(stringstream(myString) >> currenttemp)) {
cout << "That is an Invalid input, press enter to try again.\n";
cin.clear(); //clears invalid
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discards the input
}
//If statements makes sure that the user input is in a reasonable range
int maxtemp = 200;
int mintemp = -100;
if (currenttemp > maxtemp){
cout << "You must have melted, try again." << endl;
goto temploop;
}
else if (currenttemp < mintemp){
cout << "You must be frozen, try again." << endl;
goto temploop;
}
if (n < i){
temp[n] = currenttemp;
n++;
}
else{
for (int s = 0; s < n; s++){
temp[s] = temp[s + 1];
}
n = i - 1;
temp[n] = currenttemp;
n++;
}
return currenttemp;
}
void windFunction(int ¤tWindspeed, string &windDirection, int &i, int wind[], string direction[], int &m, int &p){
string myString;
//Asks the user to input windspeed but checks to see if the input is valid
windloop:
while (cout << "Please enter the current wind speed (in MPH), then press enter." << endl && getline(cin, myString) &&
!(stringstream(myString) >> currentWindspeed)) {
cout << "That is an Invalid input, press enter to try again.\n";
cin.clear(); //clears input
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discards the input
}
//Checks to make sure the input is in a reasonable range or goes back to the loop
int minwind = 0;
int maxwind = 300;
if (currentWindspeed > maxwind){
cout << "You must have blown away, try again." << endl;
goto windloop;
}
else if (currentWindspeed < minwind){
cout << "No such thing as negative wind speed, try again." << endl;
goto windloop;
}
//checks to verify that the string value has not been altered from default before placing into arrray
if (m < i){
wind[m] = currentWindspeed;
m++;
}
else{
for (int s = 0; s < m; s++){
wind[s] = wind[s + 1];
}
m = i - 1;
wind[m] = currentWindspeed;
m++;
}
//Asks the user to input the current wind direction and stores it as windDirection. Checks to see if it is a valid input
while (cout << "Please enter the current wind direction in capital letters(N, NE, NW, S, SE, SW, E, W), then press enter." << endl &&
getline(cin, windDirection) && windDirection != "N" && windDirection != "NE" && windDirection != "NW" && windDirection != "S"
&& windDirection != "SE" && windDirection != "SW" && windDirection != "E" && windDirection != "W"){
cout << "That is an Invalid wind direction input, press enter to try again.\n";
cin.clear();
cin.ignore();
}
if (p < i){
direction[p] = windDirection;
p++;
}
else{
for (int s = 0; s < p; s++){
direction[s] = direction[s + 1];
}
p = i - 1;
direction[p] = windDirection;
p++;
}
}
//gets the complete weather input from user
void getWeather(int ¤ttemp, string &windDirection, int ¤tWindspeed, int temp[], int wind[], string direction[], int &i,
int &n, int &m, int &p){
getTemperature(currenttemp, i, temp, n);
windFunction(currentWindspeed, windDirection, i, wind, direction, m, p);
}
void inputMenu(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p);
void printWeather(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p){
//allows user to print the current values for the weather station as long as it has already been inputed
if (currenttemp != NULL && currentWindspeed >= 0 && windDirection.length() != NULL){
cout << "\n";
cout << "The " << weatherString << " " << "Weather Station" << endl;
cout << "Current Temperature: " << currenttemp << " " << "Degrees Fahrenheit" << endl;
cout << "Current Wind Speed: " << currentWindspeed << " MPH" << " " << windDirection << endl;
}
else{
cout << "No data has been inputed yet, please input data then try again." << endl;
inputMenu(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p); //No data found so user is sent back to option screen
}
}
void printHistory(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p){
//allows user to print the current values for the weather station as long as it has already been inputed
if (currenttemp != NULL && currentWindspeed >= 0 && windDirection.length() != NULL){
cout << "\n";
cout << "Saved readings are printed newest to oldest" << endl;
cout << "The " << weatherString << " " << "Weather Station:";
for (int a = i - 1; a >= 0; a--){
if (!direction[a].empty()){
cout << "\n";
cout << "Current Temperature: " << temp[a] << " " << "Degrees Fahrenheit" << endl;
cout << "Current Wind Speed: " << wind[a] << " MPH" << " " << direction[a] << endl;
}
}
}
else{
cout << "No data has been inputed yet, please input data then try again." << endl;
inputMenu(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p); //No data found so user is sent back to option screen
}
}
void inputMenu(int ¤ttemp, int ¤tWindspeed, string &windDirection, string &weatherString, int temp[], int wind[],
string direction[], int &i, int &n, int &m, int &p){
int finish = 0;
//Loop which asks the user for three options to pick from
while (finish == 0){
cout << "\nPlease select from the from the following number options and press enter:" << endl;
cout << "1. To input a complete weather reading" << endl;
cout << "2. To Print the current weather" << endl;
cout << "3. To Print the weather history" << endl;
cout << "4. To exit the program" << endl;
cout << "\n" << endl;
cout << "Enter your choice here: ";
cin >> finish; //takes input from user
system("CLS"); //clears screen
cin.clear();
cin.ignore();
//switch statement evaluates the user input to different cases
switch (finish) {
case 1:
do {
getWeather(currenttemp, windDirection, currentWindspeed, temp, wind, direction, i, n, m, p); //function to get the input of a complete weather reading
finish = 0; //sends user back to while loop menu
system("CLS");
} while (finish == 1);
break;
case 2:
do{
system("CLS");
printWeather(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p);
finish = 0; //sends user back to while loop menu
} while (finish == 2);
break;
case 3:
do{
system("CLS");
printHistory(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p);
finish = 0; //sends user back to while loop menu
} while (finish == 3);
break;
case 4: //exits the program
do{
//delete[temp];
//delete[wind];
//delete[direction];
exit(0);
} while (finish == 4);
break;
default:
cout << "Please enter a correct value option." << endl;
finish = 0; //invalid input will send user to the option screen
}
}
}
int main(){
string weatherString;
int currenttemp = NULL;
int currentWindspeed = NULL;
string windDirection;
int i;
int n = 0;
int m = 0;
int p = 0;
int* temp;
int* wind;
string* direction;
askName(weatherString); //runs function to ask for name of station
system("CLS"); //clears the screen
arraySize(i);
temp = new (nothrow) int[i];
wind = new (nothrow) int[i];
direction = new (nothrow)string[i];
system("CLS");
printWelcome(weatherString); //Welcome message saying name of station
inputMenu(currenttemp, currentWindspeed, windDirection, weatherString, temp, wind, direction, i, n, m, p); //text driven menu for user input choices
return 0;
}
You have an off by one error in your copy algorithm, which you have in 2 places.
Here is one of them:
for (int s = 0; s < n; s++){
temp[s] = temp[s + 1];
}
n is the length of the array. When s is equal to n-1 (the last iteration) s+1 will be equal to n, which is beyond the bounds of the array.
Also I would check against i rather than n, as i is supposed to be the length.
To fix this compare against i-1 rather than i. You need to change this in 2 places.
for (int s = 0; s < i - 1; s++){
temp[s] = temp[s + 1];
}
I don't know why it only crashes on even array lengths, maybe something to do with memory alignment (IE maybe it over allocates for the odd length), but accessing and writing to unallocated memory invokes undefined behaviour, so any response is reasonable.