recently, while reading former's code in my current project, I encounter the problems below:
while implementing the Queue, my former wrote codes like this:
while(uq->pHead)
{
char *tmp = uq->pHead;
uq->pHead = *(char **)tmp;
//...
}
the uq->pHead has definition like:
typedef struct {
char* pHead;
//...
} Queue;
Well, I'm quite confused about the usage that "uq->pHead = *(char**)tmp" , could anyone explain it to me in detail?
if we assume that *(uq->pHead) = 32(i.e. ' ') , *(char**)tmp would translate this into pointer-form, but...how could it make sense?
Thanks a lot.
Let's suppose that we're implementing your Queue as a linked list. We might have:
struct data_type;
struct node
{
node *next;
data_type item;
};
struct linked_list
{
node *pHead;
// ...
};
To empty the linked list, we might write:
linked_list *uq=...;
while (uq->pHead)
{
// unlink the first node from the list
node *tmp = uq->pHead;
uq->pHead = tmp->next;
// do something with that node
// ...
// deallocate the node
free(tmp);
}
Now suppose we don't really care about maintainable code, or are otherwise being lazy. We might instead just figure any pointer would do, and keep the structure for 'node' in our head, and write:
linked_list *uq=...;
while (uq->pHead)
{
// unlink the first node
char *tmp = uq -> pHead; // tmp points to the first 'node'
uq -> pHead = *(char**)tmp; // The first thing in a 'node' is a pointer to
// the next node.
// do something with 'tmp', the now unlinked node
data_type *item=(data_type*) ( ((char**)tmp) + 1 ); // after the 'next' pointer
// is the real data.
// ...
// free up the node
free(tmp);
}
The Queue struct is likely to be... a queue. And it seems its first element is a pointer to the next or previous item of the queue. It sounds like the coder was not confortable with having to use the type he is being creating - Queue - inside the Queue itself.
A solution for instance was
typedef struct Queue {
struct Queue *pHead;
//...
} Queue;
Back to your question,
char *tmp = uq->pHead;
set tmp to the current Queue item (save it for later use)
uq->pHead = *(char **)tmp;
set the uq->pHead pointer value to the pHead of the current item. Since the coder didn't declare appropriately the pHead ( char * instead of struct Queue * ) it casts the structure pointer ( uq->pHead == tmp ) to char ** and then *(char **) it to retrieve the the first pointer of the structure, that is pHead.
Using my above declaration, the code could have been
while(uq->pHead)
{
Queue *tmp = uq->pHead;
uq->pHead = tmp->pHead; // or uq->pHead = uq->pHead->pHead
//...
}
In this queue pHead is pointer to another pHead.More appropriately it can be written as:
void *pHead;
Also tmp can be written as:
void *tmp;
tmp = uq->pHead;
saves the current pHead pointer to tmp variable.
Now, tmp is casted as (void **) so that tmp is seen as pointing to another pointer.
*(void **) tmp; is the value at tmp, which is also seen as pointer.
uq->pHead = *(void **) tmp;
So, this increments the pHead to next element.
This statement can also be written as:
uq->pHead = uq->pHead->pHead;
I am sorry, if i confused you.
Assume your Queue struct has a object named qa, the address of qa's first data is the same as qa's. In C++, you have many ways to invoke data such as,".","->" . But they are all really use offset just like
`#include<cstdio>
using namespace std;
class A
{
public:
int a;
int b;
};
int main()
{
A a;
printf("%p\n",&a);
printf("%p\n",& A::a);
printf("%p\n",& A::b);
printf("%p\n",&(a.a));
printf("%p\n",&(a.b));
return 0;
}`
You can get what you want from this code.
Related
Doing a self-impl queue in C++. The question is about adding the first element. I know there's an obvious way of ckecking if head is NULL then we also change head, if no then we don't touch it. But I was told there's another way which I didn't understand. The example was like this:
first = (QueueNode*)&last;
then I should assign last element and no if-check required. But it actually doesn't work, so is there a way to implement what I'm talking about and what did I get wrong?
struct QueueNode
{
T data;
QueueNode* next;
} *first, *last;
edit:
The usual way we implement Enqueue operation is
void Enqueue(T data)
{
QueueNode* node = new QueueNode();
node->data = data;
node->next = last;
last = node;
if (first == NULL) first = last; // <- THIS is what I want to get rid off
}
The error is here:
first = (QueueNode*)&last;
where :
struct QueueNode
{
T data;
QueueNode* next;
} *first, *last;
you already declare last as pointer, then when you assign it to first you dereference again this pointer.
So you have a pointer to pointer to the QueueNode struct.
I am learning list in C++ independently, and i have searched many websites about it. However, almost every approach to create a list is the same.
They usually create a struct as the node of a class. I want to create a class without using struct. So I created a class name ListNode which contains an int data and a pointer.
The main member functions of my class are AddNode and show.
Although, this program compiles successfully, it still does not work as I wish.
Here is the header file:
#ifndef LISTNODE_H_
#define LISTNODE_H_
#pragma once
class ListNode
{
private:
int data;
ListNode * next;
public:
ListNode();
ListNode(int value);
~ListNode();
void AddNode(ListNode* node,ListNode* headNode);
void show(ListNode* headNode);
};
#endif
Here is the implementation:
#include "ListNode.h"
#include<iostream>
ListNode::ListNode()
{
data = 0;
next = NULL;
}
ListNode::ListNode(int value)
{
data = value;
next = NULL;
}
ListNode::~ListNode()
{
}
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
node->next = headNode;
headNode =node;
}
void ListNode::show(ListNode* headNode) {
ListNode * traversNode;
traversNode = headNode;
while (traversNode != NULL) {
std::cout << traversNode->data << std::endl;
traversNode = traversNode->next;
}
}
Main function:
#include"ListNode.h"
#include<iostream>
int main()
{
using std::cout;
using std::endl;
ListNode* head = new ListNode();
for (int i = 0;i < 3;i++) {
ListNode* Node = new ListNode(i);
head->AddNode(Node, head);
}
head->show(head);
return 0;
}
As far as I am concerned, the output should be
2
1
0
However, the output is a single zero. There must be something wrong in the AddNode and show function.
Could you please tell me what is wrong with these two functions?
When you call head->AddNode(node, head) you´re passing the memory directions which the pointers point, when the function arguments receive those directions, they are now pointing to the same directions, but those are another pointers, no the ones you declared in main. You could see it like this:
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
/*when the arguments get their value it could be seen as something like:
node = Node(the one from main)
headNode = head(the one from main)*/
node->next = headNode;
/*Here you are modifying the new inserted node, no problem*/
headNode = node;
/*The problem is here, you´re modifying the memory direction
headNode points to, but the headNode argument of the function, no the one declared in main*/
}
So the pointer head in main() always points to the same first node you also declared in main().
In order to fix this you should change your code this way:
void ListNode::AddNode(ListNode* node,ListNode** headNode) {
/* second paramater now receives a pointer to apointer to a node */
node->next = *headNode;//the same as before but due to pointer syntaxis changes a bit
*headNode = node;//now you change the real head
}
And when you call it:
head->AddNode(Node, &head);//you use '&' before head
Now the real head, no the one in the function, will point to the last node you inserted.
So I have a stack with the typical Push and Pop functions that it allows. I'm having a hard time wrapping my head around how it all actually works code-wise. I saw this post here,
Picture/Diagram in the best answer that shows how the list is "pushed" down and you point at the newest element. I have a
node* stack;
which is hooked to a struct "node"
struct node
{
ItemType data;
node* next;
};
How do I incorporate a push and pull with a "node* next;" ? The hard part to wrap my head around is how I'm going to actually do it. I know it initially points at null, and then if I were to push a 2,4,6 it would be 6,4,2,#. Grasping how to actually do it with pointers in a linked list throws me for a loop. I can do it without pointers but the pointers are what get me. Thank you for any help, I really wanna work through this. I'm here to comment back too quickly. Thanks!
EDIT 1:
solved - my push is working
EDIT 2:
I'm trying to pop now. Would that mean I have to just aim my pointer at the next value? What do I do to the old top node? delete it since I new'd it?
It looks like a C question.
Functions push can be defined in C++ the following way
void push( node * &stack, const ItemType &item )
{
node *tmp = new node { item. stack };
stack = tmp;
}
in C it can look like
int push( struct node * *stack, const ItemType *item )
{
node *tmp = malloc( sizeof( struct node ) );
if ( tmp )
{
tmp->data = *item;
tmp->next = *stack;
*stack = tmp;
}
return tmp != NULL;
}
EDIT: After you edited your post I also edited my post.
It seems that pointer stack is a data member of class StackClass. In this case the member function can look like
void StackClass::Push( ItemType newItem )
// I would declare the parameter as const ItemType &newItem
{
node* temp = new node;
temp->data = newItem;
temp->next = stack;
stack = temp;
}
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node * next;
};
void Append(Node * head, int newdata){
Node * n = head;
if(n->next != NULL)
{
n = n->next;
}
n->data = newdata;
cout<<"data-> "<<newdata<<" inserted!"<<endl;
}
void Display(Node * head){
Node * n = head;
if(n->next != NULL)
{
cout<<"data->"<<n->data<<endl;
n = n->next;
}
cout<<"data->"<<n->data<<endl;
}
int main(int argc, char * argcv[])
{
Node * headnode;
int newdata = 20;
Append(headnode, newdata);
Display(headnode);
return 0;
}
The output of this program is:
data-> 20 inserted!
data->1
data->20
Why the headnode has been assigned a "1" data member here?
Besides the comments, the problem here is that you are sending a pointer to a Node in your append function without initializing the data and the pointer that it contains.
On the if(n->next != NULL) inside append, n->next will also be random data, meaning that you will assign the value 20 not to the "head" but to the node that the head points to.
That is why the value 20 is on the next node when printing, and random value of (in this case 1) is in your head node.
You need to use the new in order to allocate the Nodes in the memory, as dereferencing a pointer that isn't pointing to allocated memory will most likely cause segfaults.
Apart from the comments and answer by #Milan, I think the design of class Node can be better implemented. It's not always required to expose data members( i.e., Node::data ) and especially in this case. class Node can also have member functions that does appending a new link and display the linked list. To get an idea, think of the way the container std::list is implemented( i.e., its member functions ). Take the advantage of powerful feature, data hiding, in C++.
I'm trying to create an object in a function, but I am running into the problem that variable names have to be defined at runtime. Is there something I can do like with arrays that allows ne to dynamically create a variable in a function and preferably give it a different name from the one created when the function was called last?
***I'm working in C++
EDIT:
I can't give any code because I don't have any right now. All I have right now is pseudo code.
Basically, I'm trying to create a linked list, but the addNewItem() method that I want to use would require using the same method to create different objects.
EDIT:
Technically, we're not making a linklist, just more of a proof of concept to understand how they work.
EDIT: Here's the code:
#include "linklist.h"
#include <iostream>
using namespace std;
struct linklist
{
Student * obj;
linklist * next;
};
linklist * head;
int main()
{
}
void addStudent(char * newsdnt)
{
if(!head){
linklist * a = new linklist;
a->obj = new Student(newsdnt);
a->next = 0;
head = a;
return;
}else{
linklist * a = new linklist;
a->obj = new Student(newsdnt);
a->next = 0;
if(!head->next){
head->next = a; // Can only have one or two items in list
}
}
}
If you want a linked list - call new to create each new node and then add it to the list.
Smth like this:
void addStudent(char * newsdnt)
{
linklist* a = new linklist;
a.obj = new Student(newsdnt);
a.next = 0;
if( head == 0 ) {
head = a;
} else {
linklist* whereToAdd = head;
while( whereToAdd.next != 0 ) {
whereToAdd = whereToAdd.next;
}
whereToAdd.next = a;
}
}
The easiest way to build a (singly) linked list is to add the new item at the front:
linklist *head = 0;
...
a->next = head;
head = a;
...
If it is acceptable to add items at the tail in O(N) time, then you scan the list each time to find the end.
linklist head;
...
a->next = 0;
item = &head;
while (item->next != 0)
item = item->next;
item->next = a;
...
If you must add new items at the tail of the list in O(1) time, then keep a circular list, and a pointer to the tail of the list (so that tail->next is a pointer to the head of the list). (The previous list structures could be called 'open ended'.)
linklist root = { 0, &root };
linklist *tail = &root;
...
a->next = tail;
tail->next = a;
...
Beware: the termination conditions for iterating over the entire list (e.g. to find an item in the list) vary depending on the structure used (circular versus open-ended).
Caveat: untested code!
If you aren't sure what O(1) and O(N) means, then read up on 'Big O' notation.
I would suggest a vector:
#include <vector>
using namespace std;
void foo()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << v[0] + v[1] << endl;
}
Assuming that you need N objects of some type T:Arrays are very much present in C++. So is the STL which provides you with a host of oppertunities. You need to define how you will want to access and use these objects -- that influences the choice of your container. But can you post some code so that our answers are a little less vague (and more helpful to you)?
I'm not exactly sure what you want but is sounds like you could use Multiset.
Please provide more details, and I might be able to provide more help.
For starters I would suggest you rename your linkedlist struct to node and add a new linked list struct that holds the head, and (maybe) current / tail pointers. You should then implement methods in this class / struct that will allow you to manipulate it.
What you're missing at the moment is a method that will traverse the list (recursively getting the next pointer until you're at the end) and return a pointer to the last element. Once you have that, you can set the next pointer of that element to your newly created object.