How to delete a contact from a phonebook program - c++

I made a phonebook program which includes Add and search a contact.
But when I made the delete function, it deleted all the contacts instead of the one I entered.
I know it's a little bit complicated but any ideas?
This is the input in phonebook.txt from which I want to delete a contact:
Barney Hackett 0114543053
Luis Avery 01056633489
Hudson Ramsay 01576633982
Ihe code is:
void DeletePhoneNumber() {
FILE* search, * fp1;
//to receive the enter from system("cls")
char temp;
scanf("%c", &temp);
search = fopen("PHONEBOOK.txt", "r+");
fp1 = fopen("temp.txt", "w");
system("cls");
printf("\t*****DELETE CONTACT*****");
printf("\n\t Enter Name: ");
int length;
length = strlen(SearchName);
int i, y = 0;
//string comparison//
while (fgets(name, 50, search) != NULL) {
fputs(name, fp1);
}
fclose(search);
fclose(fp1);
search = fopen("PHONEBOOK.txt", "w");
fp1 = fopen("temp.txt", "r");
while (fgets(name, 50, search) != NULL) {
fputs(name, search);
}
fclose(search);
fclose(fp1);
remove("temp.txt");
printf("\n\tPRESS ANY KEY TO CONTINUE");
getch();
MainMenu();
}
}

I'll use this "answer" space to give you a partial analysis of your code. You can use it to improve your code.
Basically, your loop is all wrong:
search = fopen("PHONEBOOK.txt", "r+");
while (fgets(name, 50, search) != NULL) {
// ...
while (token != NULL) {
// ...
fclose(search);
search = fopen("PHONEBOOK.txt", "w");
You opened the file in append mode, read from it and now close the file, to open it in a different mode. What will it read on the next fgets in the while loop?
Opening the file in mode "w" for writing will destroy the file. So here is why there are no more entries in your file.
fclose(search);
MainMenu();
At the bottom of the loop you close the file. How can it still read something with fgets in the while loop.
Next you call MainMenu. But I assume this function calls this DeletePhoneNumber function, so you are in a strange loop/recursion. Of course, when you are done with deleting the phone number, you simply return to the main menu, not call it again.

Related

Paste contents of a file to another file from a particular line

I want to copy content of a text file (description.txt) and paste it on another text file at a particular line (movie.txt) using c++.
Here's the file contents:
description.txt
Chris Gardner takes up an unpaid internship in a brokerage firm after he loses his life's earnings selling a product he invested in. His wife leaves him and he is left with the custody of his son.
movie.txt
Movie name: The Pursuit of Happyness
Movie Description:
// description.txt content here
Initial release: November 2006
Director: Gabriele Muccino
Adapted from: The Pursuit of Happyness
I make a function that you can use.
void CopyContentOfTextFile(char* sourceFile, char* targetFile, int targetLine)
{
FILE* resultFilePtr = fopen("result.txt", "w");
FILE* sourceFilePtr = fopen(sourceFile, "r");
FILE* targetFilePtr = fopen(targetFile, "r");
char line[256];
int lineCounter= 0;
while (fgets(line, 256, targetFilePtr)!=NULL)
{
if (lineCounter == targetLine-1)
{
char lineToBeAdded[256];
//Now read sourceFile
while (fgets(lineToBeAdded, 256, sourceFilePtr) != NULL)
{
fprintf(resultFilePtr, "%s", lineToBeAdded);
}
fprintf(resultFilePtr, "%s", "\n");
}
fprintf(resultFilePtr, "%s", line);
lineCounter++;
}
fclose(sourceFilePtr);
fclose(targetFilePtr);
fclose(resultFilePtr);
//Remove old movie.txt file with new one
remove(targetFile);
rename("result.txt", targetFile);
}
To call it use something like:
int main()
{
char pathToSourceFile[] = "description.txt";
char pathToTargetFile[] = "movie.txt";
int line = 3;
CopyContentOfTextFile(pathToSourceFile, pathToTargetFile, line);
}

ifstream - monitor updates to file

I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.

Losing a value from pointer vector after loop that reads the file (using dirent)

I'm writing a program in C++ that behaves like a Twitter Service. The program is supposed to store data in files as follows:
f_username (stores the users that username follows), so it creates a file for each user that follows someone. I have the function load_users() that reads each file to populate all clients (users) information in a vector called client_db (global variable) of type struct (defined below). So, when a f_username file is read, the vectors client_followers and client_following are populated for each user. The function works perfectly, except for the first file it reads. It saves the information in client_followers and client_following in the while loop that reads the file, but the entries for both vectors are deleted somehow after this loop. I added the comments in the code where I'm facing this issue only for the first f_username file it reads.
I believe it has something to do with the fact I'm using pointers, but I have no clue how to fix this issue. This is the first time ever I have this weird logic error. How is possible that it only "deletes" the data from the vectors that is read from first file, but not from the other files (I have 3 files)?
Any help would be really appreciated, I tried my best to explain this problem.
**UPDATE: Problem fixed by replacing the types of vectors client_followers and client_following with a string type without declaring them as pointers, and making sure the actual entries in client_db are updated correctly. **
//Client struct that holds a user's username, followers, and users they follow
struct Client {
std::string username;
bool connected = false;
int following_file_size = 0;
std::vector<Client*> client_followers;
std::vector<Client*> client_following;
ServerReaderWriter<Message, Message>* stream = 0;
bool operator==(const Client& c1) const{
return (username == c1.username);
}
};
void load_users()
{
//load users (followers and following)
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("./")) != NULL) {
while ((ent = readdir (dir)) != NULL) {
std::string filename = ent->d_name;
int index = filename.find("f_");
if(index != std::string::npos)
{
std::ifstream in; //read following file of username
//get username
std::string user = filename.substr(index+2);
int txt_index = user.find(".txt");
user.erase(txt_index,4);
int user_index = find_user(user); //check if user is in client's db already
//client_db is a global variable
if(user_index < 0){ //if not, add client to client_db
Client c;
c.username = user;
client_db.push_back(c);
}
Client* user1 = &client_db[find_user(user)];
std::string username2;
in.open("./" + filename);
while(!in.eof())
{
getline(in,username2);
int following_index = find_user(username2);
if(following_index < 0) //create entry for the user
{
Client c2;
c2.username = username2;
client_db.push_back(c2);
}
Client* user2 = &client_db[find_user(username2)];
//it adds the information for the first file, but entries in client_followers
//and client_following is deleted after this loop ends, how is this possible?
user2->client_followers.push_back(user1);
user1->client_following.push_back(user2);
}
//When I print information of client_following and client_followers, the information obtained from the first file is not printed (e.g. size of client_following is 0).
in.close();
//break;
}
}
closedir (dir);
} else {
/* could not open directory */
//perror ("");
//return EXIT_FAILURE;
return;
}
}

Why is nothing being written to the text file?

I am trying to write song information to a text file but nothing is being written to it. The part where I am trying to write the information to onF is running but the file is blank. BTW the code below is part of a recursive function which is the reason for the first few if statements. Any ideas?
void writeToFile(int artist, int album, int song, int nA, int nAl, int nS)
{
ofstream onF("library.txt");
if(song>=nS)
{
album+=1;
song = 0;
}
if(album>=nAl)
{
artist++;
album = 0;
song = 0;
}
if(artist>=nA)
{
onF.close();
return;
}
if(onF.is_open())
{
onF<<artists[artist].artistName<<'#';
onF<<artists[artist].albums[album].albumName<<'#';
onF<<artists[artist].albums[album].songs[song].songName<<'#';
onF<<artists[artist].albums[album].songs[song].songLength<<endl;
cout<<"RAN"<<endl;
}
else
cout<<"File could not be opened."<<endl;
song++;
int numAlbums = artists[artist].numAlbums;
int numSongs = artists[artist].albums[album].numSongs;
writeToFile(artist, album, song, nA, numAlbums, numSongs);
}
Now that I have that working I am having trouble loading the information from the file. It's loading the song info twice with the second time loading everything but the song title. The loop runs twice:
if(inF)
{
while(!inF.eof())
{
getline(inF, newArtist, '#');
getline(inF, newAlbum, '#');
getline(inF, newSong, '#');
inF>>songLength;
cout<<"CALLED"<<endl;
addSong(newArtist, newAlbum, newSong, songLength, numArtists, 0, 0);
}
inF.close();
if(inF.is_open())
cout<<"FAILED TO CLOSE"<<endl;
}
You're truncating the file on entry to the function, so the last call will erase all that has been written.
If you want to append, add the std::ios::app flag

Partial line from cpp file ending up in output file - haunted code?

I'm sorry, it would be extremely difficult to make a fully reproducible version of the error --- so please bare with my schematic code.
This program retrieves information from a web page, processes it, and saves output to an ASCII file. I also have a 'log' file (FILE *theLog---contained within a Manager object) for reporting errors, etc.
Some background methods:
// Prints string to log file
void Manager::logEntry(const string lstr) {
if( theLog != NULL ) { fprintf(theLog, "%s", lstr.c_str()); }
}
// Checks if file with given name already exists
bool fileExists(const string fname) {
FILE *temp;
if( temp = fopen(fname.c_str(), "r") ) {
fclose(temp);
return true;
} else { return false; }
}
// Initialize file for writing (some components omitted)...
bool initFile(FILE *&oFile, const string fname) {
if(oFile = fopen(fname.c_str(), "w") ) { return true; }
else { return false; }
}
The stuff causing trouble:
// Gets data from URL, saves to file 'dataFileName', input control flag 'foreCon'
// stu is some object that has string which i want
bool saveData(Manager *man, Stuff *stu, string dataFileName, const int foreCon) {
char logStr[CHARLIMIT_LARGE]; // CHARLIMIT_LARGE = 2048
sprintf(logStr, "Saving Data...\n");
man->logEntry( string(logStr) ); // This appears fine in 'theLog' correctly
string data = stu->getDataPrefixStr() + getDataFromURL() + "\n"; // fills 'data' with stuff
data += stu->getDataSuffixStr();
if( fileExists(dataFileName) ) {
sprintf(logStr, "save file '%s' already exists.", dataFileName.c_str() );
man->logEntry( string(logStr) );
if( foreCon == -1 ) {
sprintf(logStr, "foreCon = %d, ... exiting.", foreCon); // LINE 'A' : THIS LINE ENDS UP IN OUTPUT FILE
tCase->logEntry( string(logStr) );
return false;
} else {
sprintf(logStr, "foreCon = %d, overwriting file.", foreCon); // LINE 'B' : THIS LINE ENDS UP IN LOG FILE
tCase->logEntry( string(logStr) );
}
}
// Initialize output file
FILE *outFile;
if( !initFile(outFile, dataFileName) ) {
sprintf(logStr, "couldn't initFile '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return false;
}
fprintf(outFile, "%s", data.c_str()); // print data to output file
if( fclose(outFile) != EOF) {
sprintf(logStr, "saved to '%s'", dataFileName.c_str());
tCase->logEntry( string(logStr) );
return true;
}
return false;
}
If the file already exists, AND 'int foreCon = -1' then the code should print out line 'A' to the logFile. If the file exists and foreCon != -1, the old file is overwritten with data. If the file doesn't exist, it is created, and the data is written to it.
The result however, is that a broken up version of line 'A' appears in the data file AND line 'B' is printed in the log file!!!!
What the data file looks like:
.. exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
The second line and onward look correct, but there is an extra line that contains part of line 'A'.
Now, the REALLY WEIRD PART. If I comment out everything in the if( foreCon == -1) { ... } block, then the data file looks like:
%d, ... exiting.20130127 161456
20130127 000000,55,17,11,0.00
20130127 010000,54,17,11,0.00
... ...
There is still an extra line, but it is the LITERAL CODE copied into the data file.
I think there is a poltergeist in my code. I don't understand how any of this could happen.
Edit: I've tried printing to console the data string, and it gives the same messed up values: i.e. %d, ... exiting.20130127 161456 - so it must be something about the string instead of the FILE *
Answer based on your latest comment:
getDataPrefixStr() ends up returning a string which starts with
something like string retStr = COMCHAR + " file created on ..."; such
that const char COMCHAR = '#';. Could the COMCHAR be the problem??
You can't add characters and string literals (which are arrays of char, not strings) like that.
You're adding 35 (the ASCII for "#") to the address of " file created on ... ", i.e. getDataPrefixStr() is whatever starts 35 characters from the start of that string. Since all literal strings are stored together in the same data area, you'll get strings from the program in the output.
Instead, you cold do
const string COMCHAR = "*";
string retStr = COMCHAR + " file created on ...";
It could be that logStr is too short and that it is causing data to be overwritten in other buffers (did you double check CHARLIMIT_LARGE?). You can diagnose this by commenting all writes to logStr (sprintf) and see if data is still corrupted. In general, your code is vulnerable to this if a user can set dataFileName (to be a very long string); use snprintf or ostringstream instead.
Otherwise, I would guess that either stu->getDataPrefixStr() or getDataFromURL() are returning corrupted results or return type char* instead of string. Try printing these values to the console directly to see if they are corrupted or not. If they return a char*, then data = stu->getDataPrefixStr() + getDataFromURL() will have undefined behavior.
if( temp = fopen(fname.c_str(), 'r') ) {
should be
if( temp = fopen(fname.c_str(), "r") ) {