I have just started with c++ and this is for a project that I'm working on. The problem is that I am not able to return a string from the SearchFunction to main. The search function itself is working perfectly and easily finding and displaying the row its supposed to find but the string temp remains empty despite me returning a string from Search Function. As a result, the DeleteFunction is not working because its not being passed the string that it's supposed to delete.
I have tried using pointers instead of returning value but still the result is same. Please help me understand where I'm going wrong.
#include<iostream>
#include<stdio.h>
#include<string>
#include<fstream>
using namespace std;
string data,temp;
string SearchFunction(string);
void DeleteFunction(string);
int main()
{
int choice=0,choice3=0;
char yn1;
string search;
cout<<"1. Press 1 to delete."<<endl;
cin>>choice;
cin.clear();
cin.ignore(1000,'\n');
if(choice==1)
{
cout<<"Enter RegNo. of record to be deleted: ";
getline(cin,search);
search="RegNo.: "+ search; //Concatenate with "RegNo: " to ensure that the search is done "by RegNo".
temp=SearchFunction(search);
cout<<"1. "<<temp<<"\n\n";
cout<<temp.length()<<endl;
cout<<"Are you sure you want to delete the above record of"<<search<<"? Y/N";
yn1=getchar();
cin.clear();
cin.ignore(1000,'\n');
if(!(yn1=='y' || yn1=='Y' || yn1=='n' || yn1=='N'))
{
do
{
cout<<"Enter 'Y' or 'N': ";
yn1=getchar();
}while(!(yn1=='y' || yn1=='Y' || yn1=='n' || yn1=='N'));
}
if(yn1=='y' || yn1=='Y')
{
DeleteFunction(temp); //Call delete function to delete record.
}
}
return 0;
}
string SearchFunction(string search)
{
int found=0, check=0; //Declare and initialize both variables to 0.
ifstream outfile; //Create object for reading file.
outfile.open("student.txt"); //Open file.
while(!outfile.eof()) //Continue loop until the end of file.
{
found=0, check=0; //Initialize both variables to 0 again in anticipation of repititions.
getline(outfile, data); //Input one row from file to string variable data.
found=data.find(search, found); //Search for the search term in string data.
if(found!=string::npos) //If search term found.
{
cout<<data<<endl; //Display row.
}
}
outfile.close();
return data;
}
void DeleteFunction(string temp)
{
string line;
ifstream in("student.txt");
if( !in.is_open())
{
cout << "Input file failed to open\n";
}
ofstream out("temp.txt");
while( getline(in,line) )
{
if(line != temp )
out << line << "\n";
}
in.close();
out.close();
remove("student.txt");
rename("temp.txt","student.txt");
}
You have stop reading the file after you found the row you are looking for. Maybe you want to change the function to:
string SearchFunction(string search)
{
int found=0, check=0; //Declare and initialize both variables to 0.
ifstream outfile; //Create object for reading file.
outfile.open("student.txt"); //Open file.
// Also check if found!!!
while(!outfile.eof() && !found) //Continue loop until the end of file.
{
found=0, check=0; //Initialize both variables to 0 again in anticipation of repititions.
getline(outfile, data); //Input one row from file to string variable data.
found=data.find(search, found); //Search for the search term in string data.
if(found!=string::npos) //If search term found.
{
cout<<data<<endl; //Display row.
}
}
outfile.close();
return data;
}
You need to break out of the while loop when you've found your data. A simple way is to just return at that point.
Don't use globals unless you have some very good reason. Globals used as scratch-pad variables, as above, are just Evilâ„¢.
Related
I have a small project for a C++ course and I'm stuck trying to check if a value of a data member of STUDENT's class exists in the file(the "ID"). I've tried to use some function that I found on the internet to transform the integer value I'm searching for into a string and then use the find function, to search for it in each line of the file.
It works, but whenever I check one line from the file, it gets false pozitive, because the ID value(for example "12") is for example, identical to the value of age(also "12"). It does that because the age value comes before the ID value in my file and also in the string variable (and I can't change it). I don't know to search in the string for the value of ID only. I use the function "inputInfo" to input student1's member values from the keyboard, and function "checkID" to check if value of "ID" already exists in the file. Also, for another aspect of the project, I am seeking a way to search for occurrence of the ID and name data members values in the same file(once they are already written). One solution I've thought is to somehow start the search after the occurence of another character(for example the space character, given the fact that in the file, each field is delimited from another with a space), but I'm not sure the find function is able to do that.Thank you in advance for your help.Below is a part of the project's code in C++:
#include<iostream>
#include<string>
#include<fstream>
#include <sstream>
using namespace std;
int checkID(int idNumber)
{
string findID;
stringstream id_string;
id_string << idNumber;
findID = id_string.str();
int offset;
ifstream in;
in.open("Students.txt");
if(in.is_open())
{
string line;
while(getline(in, line))
{
if(offset = line.find(findID, 0)!= string::npos)
{
cout<<"The ID already exists. Insert a different ID!"<<endl;
return 0;
}
}
}
else
cout<<"File doesn't exist!"<<endl;
in.close();
}
class PERSON
{
protected:
string name;
string surname;
unsigned int age;
public:
void inputinfo()
{
cin>>name;
cin>>surname;
cin>>age;
}
outputinfo()
{
cout<<name<<endl;
cout<<surname<<endl;
cout<<age<<endl;
}
};
class STUDENT: public PERSON
{
int ID;
float marks_sum;
string belonging_class;
public:
inputInfo()
{
cout<<"Name:";
cin>>name;
cout<<"Surname:";
cin>>surname;
cout<<"Age:";
cin>>age;
do
{
cout<<"ID:";
cin>>ID;
}
while (checkID(ID)==0);
cout<<"Sum of marks:";
cin>>marks_sum;
cout<<"The belonging class:";
cin>>belonging_class;
}
void outputInfo()
{
cout<<name<<endl;
cout<<surname<<endl;
cout<<age<<endl;
cout<<ID<<endl;
cout<<marks_sum<<endl;
cout<<belonging_class<<endl;
}
friend std::ostream& operator << (std::ostream& os, const STUDENT& value )
{
os << value.name<<" "<<value.surname<<" "<<value.age<<" "<<value.ID<<" "<<value.marks_sum<<" "<<value.belonging_class<<std::endl;
return os;
}
};
STUDENT student1;
int writeInFile(STUDENT studentx)
{
ofstream os("Students.txt", ofstream::app);
os << studentx;
os.close();
}
int main()
{
int opt1, opt2;
char option;
do
{
cout<<"1 - Input data into file"<<endl<<"2 - Close program"<<endl;
cin>>opt1;
switch(opt1)
{
case 1:
do
{
cout<<endl;
cout<<"Choose one of variants"<<endl<<"1.Students"<<endl<<"2.Get back to main menu"<<endl;
cin>>opt2;
switch(opt2)
{
case 1:
do
{
cout<<"Do you wish to introduce a new student(Y/N)?";
cin>>option;
if(option!='N')
{
student1.inputInfo();
writeInFile(student1);
}
}
while (option!='N');
break;
}
}
while(opt2!=2);
break;
}
}
while(opt1!=2);
}
#include <sstream>
using namespace std;
bool isUniqueID(ifstream& file, int id)
{
string id_string = to_string(id);
string currently_read_line;
// The position of the searched key. So, in this case,
// only the 3rd value will be tested (starting from 0).
// John Doe 23 456
// | | | |
// 0 1 2 3 (the id)
int offset = 3;
while (getline(file, currently_read_line))
{
istringstream ss(currently_read_line);
string current_entry;
int counter = 0;
while (ss >> current_entry) {
if (current_entry == id_string && counter == offset) {
cout << "The Id already exists." << endl;
return false;
}
counter++;
}
}
// No match found
cout << "The ID does not exist yet." << endl;
return true;
}
Please note:
Just pass your opened file to the function. The file is opened once, instead of opening it every time you want to check an ID.
This requires to compile in -std=c++11 (for the to_string conversion)
[Update]
The offset variable tells the function what value to test for. A more consistent way to do this, would be to format the data as to have a key/value for each student entry. It works as it though.
One of the things my program needs to do is validate a file using the isValid function entered by user and it will keep doing this until exit is entered and if I enter nothing but valid file names there are no problems. But when I enter an invalid file name followed by a valid file name it still says the file is invalid and I cannot figure out why and I have tried debugging it and what not and still cannot find the problem. Any help would be greatly appreciated!
# include <iostream>
#include <string>
#include<fstream>
#include<vector>
using namespace std;
void Open_file(string name)
{
ifstream my_file;
my_file.open(name.c_str());
}
bool isValid(ifstream& file, string name)
{
if ((name.substr(name.length() - 4)) != (".htm"))
{
return false;
}
cout << file << endl;
if (file.good())
{
return true;
}
else
{
return false;
}
}
string File_title(ifstream& my_file)
{
string title;
string line;
size_t first_title;
size_t second_title;
string str;
while((getline(my_file,line)))
{
str = str + line;
}
first_title = str.find("<title>");
second_title = str.find("</title>");
title = str.substr(first_title + 7, (second_title) - (first_title + 7));
return title;
}
void Output_function(ifstream& my_file)
{
string line;
ifstream MyFile("titles.txt");
string g = File_title(my_file);
while(getline(MyFile, line))
{
if((g == line))
{
return;
}
}
ofstream out_title("titles.txt", fstream::app);
out_title << g << endl ;
}
void Clear_file()
{
ofstream out_title("titles.txt");
out_title << "" << endl;
}
int main()
{
string file_name;
while (file_name != "exit")
{
cout <<"please enter a HTML file name or hit 'exit' to quit and " << endl;
cout << "if you want to clear file please enter 'clear': ";
getline(cin,file_name);
ifstream my_file(file_name.c_str());
cin.ignore(256, '\n');
if(file_name == "clear")
{
Clear_file();
break;
}
while ((isValid(my_file, file_name) == false))
{
cin.clear();
cout <<"Invalid file name, please enter a valid file name: ";
getline(cin,file_name);
ifstream my_file(file_name.c_str());
}
Open_file(file_name);
Output_function(my_file);
my_file.close();
}
}
ifstream my_file(file_name.c_str());
This doesn't replace the my_file you'd already created in an outer scope. It just makes a new local variable that lives for like a nanosecond.
You'll have to close then re-open the existing my_file, being sure to reset its error flags too.
The logic you are using to exit the loop is flawed.
You need to check the value of file_name right after it is entered, not after it is processed in the while loop once.
You need to use something along the lines of:
while ((file_name = get_file_name()) != "exit")
{
...
}
where
std::string get_file_name()
{
std::string file_name;
cout <<"please enter a HTML file name or hit 'exit' to quit and " << endl;
cout << "if you want to clear file please enter 'clear': ";
getline(cin,file_name);
return file_name;
}
Other improvements:
The call to cin.ignore() is going to be a problem line since std::getline does not leave the newline character in the input stream. You'll have to type Enter one more time. You should remove it.
You don't need the cin.clear() line. You need cin.clear() only if an error was detected in reading from the stream -- such as when using cin >> var; when the input stream did not have the right data suitable for var.
You don't need to open the file if the file is not valid.
You don't need multiple lines ifstream my_file(file_name.c_str());. You only need it once, just before the call to Output_function(my_file).
You don't need to explicitly call my_file.close(). The file will be closed and the end of the scope.
Here's a simplified version of main.
int main()
{
string file_name;
while ((file_name = get_file_name()) != "exit")
{
if(file_name == "clear")
{
Clear_file();
break;
}
while ( isValid(my_file, file_name) == false )
{
cout <<"Invalid file name, please enter a valid file name: ";
getline(cin,file_name);
}
Open_file(file_name);
ifstream my_file(file_name.c_str());
Output_function(my_file);
}
}
I'm trying to write a program which opens a text file full of words (a "dictionary" minus the definitions) and stores these values in strings to compare them against a user input to determine whether the user input is spelled correctly.
I go the program to work and do what I wanted, but I can't seem to figure out one specific detail. I want the program to continue running until the user enters "exit" as an input. The only problem is that my program continues spewing out either "input is spelled correctly" or "input is not spelled correctly" ad infinitum without giving the user a chance to input more values in.
How do I make it so the program only outputs one of these two options only once and then prompts the user for another input instead of a never-ending stream of the same statement? Thank you in advanced!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line; //holds values from txt file
string input; //holds user-inputted values
ifstream inputFile; //fstream operator declaration
bool isFound = false; //bool value to indicate if the string has been found
inputFile.open("dict.txt", ios::in);
if (inputFile)
{
cout << "Enter word to spellcheck (or exit to end)\n";
getline(cin, input);
while (input != "exit")
{
while (getline(inputFile, line))
{
if (input == line)
{
isFound = true;
break;
}
else
{
isFound = false;
}
}
inputFile.close();
if (isFound)
{
cout << input << " is spelled correctly.\n";
}
else
{
cout << input << " is not spelled correctly.\n";
}
}
if (input == "exit")
{
cout << "Ending program...\n";
}
}
else
{
cout << "Cannot open file\n";
}
return 0;
}
Inside the body of the
while (input != "exit")
loop the user is never asked to update the value of input. Moving getline(cin, input) into the while condition like this:
while (getline(cin, input) && input != "exit")
will solve that problem.
Then next problem is the handling of the dictionary file. It is closed in the middle of the loop, so subsequent reads from it will instantly fail. OP could reset the read pointer to the beginning of the file with inputFile.seekg(0);, but why reread the file every time.
Instead read the dictionary file into a std::set with more or less the same code as used in the search:
std::set<std::string> dictionary;
while (getline(inputFile, line))
{
dictionary.insert(line);
}
at the beginning of the program and search the set for the user's input in the loop.
if (dictionary.find(input) != dictionary.end())
{
cout << input << " is spelled correctly.\n";
}
else
{
cout << input << " is not spelled correctly.\n";
}
This should do the trick, you just need to move your getline block in the while loop, and move the file close statement outside the while loop:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
using namespace std;
int main()
{
string line; //holds values from txt file
string input; //holds user-inputted values
ifstream inputFile; //fstream operator declaration
bool isFound = false; //bool value to indicate if the string has been found
inputFile.open("dict.txt", ios::in);
if (inputFile)
{
while (input != "exit")
{
// Rewind file back to beginning every time
inputFile.clear();
inputFile.seekg(0,std::ios::beg);
cout << "Enter word to spellcheck (or exit to end)\n";
getline(cin, input);
while (getline(inputFile, line))
{
if (input == line)
{
isFound = true;
break;
}
else
{
isFound = false;
}
}
if (isFound )
{
cout << input << " is spelled correctly.\n";
}
else
{
if (input != "exit"){ // Don't print message if exiting
cout << input << " is not spelled correctly.\n";
}
}
}
if (input == "exit")
{
cout << "Ending program...\n";
}
inputFile.close();
}
else
{
cout << "Cannot open file\n";
}
return 0;
}
I'm very new to c++ there is a good bit of code here, so im going to do my best to condense it to the problem area. when I try to get user input using getline im getting this error. Since i don't expect spaces in the file names(i made the files)i use cin << which worked fine, but then got the same error when trying to read the file. the code is as follows
// includes here
using namespace std;
//other prototypes here
string getUserDataFromFile(vector<int>&, int&, string);
int main()
{
vector<int> numbers;
numbers.reserve(50);
int numberOfElements = 0;
int number = 0;
int numToFind = 0;
int numberPosition = -1;
int useFile = 0;
string filename = "";
string fileReadMessage = "";
string output = "";
string outFilename = "";
cout << "Would you like to load the data from a file?(1 for yes 0 for no)";
cin >> useFile;
cin.ignore(INT_MAX, '\n');
//get user data for manual input
if(useFile == 0)
{
//code here for manual input(works fine)...
}
//get userdata for file input
else
{
cout << "Please Enter the file path to be opened" << endl;
//fixed after adding cin.ignore(INT_MAX, '\n');
//see next function for another problem
getline(cin, filename);
fileReadMessage = getUserDataFromFile(numbers, numToFind, filename);
}
//some code to get data for output
return 0;
}
//function to get user data from file
//#param v(vector<int>&) - vector of integers.
//#param numToFind(int&) - the number we are looking for
//#param filename(string) - the filename of the file with data
//#return message(string) - a message containing errors or success.
string getUserDataFromFile(vector<int>& v, int& numToFind, string filename)
{
string message = "File Accepted";
string line = "";
int numOfElements = 0;
int count = 0;
ifstream fileToRead(filename.c_str());
//using 'cin >>' in main, the program runs till here then breaks
//if message is a file, extract message from file
if (fileToRead.is_open())
{
while (getline(fileToRead,line))
{
//code to do stuff with file contents here
}
fileToRead.close();
}
else
{
message = "Unable to open file.";
}
return message;
}
I left a couple of comments in the trouble areas and left out most of the code that i haven't had trouble with or haven't been able to test. Any help is appreciated. Thanks!
So my first issue was fixed by the addition of cin.ignore(INT_MAX, '\n'); any guesses on the next problem? its the line if (fileToRead.is_open()) in the next function
Add
cin.ignore();
before:
getline(cin, filename);
Otherwise, ENTER you typed after entering useFile will be read into filename.
I'm writing a program in C++ and I've been able to get it to compile and start to run how ever when I choose an option the coresponding function that is supposed to be called by a switch-case statement isn't called. Am I missing something in my code?
//The following program framework is given.
//Add the programming logic to complete the assignment.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
//function prototypes should be placed here
//Main must be the first function in the program. Write other functions after it.
int main()
{
char cInput;
string strFileName;
vector<string> vecStudent;
cout<<"Please enter the data file name (with location): ";
cin >> strFileName;
//call a function to read the content of the input file into
//the vector vecStudent
while (true)
{
cout<<"----------------------------------------"<<endl;
cout<<" Student Record - Main Menu "<<endl;
cout<<"----------------------------------------"<<endl;
cout<<" Enter 1 to display ALL students"<<endl;
cout<<" Enter 2 to add a student name"<<endl;
cout<<" Enter 3 to delete a student name"<<endl;
cout<<" Enter 4 to SAVE and quit the program"<<endl;
cout<<"----------------------------------------"<<endl;
cout<<"Enter menu option: ";
cin>>cInput;
switch (cInput)
{
case '1':
//call function display names
void displaynames();
break;
case '2':
void addname();
//call a function add name
break;
case '3':
void deletename();
//call function delete names
break;
case '4':
void saveandquit();
//call function save and quit
return 0;
if( cInput != 1,2,3,4)
cout<<"invalid input"<<endl;
break;
}
}
return 0;
}
int displaynames()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
char line[80];
// open input file
inFile.open(strFileName.c_str());
if (inFile.fail())
{
cout << " Input file error!" << endl;
return -1;
}
while (inFile>>strFName>>strLName)
vecStudent.push_back(strFName+ " "+strLName);
inFile.close();
//display the content of the vector
for(int i =0; i< vecStudent.size();i++)
cout<<vecStudent[i]<<endl;
return 0;
}
int addname()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
char line[80];
//add a new name
cout << endl<< " Enter a new name( First and Last Name):";
cin>>strFName>>strLName;
vecStudent.push_back(strFName+ " "+strLName);
// open output file for writing
outFile.open(strFileName.c_str());
if ( outFile.fail())
{
cout<<" Output file error! Student was not added"<<endl;
return -1;
}
//display the content of the vector
for(int i=0; i<vecStudent.size(); i++)
cout<< vecStudent[i]<<endl;
for(int i=0; i<vecStudent.size();i++)
outFile<<vecStudent[i]<<endl;
outFile.close();
return 0;
}
int saveandquit()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
int i=0;
char line[80];
// open output file for writing
outFile.open(strFileName.c_str());
if ( outFile.fail())
{
cout<<" Output file error!"<<endl;
return -1;
}
//display the content of the vector
for(int i=0; i<vecStudent.size(); i++)
cout<< vecStudent[i]<<endl;
for(int i=0; i<vecStudent.size();i++)
outFile<<vecStudent[i]<<endl;
outFile.close();
cout << " file saved. enter -1 to quit";
cin>> i;
if( i=-1)
return 0;
}
int deletename()
{
ifstream inFile;
ofstream outFile;
string strFileName;
string strFName,strLName;
vector<string> vecStudent;
int namepos = 0;
char line[80];
inFile.open(strFileName.c_str());
if (inFile.fail())
cout <<"Input file error!"<<endl;
//read the names from the file into the vector
while (inFile >> strFName >> strLName)
vecStudent.push_back(strFName+" "+strLName);
inFile.close();
cout <<"\nEnter the name to be deleted (First name and Last name): ";
cin >>strFName >>strLName;
int i=0, pos=-1;
int size = vecStudent.size();
bool found=false;
// use a linear search to find the name in the vecotor of names
while (i < size && !found)
{
if (vecStudent [i] == strFName+" "+strLName)
{
found = true;
cout <<"\nthat name is in the "<<(pos + 1) <<" position in the list\n";
cout <<"Please enter the position in list\n";
cin>> pos;
// use an iterator to delete name from vecStudent. vector.erase requires an iterator. used a while loop to find the name and make sure it was in the
// vector of strings. then the loop displays the position in the vector that the string is. the program asks the user to enter the number position of the name
// from there the user enters the name and the program uses a for loop to find the position and the built in vector.erase to remove the name from the list.
for(int i=0; i ==pos; i++)
{
if(i == pos)
{
vecStudent.erase (vecStudent.begin());
}
}
}
}
return 0;
}
You are actually just declaring functions instead of calling them.
void displaynames();
Declares a function.
displaynames();
Calls a function.
You are calling the functions wrong. It should be
case '1':
//call function display names
displaynames();
break;
case '2':
addname();
//call a function add name
break;
case '3':
deletename();
//call function delete names
break;
case '4':
saveandquit();
To call a function, you just need the function name and the function parameters (which in this case, seem to be none. The way you currently have it is declaring a function rather than calling a function.
In your code block (switch), you're not calling any functions, but rather just declaring them.
...
case '1':
//call function display names
void displaynames();
break;
...
Move the (forward) declarations (void displaynames();) to the top level of your source file (as you're defining the functions after using them), and then call them using the normal function application syntax (displaynames();).
From somewhere on the net:
"A declaration for a function is also called a prototype and it
informs the compiler of your intent to define and to use it. A
definition for a function is the body (code) associated with the
prototype."