So, here's the story. I'm trying to create a recursive descent parser that tokenizes a string and then creates a tree of nodes out of those tokens.
All of the pointers for my major classes are working... if you're worked with an RDP before then you know what I'm talking about with program -> statement -> assignStmt... etc. The idea being that the program node has a child that points to the statement node, etc.
Here's the problem. When I get to the end of the treenode I'm pointing to the actual tokens that the tokenizer created from the string.
So, let's say the string is:
firstvar = 1;
In this case there are 4 tokens [{id} firstvar], [{assignment} =], [{number} 1], [{scolon}]
And I want my assignStmt node to point to the non-decorator portions of that statement.. namely, child1 of assignStmt would be [{id} firstvar] and child2 would be [{number} 1]...
HOWEVER. When I assign child1 to [{id} firstvar], and then move onward to the next tokens, the value of child1 changes as I move forward. So, if I change my global token to the next token ( in this case [{assignment} =] ) then child1 of the assignStmt changes with it.
Why is this? What can I do?! Thank you!
TOKEN* getNextToken(void);
//only shown here to you know the return... it's working properly elsewhere
typedef struct node {
TOKEN *data;
struct node *child1, *child2, *child3, *child4, *parent;
} node;
TOKEN *token;
Symbol sym;
struct node *root;
void getsym()
{
token = getNextToken();
sym = token->sym;
}
int main()
{
getsym();
//So, right now, from getsym() the global token has the value {identifier; firstvar}
struct node* tempNode;
tempNode = (struct node*) calloc(1, sizeof(struct node));
tempNode->child1 = tempNode->child2 = tempNode->child3 = tempNode->child4 = NULL;
tempNode->data = token;
getsym();
//BUT NOW from getsym() the global token has the value {assignment; =}, and
//subsequently the tempNode->data has changed from what it should be
//{identifier; firstvar} to what the global token's new value is: {assignment; =}
}
Since i can't comment on this due to my low reputation i will add this answer and if have understood your problem you are probably passing a pointer to a function, and the problem is that you probably need a pointer to pointer instead of just a pointer.
in C when you pass values to a function you are passing them by value, not by reference, meaning that the function makes a local copy of that argument and it will work only with that local copy, the problem is that all the changes will affect only the local copy and when the function terminates all the changes will be lost if you will not handle this correctly.
You are returning a pointer to a global variable, and that pointer will always be the same even if you modify the global variable.
The solution is to either allocate a new object each time, or to not use pointers at all and return the structure directly and let the compiler handle copying of the structures internal values.
Related
I am learning data structure, and here is a thing that I am unable to understand...
int end(struct node** p, int data){
/*
This is another layer of indirection.
Why is the second construct necessary?
Well, if I want to modify something allocated outside of my function scope,
I need a pointer to its memory location.
*/
struct node* new = (struct node*)malloc(sizeof(struct node));
struct node* last = *p;
new->data = data;
new->next = NULL;
while(last->next !=NULL){
last = last ->next ;
}
last->next = new;
}
why we are using struct node **p?
can we use struct node *p in place of struct node **p?
the comment which I wrote here is the answer I found here, but still, I am unclear about this here is the full code...
please help me
thank you
Short answer: There is no need for a double-pointer in the posted code.
The normal reason for passing a double-pointer is that you want to be able to change the value of a variable in the callers scope.
Example:
struct node* head = NULL;
end(&head, 42);
// Here the value of head is not NULL any more
// It's value was change by the function end
// Now it points to the first (and only) element of the list
and your function should include a line like:
if (*p == NULL) {*p = new; return 0;}
However, your code doesn't !! Maybe that's really a bug in your code?
Since your code doesn't update *p there is no reason for passing a double-pointer.
BTW: Your function says it will return int but the code has no return statement. That's a bug for sure.
The shown function (according to its name) should create a new node and apend it at the end of the list represented by the pointer to a pointer to a node of that list. (I doubt however, that it actually does, agreeing with comments...)
Since the list might be empty and that pointer to node hence not be pointing to an existing node, it is ncessary to be able to potentially change the pointer to the first elemet of that list away from NULL to then point to the newly created node.
That is only possible if the parameter is not only a copy of the pointer to the first node but instead is a pointer to the pointer to the first node. Because in the second case you can dereference the pointer to pointer and actually modify the pointer to node.
Otherwise the list (if NULL) would always still point to NULL after the function call.
I'm setting up a struct called Node
typedef struct node{
struct node *left;
struct node *right;
struct node *parent;
}node;
and a function that operate on the nodes:
int test(node *old,node* new){
old->parent->right = new;
new->parent = old->parent;
}
Ok, so i make 3 nodes and set up the relationship between them
node* me =malloc(sizeof(node));
node* me1 = malloc(sizeof(node));
node* me2 = malloc(sizeof(node));
me->right = me1;
me->left = me2;
me1->parent = me;
me2->parent = me;
test(me1,me);
1.However, after test(), me1->parent->right changed while me1 didn't, which is weird because me1 and me1->parent->right point are the same address. I wonder if i make any wrong assumption here?
2.In function test(), if i replace old->parent->right with old only, then after the function call, the node me1 remains the same. Isn't the pointer modified after we do operations on it inside a function,and why in this case it is not?
me, me1, and me2 are local variables inside your outer function (let's assume it was main). These pointers are never modified, so after the call to test, me1 still points to the same node as before, while the pointer me1->parent->right now points to me. So, "me1 and me1->parent->right point are the same address" isn't true anymore!
If you only modify old inside test, you will only modify the parameter old, which is a copy of me1. After test returns, this copy is forgotten, and the modification has no effect. If you want to modify the me1 variable from within test, you will have to pass a pointer to the pointer, i.e. a double pointer:
int test(node **old,node* new){
*old = new;
...
}
and call it as test(&me1,me);.
Also: Please don't name things "new", because if you ever decide to compile the code as C++, this will conflict with the reserved keyword new.
Here is what your test() method does:
int test(node *old,node* new){
old->parent->right = new;
new->parent = old->parent;
}
when you call this:
me->right = me1;
me1->parent = me;
test(me1,me);
These steps happens:
me1's parent is me and me's right is me1. So me's right becomes me again.
me's parent becomes me itself.
Lets say I have the following code,
typedef struct WordNode WordNode;
struct WordNode {
int freq; // The frequency of the the word.
char *word; // The word itself.
WordNode *next; // The next word node in the list.
};
struct WordSet {
int size; // The number of elements in the set.
WordNode *head; // The starting node in the set.
};
After this, I've got some functions that initialize these structs. To prevent too much code in this post, I'm going to avoid posting those functions here.
Now, lets say I have the following,
WordNode **p = wset->head; // can't change this line
Here, p is basically a pointer pointing to a pointer, correct?
And then, if I do this:
(*p) == NULL
This would return true if p is pointing to NULL, right?
Now, how would I get the word stored in wset->head?
Can I do this?
(*(*p))->word
And if I want p to point to the next WordNode, can I do this?
p = (*(*p))->next
I just want to know if all this is valid syntax so that I know I'm using pointers correctly.
Not really. (*(*p))->word is a total dereferenciation. So it would either be (*(*p)).word or (*p)->word.
You can imagine it that way, that the ->-Operator takes away one reference for you.
obj->field is the same as (*obj).field
Just for the sake of simplicity, whenever I have to deal with double pointer and I need the value I all the time go via an intermediate variable
e.g.
WordNode **ptr2ptr = wset->head;
WordNode *ptr = *ptr2Ptr;
WordNode value = *ptr;
or to get the head:
WordNode head = ptr->head;
Now I'm just answering the question which is, how to access the value of a pointer to pointer. You must be careful that your wset->head contains actually a pointer to pointer which is normally not the case in a linked list the way I understand you are trying to do. This is also not the way you have defined your head member...
Hi I am making a Queue abstact data type and I ran into a problem which I will try to explain as clearly as possible.
Basically I have a two structs one for an element and one for a queue (so you can initialize multiple queues).
struct element
{
TYPE value;
struct element* next;
};
struct queue
{
struct element* head;
struct element* tail;
int element_counter;
};
And I have a function which initializes my queue struct.
int make_new_queue(struct queue* name)
{
name = malloc(sizeof(struct queue));
name->head = NULL;
name->tail = NULL;
name->element_counter = 0;
}
The problem I ran into is foolproofing this code. For example I initialised my first queue in my main function.
struct queue* first = make_new_queue(first);
But if somebody tries to do the same thing again somewhere in the middle of the code write:
first = make_new_queue(first);
it overrides it and makes the head and tail pointers NULL. The thing I can't figure out is how to make my make_new_queue function better and check if there is something in the queue that I provide it, but still let me initialise empty queues.
Sorry for my english. I hope you get the idea of what I want to do. Thanks.
Initialize it to NULL and pass a pointer to pointer:
void make_new_queue(struct queue **name)
{
if (*name != NULL) return; /* Yet initialized ? */
*name = malloc(sizeof(struct queue));
if (*name == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
*name->head = NULL;
*name->tail = NULL;
*name->element_counter = 0;
}
struct queue *first = NULL;
make_new_queue(&first);
You can simply check if you variable name is NULL.
If your variable is non-null, you can alloc and initialize your queue else just do what you want to do.
There is really no good way to enforce what you want without discipline from the user. In my opinion, the best approach is to stick to known patterns.
You can use Alter Mann's approach to pass a pointer to a pointer to update the struct. The drawback is that is that you have to separate variable declaration and initialisation. It also relies on the user to initialise the pointer to the struct to NULL. If you forget it, the queue pointer will not be initialised and you don't even know, because you can't check against NULL.
struct stuff *stuff = NULL;
stuff_initialise(&stuff);
You can use your original approach to pass in the struct and return the same struct when it was initialised or a new one. It has the same problems as the first approach plus the possibility that you forget to assign the return value. You can, however, combine allocation and initialisation:
struct stuff *stuff = stuff_new(NULL);
The simplest way is not to pass the old pointer and rely on the user not to change the pointer after allocation. After all, the functions of the standard library suffer from the same problem:
char *buf = malloc(BUFSIZE);
buf = malloc(2 * BUFSIZE); // Memory leak
buf++; // Allowed, but a bad idea
free(buf); // Ouch!
FILE *f = fopen("palomino.txt", "r");
f = stdin; // Switch horses midstream?
You should design your API so that you have matching pairs of functions that define the scope of your struct:
struct stuff *stuff = stuff_create(...);
// use stuff ...
stuff_destroy(stuff);
Good naming should make clear that stuff acts as a handle and should not be changed and that after closing or destroying the handle, it is invalid. You should see these calls as first and last statements in functions. (This method is similar to the malloc/free or fopen/fclose pairngs of the standard library.)
Finally, if you as the user of a handle want to avoid accidential changes, you can define the pointer (not what it points to) as const:
struct stuff *const handle = stuff_create("X");
handle = stuff_create("Y"); // Compiler error
But I rarely see this. C programmers usually just use an unadorned pointer and remember to keep their fingers off the hotplate.
So, here's the story. I'm trying to create a recursive descent parser that tokenizes a string and then creates a tree of nodes out of those tokens.
All of the pointers for my major classes are working... if you're worked with an RDP before then you know what I'm talking about with program -> statement -> assignStmt... etc. The idea being that the program node has a child that points to the statement node, etc.
Here's the problem. When I get to the end of the treenode I'm pointing to the actual tokens that the tokenizer created from the string.
So, let's say the string is:
firstvar = 1;
In this case there are 4 tokens [{id} firstvar], [{assignment} =], [{number} 1], [{scolon}]
And I want my assignStmt node to point to the non-decorator portions of that statement.. namely, child1 of assignStmt would be [{id} firstvar] and child2 would be [{number} 1]...
HOWEVER. When I assign child1 to [{id} firstvar], and then move onward to the next tokens, the value of child1 changes as I move forward. So, if I change my global token to the next token ( in this case [{assignment} =] ) then child1 of the assignStmt changes with it.
Why is this? What can I do?! Thank you!
TOKEN* getNextToken(void);
//only shown here to you know the return... it's working properly elsewhere
typedef struct node {
TOKEN *data;
struct node *child1, *child2, *child3, *child4, *parent;
} node;
TOKEN *token;
Symbol sym;
struct node *root;
void getsym()
{
token = getNextToken();
sym = token->sym;
}
int main()
{
getsym();
//So, right now, from getsym() the global token has the value {identifier; firstvar}
struct node* tempNode;
tempNode = (struct node*) calloc(1, sizeof(struct node));
tempNode->child1 = tempNode->child2 = tempNode->child3 = tempNode->child4 = NULL;
tempNode->data = token;
getsym();
//BUT NOW from getsym() the global token has the value {assignment; =}, and
//subsequently the tempNode->data has changed from what it should be
//{identifier; firstvar} to what the global token's new value is: {assignment; =}
}
Since i can't comment on this due to my low reputation i will add this answer and if have understood your problem you are probably passing a pointer to a function, and the problem is that you probably need a pointer to pointer instead of just a pointer.
in C when you pass values to a function you are passing them by value, not by reference, meaning that the function makes a local copy of that argument and it will work only with that local copy, the problem is that all the changes will affect only the local copy and when the function terminates all the changes will be lost if you will not handle this correctly.
You are returning a pointer to a global variable, and that pointer will always be the same even if you modify the global variable.
The solution is to either allocate a new object each time, or to not use pointers at all and return the structure directly and let the compiler handle copying of the structures internal values.