c++ outputting and inputting a single character - c++

I am writing a program in c++ which implements a doubly-linked list that holds a single character in each node. I am inserting characters via the append function:
doubly_linked_list adam;
adam.append('a');
This function is implemented as follows:
//Append node
node* append(const item c){
//If the list is not empty...
if(length){
//maintain pointers to end nodes
node* old_last_node = last;
node* new_last_node = new node;
//re-assign the double link and exit link
old_last_node->next = new_last_node;
new_last_node->back = old_last_node;
new_last_node->next = NULL;
//re-assign the last pointer
last = new_last_node;
}
//If this is the first node
else{
//assign first and last to the new node
last = first = new node;
//assign nulls to the pointers on new node
first->next = first->back = NULL;
}
//increase length and exit
++length;
return last;
}
However, I think there is an issue, perhaps with the way C++ handles characters. When I go to print my list, somehow I never get the characters to print which I have appended to my list. This is what I'm using to print:
//Friendly output function
friend std::ostream& operator << (std::ostream& out_s, const doubly_linked_list& source_list){
//create iteration node pointer
node* traverse_position = source_list.first;
//iterate through, reading from start
for(int i = 1; i <= source_list.length; ++i){
//print the character
out_s << (traverse_position->data);
traverse_position = traverse_position->next;
}
//return the output stream
return out_s;
}
I just get crap when I print it. It prints characters that I never appended to my list - you know, just characters just from somewhere in the memory. What could possibly be causing this?

Where are you assigning the value c in the append() function? I fear you may have concentrated too much on the doubly-linked-list part and not enough on the storing-data part. :)

As others have already mentioned, you forgot to store the characters you were supposedly appending. It's a reasonable mistake to make. To avoid it in the future, you can let the compiler help you.
Most compilers offer warnings about things that are technically OK, but probably aren't what you really want to do. In your case, you declared the parameter c, but you never used it. With warnings enabled, your compiler could have noticed that and told you that you hadn't used it. That would probably have been enough of a reminder for you that you weren't finished writing that function.
GCC's option to enable common warnings is -Wall. (That's "W" for "warning," plus "all"; it has nothing to do with walls. But it's not really all warnings, either.) For example:
g++ -Wall list-program.cpp
Other compilers have similar options. Check your compiler's documentation for details.

No where in your append method do you actually place the item into the new node. When you go to print, it just prints whatever value happens to be in that memory location (some random value).

Related

Trying to make a sorted dynamic list ( data structure)

Good evening everyone. The program which I am making right now is related to sorting and data structure. I have already inputted some values in my list. I want to sort them, in order to do so I extract the values present at each individual node into an array and then sort the array. I am having a confusion regarding putting the sorted values into the list.
This is the code which contains the structure, class and function definition ( the full definition of class is not mentioned)
#define max 30
struct data
{
int val,index;
data* next;
};
class exp
{
data* beg;int count;
int arr[max];
public:
exp()
{beg = NULL;
count = 0;}
};
The confusion I am having is because of this:
void exp :: sort_ins()
{
sort();
data* temp = beg;
int i = 0;
do
{
temp -> val = arr[i];
temp = temp -> next;
i++;
}while(i < count && temp != NULL);
}
My question is that after changing the values associated with temp ( which is basically going from beginning to end) will actually change the value of nodes associated with "beg"? I mean to say that after executing this code, if I try to obtain value of nodes attached to "beg", would the values have been updated? Or do I need to add something else? If possible, I would like a link to relevant theory for learning purposes( purely optional).
Thank you for your time..
(I haven't given the full code, I can share if required.)
Yes, changing what temp is pointing at also changes was beg is pointing at because they're both pointing at the same data.
If you copy a pointer, you end up with two pointers pointing at the same thing. And either pointer could be used to change that thing. That's how pointers work.

How to manage an array of pointers to a struct

I have the following struct:
struct Item
{
Item* nextPtr;
int intKey;
int intValueLength;
};
Based of such a struct I need to maintain several linked lists, which means I need to keep track of one head pointer for each one. I have thought about using an array (HEADS) which will contain a head pointer for each list. The number of lists is variable and will be calculated at run time so I am defining the array dynamically as follows:
int t = 10;
Item* HEADS = new Item[t];
Firstly, I need to initialize each head pointer to NULL because the linked lists are empty when the program runs. How do I do this initialization?
for (int i = 0; i <= t - 1; i++)
// Initialize each element of HEADS to NULL.
And, of course, I will also need to update each element of HEADS with the proper pointer to a linked list (when inserting and deleting items) and also to get the value of each head pointer to display the elements of each list.
I have seen other posts similar to this one in the forum but I am still confused, that is why I am asking my specific situation.
Is this a good approach?
I will very much appreciate your advice.
Respectfully,
Jorge Maldonado
In C++ the common way to write the initialization for loop would be
for (int i = 0; i < t ; i++)
HEADS[i] = NULL;
Or you could write
for (int i = 0 ; i < t ; HEADS[i++] = NULL);
which is slightly more compact.
As to the question of whether an array of pointers is a good idea or not - if you're going to have a variable number of lists, perhaps you should use a linked list of pointers to other linked lists.
I do wonder about your data structure, though. In it you have a pointer to the next element in the list, a key value, and a the length of the value, but you don't appear to have a reference to a value - unless the "key" is really the value, in which case you have mixed terminology - that is, you refer to something in one place as a "key" and in another as a "value. Perhaps you need a pointer to a "value"? But I don't know what you're trying to do here so I just thought I'd note that issue.
Best of luck.
Good approach? That's a very, very dependent on things. Good for a student starting to learn C, maybe. Good for a real C++ programmer? Absolutely not. If you really want to create a linked-list, you should make a class that encompasses each element of these, and dynamically add elements. This is how std::list, for example, works. (std::list is doubly-linked list, and way more complicated).
Here's a sample class of how this should look like (off the top of my head; haven't compiled it, but should work):
struct LinkedList
{
Item* list;
int size = 0;
LinkedList() //constructor of this class/struct, it's the function that will be called once you create an object of LinkedList
{
list = nullptr; //don't use NULL, it's deprecated (this is for C++11, or change it back to NULL if you insist on using C++98)
}
addItem(const int& key)
{
Item item; //construct a new item
item.intKey = key; //fill the value in the item
Item* newList = new Item[size+1]; //create the new list with one more element
for(int i = 0; i < size; i++) //copy the old list to the new list
{
newList[i] = list[i]; //copy element by element
}
list[size] = item; //fill in the new item
if(size > 0)
{
list[size - 1].nextPtr = &list[size]; //assign "next pointer" for previous element
}
size = size+1; //increase the size of the list
}
~linkedList()
{
if(list != nullptr)
{
delete[] list;
}
}
}
Now this is better, but it's still far from optimal. However, this is how C++ should be used. You create objects and deal with them. What you did above is more like C, not C++.
To my code, you have to call:
LinkedList myList;
myList.addItem(55);
There are many things to do here to make this optimal. I'll mention a few:
In my code, every time you add an item, a new array is allocated. This is bad! std::vector solves this problem by allocating a bigger size than needed (for example, you add 1 item, it reserves 10, but uses only 1, and doesn't tell you that). Once you need more than 10, say 11, it reserves 20, maybe. This optimizes performance.
Try to read my code and understand it. You'll learn so much. Ask questions; I'll try to answer. And my recommendation is: get a C++ book, and start reading.

c++ Program won't run properly on Mac but will on Windows

/*********************************************************************************************
* Function: Appends the Node newelement to the end of the List
*********************************************************************************************/
void append(const T &newelement)
{
Node *N = new Node(newelement);
if(first == (Node*)0)
{
first = N;
last = N;
_length = 1;
}
else
{
last->insertNodeAfter(N);
last = N;
_length++;
}
};
/*********************************************************************************************
* Function: Appends the Node newelement to the end of the List
*********************************************************************************************/
void prepend(const T &newelement)
{
Node *N = new Node(newelement);
if(first == (Node*)1)
{
first = N;
last = N;
_length = 1;
}
else
{
first->insertNodeBefore(N);
first = N;
_length++;
}
};
AS PEOPLE have told me off, I've narrowed it down to this code sort of... it breaks when its trying to ADD a node to the List. Giving me access errors and such. (BUT ONLY SOMETIMES)
On first glance, for example first == (Node*)1 (in prepend) is illegal/undefined and will give random behavior. Depending on memory layout of the chip and the OS, this will survive, work sometimes, work always, fail randomly, or fail always. It is not surprising at all that a Mac and a x86 chip behave differently.
There are multiple other assumption in the code, like an int is large enough for things; etc.
All these rules that people tend to gloss over have a reason, and many of these errors you get away with on one architecture,but not on another one.
Before you erroneously removed the relevant parts of your code from the question, the bug was fairly obvious.
DoubleLinkedNode's constructor fails to initialize the nextNode and previousNode class members to NULL. This results in undefined behavior.
Just because a C++ program crashes on a particular line, that doesn't mean that's where the bug is.
You are crashing when you're adding a new node to the list.
But the bug is that insertNodeAfter() is dereferencing an uninitialized pointer. And the bug is because the constructor is failing to initialize them to NULL.

Just trying to insert a node and set the pointer in it to the next node C++

I feel really silly asking this, as it seems really simple, but I just can't figure it out. All I want to do is set the node pointer to the next node in the list. The function is from a teacher, I wrote the body, so I don't want to mess with the head of the function.
void LList::insert(int num, int at)
{
node* n = new node(num);
if (!n) throw runtime_error("Can't allocate node!");
if(!root || at == 0){
// if empty list - new node is root…
if (!root) root = n;
}
if(root){
node* nextNode = new node(num);
int numF = 0;
for (node* t = root; t != NULL ; t = t->next){
numF++;
if(numF == at){
n->next=t->next;
t->next=n;
}
}
}
}
Since it seems you are using n for the new node to be inserted into the linked list (I'm inferring that it's a singly linked list from the existing code and class name), there are a few things you have to do off the top of my head:
Identify the existing member of the list after which the new node will be inserted. You are making an attempt to do this already with that for loop, but in my opinion you may want to rewrite that as a while loop since you probably don't want it to keep iterating after the insertion position has been identified. Alternately, you could short-circuit out of the for loop with a break once you've found the right place for insertion, but I don't like that for stylistic reasons. :)
Set the newly inserted node's next pointer to the same location to which the next pointer of the node identified in #1.
Set the next pointer of the node identified in #1 to point at the new node, thus re-establishing the integrity of the chain.
Your code looks like it is attempting to do #2 and #3 out of order, which won't work. You're obliterating the value of t->next before you've had a chance to point n->next at it.
Finally, you may need to define some behavior to which you can fall back in case you are adding to a position not already defined in the list (i.e. inserting into the fourth position of a linked list that currently has three elements). You may need to re-jigger your loop to terminate when t->next is null rather than when t itself is null - otherwise you lose the hook to be able to connect the (currently) last element of the list to your new node.

Changing a line in linked list reversal causes error

This question is probably one of the most popular questions around and while searching for a solution, I've found many but the code below was the most suitable for me.
What it actually does is that it creates another list and iterates through the old list and add the element always to the head of the new list.
Node *reverseList(Node *oldList)
{
Node* newList=NULL;
while(oldList!=NULL)
{
Node *temp=oldList;
oldList=oldList->next;
temp->next=newList;
newList=temp;
}
return newList;
}
However when I decided to re-implement this idea without looking at this code I've changed place of the oldList=oldList->next; and put it after the newList=temp.
My question is does it really make a difference? I couldn't comprehend the reason because after all you are iterating through the oldList. Why would it require to be done immediately after the *temp declaration?
After doing
Node *temp = oldList;
both pointers point at the same place. Since
temp->next = newList;
will overwrite the next pointer of oldList (because it points to the same thing as temp at this stage), you need to update oldList from its next pointer first.