The Intro:
I'm working on a Project #Student Course Registration System,
my project is based on singly linked list, with file handling.
The Problem:
I have managed to modify the nodes in LinkedList, made a separate function to update my text file. But the problem is the file is not getting updated. On the console, I do see the items updated.
I have to work around modifying the text file without making a temporary one and copying items to that, which I know how to.
P.S : I have made a function which always loads all the required Text Files into the program at startup.
Structure:
struct Student {
string stdID;
string stdName;
string stdSemester;
Student *next;
};
Main:
int main() {
Student *Head = NULL;
Student *Tail = NULL;
Course *Headd = NULL;
Course *Taill = NULL;
UpdateDirectory(Head, Tail, Headd, Taill);
Display(Head, Tail);
_getch();
string Value;
getline(cin, Value);
ModifyStudent(Value, Head);
UpdateFile(Head, Tail);
//Display(Head, Tail);
return 0;
}
Modify Function:
void ModifyStudent(string Value, Student *&Head) {
// Initialize:
Student *Curr = NULL;
Student *Temp1 = NULL;
Student *Temp2 = NULL;
Student *Obj = new Student;
if (isEmpty(Head)) {
cout << "\t\t\t\t Underflow....\n\n";
_getch();
}
else {
Curr = Head;
Temp1 = Head;
while (Curr->stdID != Value) {
Temp1 = Curr;
Curr = Curr->next;
}
if (Curr->stdID == Value) {
cout << "\t\t\t\t Student Found!!\n\n";
cout << Curr->stdID << endl; // 1324
cout << Temp1->stdID << endl; // 3424
// Modify:
cout << "\t\t\t\t Enter New Student ID : ";
getline(cin, Obj->stdID);
cout << "\t\t\t\t Enter New Student Name : ";
getline(cin, Obj->stdName);
cout << "\t\t\t\t Enter New Semester : ";
getline(cin, Obj->stdSemester);
Temp1->next = Obj;
Obj->next = Curr->next;
Curr->next = NULL;
delete(Curr);
/// Save:
cout << "\t\t\t\t Record Is Being Updated, Please Wait.......\n\n" << endl;
_getch();
}
}
}
Update File:
void UpdateFile(Student *&Head, Student *&Tail) {
Student *Temp = NULL;
fstream SFile;
SFile.open("StudentRecords.txt", ios::trunc);
if (isEmpty(Head)) {
cout << "\t\t\t\t UnderFlow\n" << endl;
}
else {
Temp = Head;
while (Temp->next != NULL) {
cout << Temp->stdID << '\t' << Temp->stdName << '\t' << Temp->stdSemester << '\n';
SFile << Temp->stdID << '\t' << Temp->stdName << '\t' << Temp->stdSemester << '\n';
Temp = Temp->next;
}
cout << Temp->stdID << '\t' << Temp->stdName << '\t' << Temp->stdSemester << '\n';
SFile << Temp->stdID << '\t' << Temp->stdName << '\t' << Temp->stdSemester << '\n';
_getch();;
}
_getch();;
}
I have even used ios::trunc, but no effect.
Thank You!
It is hard to say what the problem is. You did not provide the full source code; therefore we cannot compile the code.
To write a file, use the following. The file will be overwritten (this seems to be what you are looking for):
ofstream os{ "test.txt" };
if( !os )
return -1;
if( !list.write( os ) )
return -2;
Regarding your code, this is a more c++ like approach to single linked lists:
Define a data class/structure. You may want to use the data with other classes, not only with a linked list, therefore keep it separated from node:
class student_t
{
public:
string id;
string name;
string semester;
// ...
};
Define operations. One of the operations you need is write:
ostream& write( ostream& os )
{
return os
<< id << endl
<< name << endl
<< semester << endl;
}
Define a node. A node is made of data and a pointer to next node:
class node_t
{
friend class list_t; // or replace it with public:
student_t data;
node_t* pnext;
// ...
};
Add a constructor and a write method:
node_t( const student_t& s, node_t* pnext ) : data{ s }, pnext{ pnext } {}
ostream& write_data( ostream& os )
{
return data.write( os );
}
Define a list class. The only data a list class holds is the list’s head. The class will gather all list operations like write_data, push_front, display_data, etc.
class list_t
{
node_t* phead{ nullptr };
public:
void push_front( const char* id, const char* name, const char* semester )
{
phead = new node_t( student_t{ id, name, semester }, phead );
}
ostream& write( ostream& os )
{
node_t* pn = phead;
while( pn && pn->write_data( os ) )
pn = pn->pnext;
return os;
}
//...
};
And this is how you use it:
int main()
{
list_t list;
list.push_front( "J1", "Jon", "first" );
list.push_front( "S1", "Steve", "first" );
{
ofstream os{ "test.txt" };
if( !os )
return -1;
if( !list.write( os ) )
return -2;
} // the file is automatically closed here
list.push_front( "A1", "Ava", "second" );
{
ofstream os{ "test.txt" };
if( !os )
return -1;
if( !list.write( os ) )
return -2;
}
return 0;
}
Related
I have a doubly-linked-list called "all_gods" with both Greek and Norse gods.
And I'm trying to remove all Greek gods from "all_gods" and move them to a "greek_gods" list.
I was able to erase them from all_gods but not to insert them in greek_gods.
And I have a couple of questions regarding the code below:
is the Destructor for class Link correct?
inside the for loop in the main() should I delete the "q" pointer? it gives "segmentation fault (core dumped)" error. Without "delete q" I am able to erase all Greek gods from "all_gods".
when I try to insert the same "q" into the "greek_gods" I have a weird behavior ("p" doesn't take the next value, after a couple of iterations).
I'm out of ideas of what I can try. Thanks for any help!
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
struct God
{
God(const string &n, const string &m)
: name{n}, mythology{m} {}
string name;
string mythology;
};
class Link
{
public:
Link(const string &n, const string &m, Link *p = nullptr, Link *s = nullptr)
: god{n, m}, prev{p}, succ{s}
{
}
Link *insert(Link *n); // insert n before this object
Link *erase(); // remove this object from list
Link *find(const string &s); // find s in list
Link *next() const { return succ; }
Link *previous() const { return prev; }
~Link() // destructor
{
if (prev)
delete prev;
if (succ)
delete succ;
}
God god;
private:
Link *prev;
Link *succ;
};
Link *Link::insert(Link *n) // insert n before this object; return n
{
if (n == nullptr)
return this;
if (this == nullptr)
return n;
n->succ = this; // this object comes after n
if (prev)
prev->succ = n;
n->prev = prev; // this object’s predecessor becomes n’s predecessor
prev = n; // n becomes this object’s predecessor
cout << "3.insert " << n << ' ' << n->god.name << "\n\n";
return n; // returns n(the new element) which is before the top node
}
Link *Link::erase() // remove *p from list; return p’s successor
{
if (this == nullptr)
return nullptr;
if (succ)
succ->prev = prev;
if (prev)
prev->succ = succ;
cout << "2.erased " << this << ' ' << this->god.name << "\n\n";
return succ;
}
Link *Link::find(const string &s) // find s in list;
{
Link *p = this; // pointer p is the pointer to the caller of this function
while (p)
{
if (p->god.name == s)
return p;
p = p->succ;
}
return nullptr;
}
void print_all(Link *p)
{
while (p)
{
cout << ' ' << p << ' ' << p->god.name << ", " << p->god.mythology;
if (p = p->next()) // moved to the next node
cout << "\n";
}
}
int main()
try
{
Link *all_gods = new Link{"Four", "Greek"};
all_gods = all_gods->insert(new Link{"Three", "Greek"});
all_gods = all_gods->insert(new Link{"Two", "Norse"});
all_gods = all_gods->insert(new Link{"One", "Greek"});
cout << "all_gods:\n";
print_all(all_gods);
cout << "\n\n";
Link *greek_gods = nullptr;
for (Link *p = all_gods; p != nullptr; p = p->next())
{
if (p->god.mythology == "Greek")
{
cout << "1.found " << p << ' ' << p->god.name << '\n';
Link *q = all_gods->find(p->god.name);
cout << "q found " << q << ' ' << q->god.name << '\n';
if (q)
{
if (q == all_gods)
all_gods = all_gods->next();
q->erase();
//greek_gods = greek_gods->insert(q); // insert q in d
}
delete q; // gives core dumped - it's deleted at the exit of if() ? no, needs to be deleted at the function's exit
}
}
// delete p; // no need for this because it's decimated by p=p->next() ?
cout << "all_gods:\n";
print_all(all_gods);
cout << "\n";
cout << "greek_gods:\n";
print_all(greek_gods);
cout << "\n";
delete all_gods;
delete greek_gods;
}
catch (exception &e)
{
cerr << "exception: " << e.what() << '\n';
return 1;
}
catch (...)
{
cerr << "exception\n";
return 2;
}
I am currently learning how to use linked list in class in my free time. Now I only know how to insert, display and delete. I can delete by using int age; but I think it would be better if I'm able to generate a unique ID that is easier for user to remember(user-friendly), for each data in the linked list so that I could delete by its ID.
I want to know if there is a possible way for me to generate a unique ID in the getInput(); function?
If yes, please give me a hint how to do it. Thanks!
struct list
{
list *head, *tail;
list *next;
}
class node
{
private:
std::string name; // Name
int age; // Age in integer
float height; // In meters
public:
node *next; // Pointer to next node
node *head, *tail;
node *start_ptr = NULL; // Start Pointer (root)
node *temp;
node *temp2;
node *pNextValue;
node* prev; // empty header
node* current;
void printList();
void delete_end_node();
void search();
void sort_age();
void deletebyAge();
node()
{
head = NULL;
tail = NULL;
}
void getInput()
{
temp = new node;
cout << "ID: ";
// This is where I want to generate unique ID
cout << "Name: ";
cin >> temp->name;
cout << "Age: ";
cin >> temp->age;
cout << "Height: ";
cin >> temp->height;
cout<<"\n";
temp->next = NULL; // Sets the node to be the last node
if (start_ptr == NULL)
start_ptr = temp;
else
{
temp2 = start_ptr; // We know temp2 is not NULL - list not empty!
while (temp2->next != NULL) // The loop will terminate when temp2
temp2 = temp2->next; // points to the last node in the list
// Move to next link in chain
temp2->next = temp; // Sets the pointer from that last node to point to the node that has just declared
}
} // End of getInput() function
}; //End of class
In C++ the identity of an object is its address. You can use node address as its id, e.g.:
class node
{
private:
std::string name; // Name
int age; // Age in integer
float height; // In meters
friend std::ostream& operator<<(std::ostream& s, node& n) {
return s << "id:" << &n
<< ' ' << "name:" << n.name
<< ' ' << "age:" << n.age
<< ' ' << "height:" << n.height
<< '\n';
}
// the rest of your code...
};
And then print it like:
node n;
std::cout << n;
Alternatively, use a serial counter:
class node
{
private:
std::string name; // Name
int age; // Age in integer
float height; // In meters
unsigned const id;
static unsigned object_counter;
public:
node()
: id(++object_counter)
{}
friend std::ostream& operator<<(std::ostream& s, node& n) {
return s << "id:" << n.id
<< ' ' << "name:" << n.name
<< ' ' << "age:" << n.age
<< ' ' << "height:" << n.height
<< '\n';
}
// the rest of your code...
};
unsigned node::object_counter = 0;
I'm having trouble trying to merge sort my doubly link list. When I tried to display all of my nodes after merge sorting, it hits a segmentation fault.
my header file with the pre-processor directives ,structs , function prototypes.
hw07.h
#ifndef HW07_H_
#define HW07_H_
#include <iostream>
#include <fstream>
using namespace std;
typedef struct slist slist;
struct stud
{
string term;
string title;
string description;
string tktNum;
string location;
string lecDay;
string instructor;
string labLoc;
string labDay;
string labInstruct;
string units;
string preReqs;
string grade;
};
struct sentry
{
slist *list;
sentry *next;
sentry *prev;
stud *data;
};
struct slist
{
int length;
sentry *first;
sentry *last;
};
void readFile(slist *&header);
void displayAll(list *header);
sentry *mergeSort(sentry *header);
sentry *merge(sentry *first, sentry *second);
sentry *split(sentry *header);
#endif
my main
hw07.cpp
#include "hw07.h"
int main()
{
slist *header = NULL;
readFile(header);
displayAll(header);
mergeSort(header->first);
displayAll(header);
return 0;
}
my readFile function
readFile.cpp
#include "hw07.h"
void readFile(slist *&header)
{
ifstream fin;
sentry *node, *temp;
node = NULL;
temp = NULL;
// opens the text file/database
fin.open("sbclassdb.txt");
while(fin.good())
{
if(header == NULL)
{
header = new slist;
header->length = 0;
header->first = NULL;
header->last = NULL;
node = new sentry;
header->first = node;
header->last = node;
node->prev = NULL;
node->next = NULL;
}
else
{
node = new sentry;
node->prev = header->last;
node->next = NULL;
temp = header->last;
temp->next = node;
header->last = node;
}
node->data = new stud;
getline(fin, node->data->term);
getline(fin, node->data->title);
getline(fin, node->data->description);
getline(fin, node->data->tktNum);
getline(fin, node->data->location);
getline(fin, node->data->lecDay);
getline(fin, node->data->instructor);
getline(fin, node->data->labLoc);
getline(fin, node->data->labDay);
getline(fin, node->data->labInstruct);
getline(fin, node->data->units);
getline(fin, node->data->preReqs);
getline(fin, node->data->grade);
++header->length;
// when there's a blank line
string blankLine;
if(!getline(fin, blankLine))
break;
}
fin.close();
}
my displayAll function (displays all nodes)
displayAll.cpp
#include "hw07.h"
void displayAll(slist *header)
{
sentry *temp, *node;
node = NULL;
temp = NULL;
node = header->first;
cout << endl;
for(int i=0; i<header->length; ++i)
{
cout << "Term: " << node->data->term << endl;
cout << "Title: " << node->data->title << endl;
cout << "Description: " << node->data->description << endl;
cout << "Ticket #: " << node->data->tktNum << endl;
cout << "Lecture Location: " << node->data->location << endl;
cout << "Lecture Time: " << node->data->lecDay << endl;
cout << "Instructor: " << node->data->instructor << endl;
cout << "Lab Location: " << node->data->labLoc << endl;
cout << "Lab Time: " << node->data->labDay << endl;
cout << "Lab Instructor: " << node->data->labInstruct << endl;
cout << "Units: " << node->data->units << endl;
cout << "Pre-Requisites: " << node->data->preReqs << endl;
cout << "Grade: " << node->data->grade << endl;
temp = node;
node = temp->next;
cout << "\n";
}
}
my mergeSort function
mergeSort.cpp
#include "hw07.h"
sentry *mergeSort(sentry *header)
{
if (!header || !header->next)
{
return header;
}
sentry *second = split(header);
header = mergeSort(header);
second = mergeSort(second);
return merge(header, second);
}
sentry *split(sentry *head)
{
sentry *fase = head, *slow = head;
while(fast->next && fast->next->next)
{
fast = fast->next->next;
slow = slow->next;
}
sentry *temp = slow->next;
slow->next = NULL;
return temp;
}
sentry *merge(sentry *first, sentry *second)
{
if (!first)
return second;
if (!second)
return first;
if(first->data->title < second->data->title)
{
first->next = merge(first->next, second);
first->next->prev = first;
first->prev = NULL;
return first;
}
else
{
second->next = merge(first, second->next);
second->next->prev = second;
second->prev = NULL;
return second;
}
}
my sbclassdb.txt
Fall 2017
CS1B
Intro to Computer Science 2
11111
SM101
TTH 100PM
John Doe
SM102
TTH 300PM
John Doe
5
NA
A
Spring 2018
CS1A
Intro to Computer Science 1
22222
SM101
TTH 200PM
Jane Doe
SM102
TTH 300PM
Jane Doe
5
CS1A
NA
Spring 2018
ANTHRO 1
Introduction to Anthropology
12345
BGS101
MWF 200PM
Bob Smith
BGS102
Bob Smith
4
CS1B
NA
NA
Spring 2015
MATH 2
Pre-Calculus
111213
SM405
MW 200PM
Rick Sanchez
NA
NA
NA
4
Math 124
A+
Your mergeSort function returns a value, which you ignore in main. This results in the head of your list pointing at the wrong node (somewhere in the middle, instead of at the new front node).
When you display the list, you base your loop on the number of entries in your list, rather than looping until a NULL pointer is found. This is normally OK, but because of the first problem your program crashes when you try to move on past the last node.
I was trying to delete a node in a linked list defined as follows:
typedef struct
{
char key[10];
char name[20];
int age;
}Data;
typedef struct Node
{
Data nodeData;
struct Node *nextNode;
}cltype;
And the the delete function is defined as below:
int clDeleteNode(cltype *head, char *key)
{
cltype *node, *htemp = new (cltype);
htemp = head;
node = head;
while (htemp)
{
if (strcmp(htemp->nodeData.key, key))
{
node->nextNode = htemp->nextNode;
delete htemp;
return 1;
}
else
{
node = htemp;
htemp = htemp->nextNode;
}
}
//delete mp
return 0;
}
And the problem is when I tried to invoke the the delete function in this form the program will collapse:
cout << "program demo for deleting node\n" << "input key:" << endl;
fflush(stdin);
cin >> key;
//scanf("%s", key);
//int i =
if (clDeleteNode(head, key))
{
cout << "Delete Successful" << endl;
}
else
{
cout << "Operation Failed" << endl;
}
clAllNode(head);
The screen will display "Delete Successful", but the clAllNode(...) function will not execute.And the clAllNode(...) functions works totally well at other place, so I guess there is something wrong with the delete operation,can someone tell me where I did wrong?
Thank you.
I am having two issues with my c++ code (The test file is below):
I can't seem to figure out why its not breaking out of the while loop, when running, its stuck on the loop "7 versus 325".
So it should go into the next node of temp, which would be null, and then jump into the section where it adds it to the end of the queue. But its just looping and looping.
My second issue is with the the function I have commented out, queue1.back, whenever that is ran, it just errors out and gives what appears to be the address, but the .front() function works just fine.
The Test File I am working with is like this:
89 Alex
325 Rob
72 Joy
91 Bob
using namespace std;
class Person
{
friend class Pqueue;
public:
int priority;
string name;
};
class PQueue
{
friend class Person;
private:
//Structure for my linked list.
typedef struct node {
Person data;
struct node *next;
}Node, *NodePtr;
Node *head, *tail;
public:
//Prototype Functions
PQueue(void); //Initializer function
bool empty(void); //Test if empty
int size(void); //Return size
void enqueue(Person *); //Insert Node
void dequeue(void); //Remove Node
Person* front(void); //Access Next Node
Person* back(void); //Access last node
};
PQueue::PQueue()
{
head = NULL;
tail = NULL;
}
bool PQueue::empty(){
return (head == NULL);
}
void PQueue::enqueue(Person *myPerson){
NodePtr np = (NodePtr) malloc(sizeof(Node));
np->data = *myPerson;
np->next = NULL;
if(empty())
{
cout << "Making into creating the first node, of the linked list" <<endl;
head = np;
tail = np;
}
else { //Queue has more the one node
Node* temp = head;
if(np->data.priority > temp->data.priority) //If the priority is greater then the rest.
{
head = temp; //Saving my head pointer
head->data = np->data; //Assigning new Data to the head pointer
head->next = temp; //Assigning the rest of the linked list back into head.
cout << "Making into creating the first node again, having to reassign." <<endl;
}
else{
//Searching where to place the node.
while(temp->data.priority > np->data.priority) //Searching if the next priority is higher then the passed.
{
cout << "Inside the while loop: " << np->data.priority << " versus "<<temp->data.priority <<endl;
if(temp->next == NULL)
break;
temp = temp->next;
}
if(temp->next == NULL && np->data.priority < temp->data.priority) //Inserting at the end.
{
cout << "Making into creating the last node" <<endl;
tail->next = np;
cout << "Passing the function of creating the last node" <<endl;
}
else //Inserting into the middle of the function.
{
cout << "Inserting in the middle of the queue" <<endl;
np->next = temp->next;
temp->next = np;
}
}
}
}
void PQueue::dequeue(){
if(empty()){
cout << "\nAttempt to remove from an empty list." << endl;
exit(1);
}
Person hold = head->data;
NodePtr temp = head;
head=head->next;
if (head == NULL) tail = NULL;
free(temp);
}
Person* PQueue::front(){
//Person &temp = head->next->data;
//Person &temp = head->data;
Person &temp = head->data;
return &temp;
}
Person* PQueue::back(){
if(empty()){
cout << "\nNo entries in list." << endl;
exit(1);
}
Person &temp = tail->data;
return &temp;
}
int main() {
cout << "Starting main" << endl;
PQueue queue1; //Creating my queue.
cout << "Created Queue" << endl;
Person tempPerson;
ifstream inFile;
inFile.open("/tmp/temp");
cout << "going into while loop" << endl;
while (inFile >> tempPerson.priority >> tempPerson.name){
cout << "The priority is " << tempPerson.priority << " the name is " << tempPerson.name <<endl;
queue1.enqueue(&tempPerson);
}
//Testing Section, trying to get .front and .back to work.
Person *testPerson;
testPerson = queue1.front();
cout << "The TEST priority is " << testPerson->priority << " the TEST name is " << testPerson->name <<endl;
/**
Person *tailPerson;
testPerson = queue1.back();
cout << "The TEST priority is " << tailPerson->priority << " the TEST name is " << tailPerson->name <<endl;
**/
queue1.dequeue();
queue1.dequeue();
queue1.dequeue();
return 0;
}
When you add a new head entry to a non-empty list, you're mistakenly setting the next pointer to point right back at the node it's in, rather than setting it to point at the rest of the linked list like you intended.
head = temp; //Saving my head pointer
head->next = temp; //Assigning the rest of the linked list back into head.