Double linked list implementation - c++

I am having some syntax problems with a double linked list program I am writing for educational purposes. I have created a struct in my header file, and my main program seems to be alright, but implementing my functions in the .cpp file is giving me immense difficulty. I am having trouble discerning the three cases for inserting a record into the list. Specifically, allocating the memory, initializing the list head and tail, and the order of statements is confusing to me, as is passing a copy of the record to be added to my list.
My header file is as follows:
struct rec
{
char * id;
char firstname[15];
char lastname[15];
struct rec* prev;
struct rec* next;
};
int AddItem ( rec r );
int DeleteItem ( char* delid );
void PrintList ( int order );
My .cpp file, which is where the difficulty lies, is as follows:
#include <iostream>
#include "list.h"
#include <string.h>
using namespace std;
// These pointers refer to the head and tail of the list.
rec* first = NULL;
rec* last = NULL;
int AddItem( Rec r )
{
rec* newRecEntry;
rec* current = NULL;
rec* previous = NULL;
// Check for duplicate id
current = first;
while (current)
{
if( strcmp(current -> id, r.id) == 0)
{
return 0;
}
else
// Create a new node
{
newRecEntry = new Rec;
newRecEntry->id = new char[strlen(r.id)+1];
strcpy(newRecEntry->id, r.id);
strcpy(newRecEntry->firstname,r.firstname);
strcpy(newRecEntry->lastname,r.lastname);
newRecEntry->next = NULL;
newRecEntry->prev = NULL;
}
// Find the appropriate position for the node and insert accordingly
// Check to see if the list is empty
if (first == NULL)
{
first = newRecEntry;
last = newRecEntry;
}
else if ( r.lastname>last.lastname)
{
else
{
return 0;
}
/*int DeleteItem(char* ID)
I am supposed to be able to insert at the beginning, middle, and end of the list. Delete an item from the list based on the ID, and print the list in ascending or descending order based on user input, but I'd first simply like to handle the addition of items to said list.
My function definitions are as follows and also contains some errors
lists.cpp
#include <iostream>
#include "list.h"
#include <string.h>
using namespace std;
// These pointers refer to the head and tail of the list.
rec* first = NULL;
rec* last = NULL;
int AddItem( Rec r )
{
rec* newRecEntry;
rec* current = NULL;
rec* previous = NULL;
// Check for duplicate id
current = first;
while (current)
{
if( strcmp(current -> id, r.id) == 0)
{
return 0;
}
else
// Create a new node
{
newRecEntry = new Rec;
newRecEntry->id = new char[strlen(r.id)+1];
strcpy(newRecEntry->id, r.id);
strcpy(newRecEntry->firstname,r.firstname);
strcpy(newRecEntry->lastname,r.lastname);
newRecEntry->next = NULL;
newRecEntry->prev = NULL;
}
// Find the appropriate position for the node and insert accordingly
// Check to see if the list is empty
if (first == NULL)
{
first = newRecEntry;
last = newRecEntry;
}
else if ( r.lastname>last.lastname)
{
else
{
return 0;
}
/*int DeleteItem(char* ID)
{
rec
}
*/
/*void printList(int order)
{
loop
{
cout << ptr -> Id << " ";
cout << ptr -> firstname << " ";
cout << ptr -> lastname << " ";
cout << ptr -> prev << " "; // address of previous
cout << ptr << " "; // address of item
cout << ptr -> next << " "; // address of next item
}
}
Main is as follows:
#include <iostream>
#include "list.h"
#include <string.h> // <string>
using namespace std;
void main (void)
{
int choice, printorder;
char idbuffer[100];
rec r;
do
{
cout << "Enter your choice 1 Add, 2 Delete, 3 Print, 0 quit "<<endl;
cin >> choice;
switch ( choice )
{
case 1: //AddItem
cout << "\nEnter ID ";
cin >> idbuffer;
r.id = idbuffer;
cout << "\nFirst Name ";
cin >> r.firstname;
cout << "\nLast Name ";
cin >> r.lastname;
if ( AddItem ( r ) )
{
cout << "\nSuccess!\n";
}
else
{
cout << "\nItem failed to be added\n";
}
break;
case 2: //Delete
cout << "\nEnter id :";
cin >> idbuffer;
if ( DeleteItem ( idbuffer ) )
{
cout << "\nDelete OK\n";
}
else
{
cout << "\nDelete Failed for " << idbuffer;
}
break;
case 3: // Print
cout << "Enter order 0 - Ascending, 1 - Descending\n";
cin >> printorder;
PrintList (printorder);
break;
case 0: // quit
break;
default: // bad choice
break;
} // end switch
}
while ( choice != 0 );// end do while
} // end main

It may not seem like it, but even this function
int AddItem(Record entry)
{
Record* newRecordPointer;
newRecordPointer=new Record;
strcpy(newRecordPointer->firstName,entry.firstName);
strcpy(newRecordPointer->lastName,entry.lastName);
newRecordPointer->ID=new char[strlen(entry.ID)+1];
strcpy(newRecordPointer->ID, entry.ID);
return 0;
}
is trying to do too many things.
Let's write the pseudocode description of adding an item to a list:
create a new node
populate the new node with the values provided
attach the new node to the list
I've marked the verbs and nouns involved, and you can already see one of the nouns is missing from your function. You're asking AddItem to add an item to a list ... but you don't give it a list to work on.
It's also useful to write out your expectations clearly:
before AddItem is called:
it needs a list to work on
we don't have a list container class, just the records, so we have to pass a Record
let's say we want to add our new item after the Record passed in
after AddItem is called:
whatever Record we passed in, its Next should point to the new node
the new node's Previous should point to the node passed in
etc. etc. (these are the standard doubly-linked list insertion behaviours)
note for later: we haven't described how we store an empty list
if it's a circular list, an empty list will be a Record whose Next and Previous members point to itself
if it's linear, they might both be NULL instead
it could just be a NULL pointer, but then adding the first node to an empty list needs more effort
So, let's say the minimal function that could possibly work is:
void AddItem(Record *insert_after, Record value)
{
Record *new_node = CreateRecord();
CopyRecordValues(new_node, &value);
AttachAfter(insert_after, new_node);
}
Note that if we were writing real C++ the first two lines could just use the copy constructor Record *new_node = new Record(value), but it will take more changes than that to reach idiomatic C++ code from where we started.
Now, given that, can you:
implement those three functions? (CreateRecord and CopyRecordValues are already handled in your current code)
write the equivalent pseudocode for your other operations, and translate it yourself?

Try changing this:
int AddItem(Record entry);
To this:
Record* AddItem(Record entry, Record *insertion_point = NULL );
If insertion_point is NULL, you can assume that the Record is the beginning of a new list.
Now you have enough information to set Next and Previous pointers, and return the newly created node.

Related

Inserting a basic singly linked list node seems to break my c++ code?

Singly Linked List and Node classes and the start of the main function, where I wrote a brief outline of the code functionality. The issue is toward the end of the main function. I wrote '...' in place of what I believe to be irrelevant code because it simply parses strings and assigns them to the string temp_hold[3] array.
#include <bits/stdc++.h>
using namespace std;
class Node {
public:
string value;
string attr;
string tagname;
Node *next;
Node(string c_tagname, string c_attr, string c_value) {
this->attr = c_attr;
this->value = c_value;
this->tagname = c_tagname;
this->next = nullptr;
}
};
class SinglyLinkedList {
public:
Node *head;
Node *tail;
SinglyLinkedList() {
this->head = nullptr;
this->tail = nullptr;
}
void insert_node(string c_tagname, string c_attr,string c_value) {
Node *node = new Node(c_tagname,c_attr, c_value);
if (!this->head) {
this->head = node;
} else {
this->tail->next = node;
}
this->tail = node;
}
};
int main(int argc, char **argv) {
/* storage is a vector holding pointers to the linked lists
linked lists are created and the linked list iterator sll_itr is incremented when
previous line begins with '</' and the currentline begins with '<'
linked lists have nodes, which have strings corresponding to tagname, value, and attribute
*/
SinglyLinkedList *llist = new SinglyLinkedList();
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
string temp_hold[3];
// to determine new sll creation
bool prev = false;
bool now = false;
//input
int num1, num2;
cin >> num1; cin >> num2;
//read input in
for (int i = 0; i <= num1; ++i) {
string line1, test1;
getline(cin, line1);
test1 = line1.substr(line1.find("<") + 1);
//determine to create a new linked list or wait
if (test1[0] == '/') {
prev = now;
now = true;
} else {
//make a node for the data and add to current linked list
if (i > 0) {
prev = now;
now = false;
//if last statement starts with '</' and current statment starts with '<'
// then start a new sll and increment pointer to vector<SinglyLinkedList*>
if (prev && !now) {
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp);
sll_itr++;
}
}
//parse strings from line
int j = 0;
vector<string> datastr;
vector<char> data;
char test = test1[j];
while (test) {
if (isspace(test) || test == '>') {
string temp_for_vect(data.begin(),data.end());
if (!temp_for_vect.empty()) {
datastr.push_back(temp_for_vect);
}
data.clear();
} else
if (!isalnum(test)) {
} else {
data.push_back(test);
}
j++;
test = test1[j];
}
//each node has 3 strings to fill
int count = 0;
for (auto itrs = datastr.begin(); itrs!=datastr.end(); ++itrs) {
switch (count) {
case 0:
temp_hold[count]=(*itrs);
break;
case 1:
temp_hold[count]=(*itrs);
break;
case 2:
temp_hold[count]=(*itrs);
break;
default:
break;
}
count++;
}
}
cout << "before storing node" << endl;
(*sll_itr)->insert_node(temp_hold[0], temp_hold[1], temp_hold[2]);
cout << "after" << endl;
}
cout << "AFTER ELSE" << endl;
return 0;
}
And here is the line that breaks the code. The auto sll_itr is dereferenced which means *sll_itr is now a SinglyLinkedList* and we can call the insert_node(string, string, string) to add a node to the current linked list. However when I keep the line, anything after the else statement brace does not run, which means the cout<<"AFTER ELSE"<< endl; does not fire. If I remove the insert_node line, then the program runs the cout<<"AFTER ELSE"<< endl; I am unsure what the issue is.
(*sll_itr)->insert_node(temp_hold[0],temp_hold[1],temp_hold[2]);
cout << "after" << endl;
} //NOT HANGING. This closes an else statement.
cout << "AFTER ELSE" << endl;
return 0;
}
Compiled as g++ -o myll mylinkedlist.cpp and then myll.exe < input.txt And input.txt contains
8 3
<tag1 value = "HelloWorld">
<tag2 name = "Name2">
</tag2>
</tag1>
<tag5 name = "Name5">
</tag5>
<tag6 name = "Name6">
</tag6>
Your linked list isn't the problem, at least not the problem here.
A recipe for disaster in the making: retaining, referencing, and potentially manipulating, an iterator on a dynamic collection that potentially invalidates iterators on container-modification. Your code does just that. tossing out all the cruft between:
vector<SinglyLinkedList*> sllVect;
sllVect.push_back(llist);
auto sll_itr = sllVect.begin();
....
SinglyLinkedList *llisttemp = new SinglyLinkedList();
sllVect.push_back(llisttemp); // HERE: INVALIDATES sll_iter on internal resize
sll_itr++; // HERE: NO LONGER GUARANTEED VALID; operator++ CAN INVOKE UB
To address this, you have two choices:
Use a container that doesn't invalidate iterators on push_back. There are really only two sequence containers that fit that description: std::forward_list and std::list.
Alter your algorithm to reference by index`, not by iterator. I.e. man your loop to iterate until the indexed element reaches end-of-container, then break.
An excellent discussion about containers that do/do-not invalidate pointers and iterators can be found here. It's worth a read.

Store the address of an object inside a node

I'm trying to create an object of a class called Cell and store it in a linked list. I'm sure I could do this with an array, but part of my assignment is that I use a linked list and I didn't think I'd get this many problems. This is currently my node. Right now, I have all these variables stored in the node, but I'd rather create an object(Called "Cell") to store them. Info should be a pointer to an object of type T. Right now, that T should be of type Cell.
template<class T>
struct Node {
T *info;
Node<T> *nodeP;
Node<T> *linkP;
int nodeNumber = 0;
bool purchased = false;
std::string color = " ";
int index = 0;
int max_num = 0;
std::string name = " ";
int price;
};
In here I am creating the node and adding it to a linked list. At the moment I'm just filling in values of the node, but I'm trying to create an object of type Cell and assign it's address to the pointer info. I've tried a couple different ways but keep coming back with errors. I commented them out so you can see what I've tried.
template<class T>
void Board<T>::setCellValue() {
//open file
ifstream inFile;
string line;
inFile.open("CellValues.txt");
//Check for Error
if (inFile.fail()) {
cerr << "File does not exist!";
exit(1);
}
int index = 0, max_num = 0, count = 0, price = 0;
string color, name;
istringstream inStream;
while (getline(inFile, line)) {
inStream.clear();
inStream.str(line);
inStream >> color >> index >> max_num >> name >> price;
//creates node
Node<T> *newNodeP = new Node<T>;
//create pointer, assign pointer to pointer in Node
//Cell<T> *cellPtr = new Cell<T>(count, name, color, index, max_num, price);
//newNode->info= cellPtr;
//creating anonymous object and assigning to the node? I think
newNodeP->info = new Cell<T>(color, index, max_num, name, price);
//weird way I was just experimenting with
newNodeP->info->Cell<T>(count, name, color, index, max_num, price);
//fills node values(this is what I want to handle in the object
newNodeP->color = color;
newNodeP->index = index;
newNodeP->max_num = max_num;
newNodeP->name = name;
newNodeP->nodeNumber += count;
newNodeP->price = price;
newNodeP->linkP = NULL;
if (firstP != NULL)
lastP->linkP = newNodeP;
else
firstP = newNodeP;
lastP = newNodeP;
count++;
}
}
Currently, I have two ways of returning the node landed on. One returns a Node* and sort of works. It returns the pointer to the node, and I can access the values inside that node, but I can't figure out how to store the pointer to that node.
//Find Cell
template<class T>
Node<T>* Board<T>::findCell(int id) {
for (Node<T> *traverseP = firstP; traverseP != NULL; traverseP = traverseP->linkP) {
if (traverseP->nodeNumber == id) {
return traverseP;
}
}
return nullptr;
}
//how I call it in main. it returns an address to that node, but I'm getting errors trying to store that address in a pointer.
cout << "You landed on cell " << gameBoard.findCell(player.getCellNum()) << endl << endl;
Node<T> *ptr = gameboard.findCell(player.getCellNum())->info;
This second way, I think returns the reference to the object in the node, but my earlier problem is stopping me from figuring that out.
//Return Cell
template <class T>
T Board<T>::returnCell(int id) {
for (Node<T> *traverseP = firstP; traverseP != NULL; traverseP = traverseP->linkP) {
if (traverseP->nodeNumber == id) {
return traverseP->info;
}
}
return nullptr;
}
//How i'm calling it in main. I don't really know what it's returning though because it only prints "You landed on " and then nothing else.
cout << "You landed on " << gameBoard.returnCell(player.getCellNum()) << endl;

Reading data from a file into a linked list, and searching for elements in the linked list

I am trying to write code and am taking in data from a file and storing it into a struct and creating a linked list. I don't see any immediate problems with my code but I made a function to check if a zipcode exists within any of the structs in the linked list and it doesn't seem to be working. Here's what the data from the file looks like:
id,price,bedrooms,bathrooms,sqft,yr_built,zipcode
1370804430,543115,2,1,1380,1947,98199
3744000040,518380,4,2.5,2810,2014,98038
3313600266,190000,3,1,1180,1966,98002
EDIT I implemented new code for reading the file into a linked list but my function for finding the zipcode isn't working. When I enter a zipcode I know exists in the file, nothing gets printed.
typedef struct housetype house;
struct housetype{
int id;
int price;
int bedrooms;
double bathrooms;
int sqft;
int year;
int zipcode;
house *next; };
int findzipcode(house* head, int zip){
house* current = head;
while(current != NULL){
if(current->zipcode == zip){
cout << "Zipcode exists" << endl;
return 1;
break;}
current = current->next;
}
return 0;}
int main(){
house *head = NULL;
FILE *houseinfo = NULL;
houseinfo = fopen("house-info-v4.txt", "r");
if (houseinfo == NULL) {
cout << "Error reading file" << endl;
}
else {
int res;
house *last = head;
house h;
do {
res = fscanf(houseinfo, "%d,%d,%d,%lf,%d,%d,%d",
&h.id, &h.price, &h.bedrooms, &h.bathrooms,
&h.sqft, &h.year, &h.zipcode);
if (res > 0) { // <== fscanf successful (if file fits!)
house *n = (house*)malloc(sizeof(house));
memcpy(n, &h, sizeof(house));
n -> next = NULL;
if (last) last->next = n;
if ( ! head) head = n;
last = n;
}
} while (res > 0);
}
int zip;
cout << "Enter a zipcode" << endl;
cin >> zip;
findzipcode(head, zip);}
The code you present will only load the first item, so if you are searching for later items it won't work.
Notice how the code with the fscanf doesn't have a loop.
I think you read only one row from data and made one node for linked list. If you want to make linked list then you have to read all rows from file and create node of each row and link it with loop.
For example
while (1)
read_file
if feof:
break
make_node
add row_info -> node
link_node
Trying to write this code with c++
At least two problems
head remains NULL
only one house is read from the file
Try something like
if (houseinfo == NULL) {
cout << "Error reading file" << endl;
}
else {
int res; // <== fscanf result
house *last = head; // <== last house set (head is still null)
house h; // <== holds values until fscanf check
do {
res = fscanf(houseinfo, "%d,%d,%d,%lf,%d,%d,%d",
&h.id, &h.price, &h.bedrooms, &h.bathrooms,
&h.sqft, &h.year, &h.zipcode);
if (res > 0) { // <== fscanf successful (if file fits!)
house *n = (house*)malloc(sizeof(house)); // c++ cast malloc
memcpy(n, &h, sizeof(house)); // <== copy to allocated house
n -> next = NULL;
if (last) last->next = n; // last next is our n
if ( ! head) head = n; // set head if necessary
last = n; // last house set is n, now
}
} while (res > 0);
}
Explanations are in comments. Basically
loop on fscanf until no more lines in file
read values in local variable h
if fscanf successful, allocate and set n
if we have a last, set its next to our new n
if head not set yet, set it
finally, last points to n to be used at next iteration
First of all select a language. Either C or C++.
There is a problem in your code. The thing is, you have memory leak here and that in one way is the reason for the problem.
Well to say it in detail, you allocate memory and get input and store it in that memory and then you forget about it. You don't forget but yes there is no way you can access it. This is the memory leak. And then you pass a NULL valued pointer to the search function and it returns nothing.
This change will solve the problem,
house *n = malloc(sizeof(house));
head = n; //<----- We are not losing the allocated memory
fscanf(houseinfo, "%d.....
..
Also there is one redundant thing in your code (this is not causing the problem but yes you should know this).
cout << "Zipcode exists" << endl;
return 1;
break; //<--- this is redundant
}
Once a return statement is executed that break will never be executed. Just put the return statement. No use putting the break here.
Another point you didn't free the allocated memory.(Ah! to free you need to keep track of it - which you didn't do here). After you are done working with it you should free it.
findzipcode(head, zip);
free(head);
Also check the return value of malloc. In case it returns NULL take necessary action.
in the following proposed code:
error conditions are checked and acted upon
most of the comments to the question are incorporated
And now, the proposed code:
#include <cstdio>
#include <cstdlib>
#include <errno.h>
struct housetype
{
int id;
int price;
int bedrooms;
double bathrooms;
int sqft;
int year;
int zipcode;
struct housetype *next;
};
typedef struct housetype house;
void findzipcode(house* head, int zip)
{
house* current = head;
while( current )
{
if(current->zipcode == zip)
{
cout << "Zipcode exists" << endl;
return;
}
current = current->next;
}
}
int main( void )
{
house *head = NULL;
FILE *houseinfo = fopen("house-info-v4.txt", "r");
if ( !houseinfo )
{
cerr << "fopen failed due to" << strerror( errno ) << endl;
exit( EXIT_FAILURE );
}
// implied else, fopen successful
int res;
house *last = NULL;
house h;
while( 7 == (res = fscanf(houseinfo, "%d,%d,%d,%lf,%d,%d,%d",
&h.id, &h.price, &h.bedrooms, &h.bathrooms,
&h.sqft, &h.year, &h.zipcode) ) )
house *n = new house;
if( !n )
{
cerr << "malloc failed due to: " << strerror( errno ) << endl;
exit( EXIT_FAILURE );
}
// implied else, malloc successful
memcpy(n, &h, sizeof(house));
n -> next = NULL;
if (last)
last->next = n;
else if ( ! head)
head = n;
last = n;
}
int zip;
cout << "Enter a zipcode" << endl;
cin >> zip;
findzipcode(head, zip);
while( head )
{
house *nextHouse = head->next;
delete head;
head = nextHouse;
}
}
Of course, if you really want to use C++, then suggest using a vector rather than a linked list

Doubly Linked List of Structures - Overwriting

So I am attempting to make a program in C++ that performs basic operations on a doubly linked list. The main problem I am having is that every time I add a new element to the list, the id field I enter for the new element overwrites the id fields of all other elements. The id field is the only field that does this, which is extremely confusing to me. I believe my error could lie somewhere in my use of pointers, as this is my first program in C++ using them to manage a list(Pointers in Ada seem much simpler to me). I have ran my program through GDB step-by-step multiple times and still can't seem to determine what is causing the problem. This leads me to believe that it could be a logic error on my part.
Here is my main:
#include <iostream>
#include "list.h"
#include <string.h> // <string>
using namespace std;
int main (void)
{
int choice, printorder;
char idbuffer[100];
rec r;
do
{
cout << "Enter your choice: 1 - Add, 2 - Delete, 3 - Print, 0 - quit. " <<endl;
cin >> choice;
switch ( choice )
{
case 1: //AddItem
cout << "\nEnter ID ";
cin >> idbuffer;
r.id = idbuffer;
cout << "\nFirst Name ";
cin >> r.firstname;
cout << "\nLast Name ";
cin >> r.lastname;
if ( AddItem ( r ) )
{
cout << "\nSuccess!\n";
}
else
{
cout << "\nItem failed to be added.\n";
}
break;
case 2: //Delete
cout << "\nEnter id: ";
cin >> idbuffer;
if ( DeleteItem ( idbuffer ) )
{
cout << "\nDelete OK.\n";
}
else
{
cout << "\nDelete Failed for: " << idbuffer << endl;
}
break;
case 3: // Print
cout << "Enter order: 0 - Ascending, 1 - Descending. \n";
cin >> printorder;
PrintList (printorder);
break;
case 0: // quit
break;
default: // bad choice
break;
} // end switch
}
while ( choice != 0 );// end do while
} // end main
Here is my file list.h:
struct rec
{
char * id;
char firstname[15];
char lastname[15];
rec* prev;
rec* next;
};
int AddItem ( rec r );
int DeleteItem ( char* delid );
void PrintList ( int order );
And finally the AddItem function from my file list.cpp:
#include <iostream>
#include "list.h"
#include <string.h>
using namespace std;
rec * first = NULL;
rec * last = NULL;
int AddItem( rec r )
//Return: 1 if a success, 0 if failed.
//No duplicate id's, sort by lastname
{
rec * ptr = NULL;
rec * current;
rec * myStruct = new rec;
myStruct -> id = r.id;
strcpy(myStruct -> firstname, r.firstname);
strcpy(myStruct -> lastname, r.lastname);
ptr = first;
//Check for duplicate id's, currently commented out due to id's being overwritten
//while (ptr)
//{
// if (ptr -> id == myStruct -> id)
// {
// return 0;
// }
// ptr = ptr -> next;
//}
//ptr = first;
if (first == NULL) //Empty
{
first = myStruct; //Inserts node into empty list
last = myStruct;
myStruct -> prev = NULL;
myStruct -> next = NULL;
return 1;
}
else if (myStruct -> lastname > last -> lastname) //Add to end of list
{
last -> next = myStruct;
myStruct -> prev = last;
last = myStruct;
return 1;
}
else if (myStruct -> lastname && myStruct -> lastname < first -> lastname) //Add to beginning of list
{
ptr = first;
first = myStruct;
myStruct -> next = ptr;
ptr -> prev = myStruct;
return 1;
}
else
{
current = first;
while (current)
{
if (myStruct -> lastname > current -> lastname && myStruct -> lastname <= current -> next -> lastname)
{
ptr = current -> next;
current -> next = myStruct;
myStruct -> prev = current;
myStruct -> next = ptr;
ptr -> prev = myStruct;
return 1;
}
else
{
current = current -> next;
}
}
return 0;
}
I'm sure there are other errors throughout this code and some sloppy programming, but I plan on fixing those up and making the program neater/more efficient after I work out this overwriting problem, as it is also holding me back from testing other parts of my program. Thanks in advance and sorry for the lengthy post.
Update1: After realizing I needed to change the line
myStruct -> id = r.id;
to a string copy, such as:
strcpy(myStruct -> id, r.id);
I am now receiving a segmentation fault.. I would imagine something with my pointers is messed up. Back to work I go and thanks for all the help so far!
Update2: After much more editing and quite a few more errors, I have the program working! I am now in the process of cleaning things up and optimizing the program. Thanks to everyone for the great advice!
All id objects have the same value - the address of the first character of idbuffer.
In main
cin >> idbuffer;
r.id = idbuffer;
^^^^^^^^^
and then further in AddItem
int AddItem( rec r )
//Return: 1 if a success, 0 if failed.
//No duplicate id's, sort by lastname
{
rec * ptr = NULL;
rec * current;
rec * myStruct = new rec;
myStruct -> id = r.id;
^^^^^
//...
You should dynamically allocate memory that will be pointed to by id and there the actual string with id will be copied. Or you should declare data member id as a character array.
For example in main
cin >> idbuffer;
r.id = new char[std::strlen( idbuffer ) + 1];
std::strcpy( r.id, idbuffer );
and in AddItem
rec * myStruct = new rec( r );
A better approach is to use an object of type std::string.

getting mergesort to work on linked-list?

Apologies if this is a silly / simple question.. but I'm very lost. I'm having trouble getting this program to run. I've written this program to read in 2 values, the first being a number of elements in a linked list, and the second to be the maximum random value that can be put into each element.
It should then use the merge sort algorithm included to sort and reprint the sorted list.
Ok, so I'm getting errors like:
base operand of `->' has non-pointer type `LIST'
and
request for member `element' in `conductor', which is of non-aggregate type `LIST *'
...(and a few others).
Yes this is for a class.. I've written the program but I'm not sure what I've done wrong here or why I'm getting errors? Any help is appreciated! Thank you
#include <cstdlib>
#include <iostream>
#include <math.h>
#include <sys/time.h>
using namespace std;
typedef struct LIST {
int element;
LIST *next;
};
LIST split(LIST list)
{
LIST pSecondCell;
if (list == NULL)
return NULL;
else if (list.next == NULL)
return NULL;
else {
pSecondCell = list.next;
list.next = pSecondCell.next;
pSecondCell.next = split(pSecondCell->next);
return pSecondCell;
}
}
LIST merge(LIST list1, LIST list2)
{
if (list1 == NULL)
return list2;
else if (list2 == NULL)
return list1;
else if (list1.element <= list2.element) {
list1.next = merge(list1.next, list2);
return list1;
} else {
list2.next = merge(list1, list2.next);
}
}
LIST MergeSort(LIST list)
{
LIST SecondList;
if (list == NULL)
return NULL;
else if (list.next == NULL)
return list;
else {
SecondList = split(list);
return merge(MergeSort(list), MergeSort(SecondList));
}
}
int main(int argCount, char *argVal[])
{
int i, number, max;
struct timeval time1;
struct timeval time2;
//check for correct number of arguments
if (argCount != 3) {
cout << "Incorrect number of arguments" << endl;
return 0;
}
// initialize read in n and max values
number = atoi(argVal[1]);
max = atoi(argVal[2]);
// create list and fill with random numbers
LIST *conductor;
LIST *root = new LIST;
conductor = root;
for (i = 0; i < number; i++) {
conductor.element = rand() % max;
conductor.next = new LIST;
conductor = conductor.next;
}
// time how long it takes to sort array using mergeSort
gettimeofday(&time1, NULL);
mergeSort(root);
gettimeofday(&time2, NULL);
// print name, sorted array, and running time
cout << "Heather Wilson" << endl;
conductor = root;
for (i = 0; i < number - 2; i++) {
cout << conductor.element << ", ";
conductor = conductor.next;
}
double micro1 = time1.tv_sec * 1000000 + time1.tv_usec;
double micro2 = time2.tv_sec * 1000000 + time2.tv_usec;
cout << conductor.element << endl;
cout << "Running time: " << micro2 - micro1 << " microseconds" << endl;
return 0;
}
For base operand of->' has non-pointer type LIST'
Replace the -> with a .. You want to access a member of a local LIST, not a member of a pointed at object.
request for memberelement' in conductor', which is of non-aggregate type LIST *
This is the opposite. Replace the . with a ->. You want to access a member of the pointed at LIST, not a member of the pointer.
For clarification, I didn't read the code. There's too much of it. But those are the usual ways to address those specific errors. parapura seems to have actually read the code.
First: you should never have let the code grow this big with so many errors. You should start small and simple, then build up, testing at every stage, and never add to code that doesn't work.
Here's a stripped-down beginning of your code, with some bugs fixed:
#include <iostream>
using namespace std;
typedef struct LIST{
int element;
LIST *next;
};
int main(){
int i, number, max;
number = 5;
max = 100;
// create list and fill with random numbers
LIST *conductor;
LIST *root = new LIST;
conductor = root;
for(i=0; i<number; i++){
conductor->element = rand() % max;
cout << "element " << i << " is " << conductor->element << endl;
conductor->next = new LIST;
conductor = conductor->next;
}
conductor = root; // Forgot this, didn't you!
for(i=0; i<number-2;i++){
cout << conductor->element << ", ";
conductor = conductor->next;
}
return 0;
}
Take a look at this, verify that it works, make sure you understand the changes I made, then you can take a crack at implementing your split, merge and MergeSort functions and the I/O (one at a time, and testing at every stage, naturally).
I think all the places you are passing
LIST merge ( LIST list1 , LIST list2 )
it should be
LIST* merge ( LIST* list1 , LIST* list2 )