So I'm trying to add a card to a player's hand... and the value of the card will only be passed back to the main function if I use a double pointer for the top and last cards. But last->pt can't translate to temp, how do I fix this?
typedef struct card_s
{
char suit[9];
int value;
struct card_s *pt;
} card;
void deal_card(card **top, card **last, card dealt)
{
card *temp;
temp = (card*)malloc(sizeof(card));
strcpy(temp->suit, dealt.suit);
temp->value = dealt.value;
if(*top == NULL)
*top = temp;
else
*last->pt = temp; //FIX ME - something is going wrong at this point
*last = temp;
last->pt = NULL; //FIX ME - same problem as above
}
The problem seems to be operator precedence, so using parentheses should resolve it:
(*last)->pt = temp;
The way it was written originally, it was treating last as a (single) pointer, and trying to dereference member pt. Instead, you want to dereference last, and then access member pt of the resulting pointer.
Since pointers to structures are common, and the parentheses in the example above are a nuisance, there's another structure selection operator which works on pointers to structures. If p is a pointer to a structure and m is a member of that structure, then
p->m
selects that member of the pointed-to structure. The expression p->m is therefore exactly equivalent to
(*p).m
You on the other hand are using some vague combination. Use either format.
E.g. last->pt or (*last).pt
Also these lines contain asterisks that don't belong there I believe:
if(*top == NULL)
*top = temp;
else
*last->pt = temp; //FIX ME - something is going wrong at this point
*last = temp;
All together, this should work:
if(top == NULL)
top = temp;
else
last->pt = temp;
last = temp;
(Assuming you want to change the address the pointer is pointing to. If you use a asterisk in front of it you are comparing/assigning with the actual value the pointer is pointing to.
Related
I'm trying to create a linked list without using structures in C.
I want to be able to store an int variable on every node and a pointer to the next node, add unlimited numbers to the list, remove the first item, print all of the elements, etc.
I was thinking that every node of type int** should have 2 pointers of type int*.
the first one will point to an int address and the second will point to NULL.
Then, if I like to add a number to the list, I'll use the last pointer to point to a new allocated node of type int** and so on.
I'm having trouble writing the proper code for this though, and can't seem to reach to the actual int values. See the image below:
You can achieve this by allocating two uintptr_t each time: the first allocated memory space will be responsible for storing the value of the integer and the second one will be pointing to the next memory location.
uintptr_t nodeFirst = malloc(2 * sizeof(uintptr_t));
...
...
uintptr_t nodeNext = malloc(2 * sizeof(uintptr_t));
....
....
*nodeFirst = someIntValue;
*(nodeFirst + 1) = nodeNext;
...
The fact is, my solution above is still using the struct analogy, but w/o the struct keyword.
Here is a complete solution of a LinkedList managed as int ** pointers.
Step 1 - the addNode() function to add one node to the int **head.
int **addNode(int **head, int ival)
{
int **node = malloc(2 * sizeof(int *));
// don't forget to alloc memory to store the int value
node[0] = malloc(sizeof(int));
*(node[0]) = ival;
// next is pointing to NULL
node[1] = NULL;
if (head == NULL) {
// first node to be added
head = node;
}
else {
int **temp;
temp = head;
// temp[1] is the next
while (temp[1]!=NULL) {
// cast needed to go to the next node
temp = (int **)temp[1];
}
// cast needed to store the next node
temp[1] = (int *)node;
}
return (head);
}
Step 2 - a function display() to explore the current linkedlist.
void display(int **head)
{
int **temp;
int i = 0;
temp = head;
printf("display:\n");
while (temp!=NULL) {
// temp[0] is pointing to the ivalue
printf("node[%d]=%d\n",i++,*(temp[0]));
temp = (int **)temp[1];
}
printf("\n");
}
Step 3 - the popNode() function to remove the first node.
int **popNode(int **head)
{
int **temp;
if (head!=NULL) {
temp = (int **)head[1];
// don't forget to free ivalue
free(head[0]);
// then free the next pointer
free(head[1]);
head = temp;
}
return (head);
}
Step 4 - then an example of main() function using the linkedlist.
int main()
{
int **head = NULL;
head = addNode(head,111);
head = addNode(head,222);
head = addNode(head,333);
display(head);
// display:
// node[0]=111
// node[1]=222
// node[2]=333
head = popNode(head);
display(head);
// display:
// node[0]=222
// node[1]=333
while ((head = popNode(head))!=NULL);
display(head);
// display:
return (0);
}
Allocate two arrays, both of which are stored as pointers. In C, they can be the pointers you get back from calloc(). The first holds your node data. We can call it nodes. The second is an array of pointers (or integral offsets). We can call it nexts. Whenever you update the list, update nodes so that each nexts[i] links to the next node after the one that contains nodes[i], or an invalid value such as NULL or -1 if it is the tail. For a double-linked list, you’d need befores or to use the XOR trick. You’ll need a head pointer and some kind of indicator of which elements in your pool are unallocated, which could be something simple like a first free index, or something more complicated like a bitfield.
You would still need to wrap all this in a structure to get more than one linked list in your program, but that does give you one linked list using no data structure other than pointers.
This challenge is crazy, but a structure of arrays isn’t, and you might see a graph or a list of vertices stored in a somewhat similar way. You can allocate or deallocate your node pool all at once instead of in small chunks, it could be more efficient to use 32-bit offsets instead of 64-bit next pointers, and contiguous storage gets you locality of reference.
This might seem like a silly question to some of you and I know that I get things mixed up quite often but I need to understand the code so I can stop obsessing about it and focus on the real matter of why I need to use it.
So, in the code I see several assignments like this:
struct bst_node** node = root;
node = &(*node)->left;
node = &(*node)->right;
is there an invisible parenthesis here?
node = &((*node)->right);
This example is taken from literateprograms.org.
So to me it seems &(*node) is unnecessary and I might as well just write node->left instead, but the code seems to work where I can't make sense of it and I'm wondering if it's because I'm misunderstanding what's happening at those lines. Particularly, at one place in the code where it is deleting a node by constantly moving the "deleted" data to the bottom of the tree to safely remove the node without having to "break things", I'm lost because I don't get how
old_node = *node;
if ((*node)->left == NULL) {
*node = (*node)->right;
free_node(old_node);
else if ((*node)->right == NULL) {
*node = (*node)->left;
free_node(old_node);
} else {
struct bst_node **pred = &(*node)->left;
while ((*pred)->right != NULL) {
pred = &(*pred)->right;
}
psudo-code: swap values of *pred and *node when the
bottom-right of the left tree of old_node has been found.
recursive call with pred;
}
can keep the tree structure intact. I don't understand how this makes sure the structure is intact and would appreciate some help from somebody who knows what's going on. I interpret node being a local variable on the stack, created at the function call. Since it is a double pointer it points to a location in the stack (I assume this, since they did &(*node) previously to the function call), of either it's own stack or the function before, which then points to said node on the heap.
In the example code above what I think it is supposed to do is switch either left or right, since one of them is NULL, and then switch the one that isn't (assuming the other one isn't NULL?) As I said, I'm not sure about how this would work. My question mostly relates to the fact that I think &(*node) <=> node but I want to know if that's not the case etc.
node = &(*node)->right;
is there an invisible parenthesis here?
node = &((*node)->right);
Yes. It is taking the address of the right member of *node. The -> takes precedence over &; see C++ Operator Precedence (-> is 2 and & is 3 in that list) (it's the same general precedence as C).
So to me it seems &(*node) is unnecessary and I might as well just write node->left instead,
Your premise is off. There is no expression &(*node), as explained above, the & applies to the entire (*node)->left, not (*node).
In that code the double pointers are just that, a pointer to a pointer. Just as this works:
int x = 0;
int *xptr = &x;
*xptr = 5;
assert(x == 5);
This is the same, it changes the value of the pointer x:
int someint;
int *x = &someint;
int **xptr = &x;
*xptr = NULL;
assert(x == NULL);
In that code snippet you posted, assigning a pointer to *node changes the value of the pointer that node points to. So, e.g. (pseudo-ish code):
typedef struct bst_node_ {
struct bst_node_ *left;
struct bst_node_ *right;
} bst_node;
bst_node * construct_node () {
return a pointer to a new bst_node;
}
void create_node (bst_node ** destination_ptr) {
*destination_ptr = construct_node();
}
void somewhere () {
bst_node *n = construct_node();
create_node(&n->left); // after this, n->left points to a new node
create_node(&n->right); // after this, n->right points to a new node
}
Noting again that &n->left is the same as &(n->left) because of precedence rules. I hope that helps.
In C++ you can pass arguments to a function by reference, which is essentially the same as passing a pointer except syntactically it leads to code that is a bit easier to read.
That is useful
&(*node)->left <=>&((*node)->left)
The variable edited by this code is *node. I need the context fo this code to give more info
so i wrote a program to read words from a file and insert, remove or search them in a binary search tree. It seemed like everything was working fine but somehow when inserting a word in a binary search tree, from the second word onwards the root pointer I pass as the parameter of the insert function is shifted to point at the word being inserted. So instead of inserting the word the function only increases the occurence of the first word. I sincerely don't know how this is happening. Does anyone know what could be the problem?
my structs:
typedef char * TypeKey;
typedef struct TypeItem {
TypeKey Key; //[MAXTAM];
int counting;
} TypeItem;
typedef struct Node * Pointer
typedef struct Node {
TypeItem Reg;
Pointer Left, Right;
} node;
typedef Pointer TypeTree;
The insert function:
void Insert (TypeItem * x, Pointer * p){
if (*p == NULL){
*p= (Pointer)malloc(sizeof(Node));
(*p)->Reg = *x;
(*p)->Left = NULL;
(*p)->Right = NULL;
printf("insert %s\n",x->Key);
return;
}
if (strcmp(x->Key,(*p)->Reg.Key)< 0){
Insert(x, &(*p)->Left);
}
if (strcmp(x->Key,(*p)->Reg.Key) > 0)
Insert(x, &(*p)->Right);
else {
(*p)->Reg.counting ++;
printf("increases %s\n",x->Key);
return;
}
}
And i just declare the root pointer "arvore" on main like this:
Pointer arvore = NULL;
TypeItem item;
item.Key = Palavra;
item.counting = 1;
Insert(&item, arvore);
If anyone could help me understand what is the wrong it would be really nice.
You have undefined behavior in your code
First you declare arvore of type Apontador, and then assign NULL to that pointer. Then you call Insere with arvore as argument, but Insere want a pointer to an Apontador, meaning you have one level of indirection to little in the call. This shouldn't even compile, or at least give a warning (warnings are a very good sign that you're doing something you shouldn't be doing).
And when inside the Insere function, you dereference the pointer p (which is arvore in the call) which is NULL, leading to undefined behavior.
You should call the function using the address-of operator & for the second argument as well:
Insere(&item, &arvore);
Also, if Palavra is a pointer to e.g. an array defined locally in a function, that pointer will no longer be valid once that function returns. If it's so then you have another case of undefined behavior.
[Too long for a comment]
I did not dive to the ground but this line
(*p)->Reg = *x;
copies a TypeItem and with it copies one of its members, namely TypeKey Key with Key being a pointer char *. I strongly assume here a deep copy is needed, you need to duplicate what the pointer Key points to.
It is not fully clear as we do not see who you fully initialies your node.
I'm quite newbie in C and now I'm trying to implement basic generic linked list with 3 elements, each element will contain a different datatype value — int, char and double.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
struct node
{
void* data;
struct node* next;
};
struct node* BuildOneTwoThree()
{
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = (struct node*)malloc(sizeof(struct node));
second = (struct node*)malloc(sizeof(struct node));
third = (struct node*)malloc(sizeof(struct node));
head->data = (int*)malloc(sizeof(int));
(int*)(head->data) = 2;
head->next = second;
second->data = (char*)malloc(sizeof(char));
(char*)second->data = 'b';
second->next = third;
third->data = (double*)malloc(sizeof(double));
(double*)third->data = 5.6;
third->next = NULL;
return head;
}
int main(void)
{
struct node* lst = BuildOneTwoThree();
printf("%d\n", lst->data);
printf("%c\n", lst->next->data);
printf("%.2f\n", lst->next->next->data);
return 0;
}
I have no problem with the first two elements, but when I try to assign a value of type double to the third element I get an error:
can not convert from double to double *
My questions:
What is the reason for this error?
Why don't I get the same error in case of int or char?
How to assign a double value to the data field of the third element?
The problem string is (double*)third->data = 5.6;.
In your "working" examples, you're calling malloc to get a pointer to some newly-allocated space, and then immediately throwing that pointer away and replacing the pointer value with your integer or character value. That works more or less by accident because in most C implementations a pointer cell can hold an integer or char value, though you should be getting warnings. If you actually tried to dereference the data pointer after those assignments, you would probably get a crash and core dump.
You want to put the values at the place pointed to by the pointer, not in the pointer itself. Which means you need an extra *:
*((double *)third->data) = 5.6;
The * in the (double *) typecast is part of the type name - "pointer to double". The cast says "take the value of third->data and interpret it as a pointer to double". The result is still a pointer, so when you assign to that, you are changing where the pointer points (and probably making it point somewhere meaningless). Instead, you want to assign a value to the place it already points, which is what the outer * does.
However, if you're only storing basic types like int, char, and double, you don't need to go through a pointer (and worry about the attendant memory management). You can just use a union:
struct node
{
struct node *next;
union {
char c;
int i;
double d;
} data;
}
Then you would do e.g.
head->data.i = 2;
second->data.c = 'b';
third->data.d = 5.6;
You are casting the pointer, but you need to derefernce it for the assignment, the assignment worked for the first two since the int and char were casted to pointers, it should be:
*((int*)(head->data)) = 2;
*((char*)(second->data)) = 'b';
*((double*)(third->data)) = 5.6;
Anyway, there should be warning for such a cast in first place.
You can't assign the value to the pointer, you have to assign it to the object pointed (in the last case, a double - you only have space for one double).
So:
...
head->data = (int*)malloc(sizeof(int));
((int*)(head->data))[0] = 2;
head->next = second;
second->data = (char*)malloc(sizeof(char));
((char*)second->data)[0] = 'b';
second->next = third;
third->data = (double*)malloc(2 * sizeof(double));
((double*)third->data)[0] = 5.6;
((double*)third->data)[1] = 3.1415;
// We only allocated space for 2 doubles, so this line here would cause a crash
// (or anyway, a data corruption)
// ((double*)third->data)[2] = 666;
third->next = NULL;
return head;
}
int main(void)
{
struct node* lst = BuildOneTwoThree();
printf("%d\n", ((int *)lst->data)[0]);
printf("%c\n", ((char *)lst->next->data)[0]);
printf("%.2f\n", ((double *)lst->next->next->data)[0]);
printf("%.2f\n", ((double *)lst->next->next->data)[1]);
...
returns:
2
b
5.60
3.14
BTW: with full warnings enabled, the compiler should have warned you that the first two assignments were risky (GCC considers them errors) and the third one unallowed (can't convert from a double to a pointer)
One more thing: when you use a struct payload this way, you have to consider that the data type that you actually stored in the payload itself is lost. So you can't, by inspecting an instance of your linked list, determine whether it is a char, an integer or a double. Worse, even checking the value might not be allowed and crash the program (suppose you stored a single byte, but try to read four or eight).
So you ought to also store an extra field in your structure holding an indicator (an enum maybe) of the original data type:
typedef enum
{
TYPE_IS_CHAR,
TYPE_IS_INT,
TYPE_IS_FLOAT,
TYPE_IS_DOUBLE,
...
} mytype_t;
struct node
{
mytype_t type;
void *data;
struct node *next;
}
I need to sum a variable inside of my linked list. I've got the following function but I'm getting errors on the line noted. I also think that I may not have finished the if statement correctly to return the summed value to the function.
int print_nodeprice1 (node *headptr, int num) {
int sum = 0;
node *first;
first = *headptr; // getting errors that I can't assign this
while (first != NULL) {
first = first -> next_ptr;
if (num == first -> price1)
return sum;
else {
printf("\n");
}
}
}
first = headptr;
this will work..since both are of type (node *)
You have a couple issues:
Assign first = headptr, instead of *headptr
Do your num check at the top of the loop, before setting first =
first->next
You aren't actually summing anything. Did you mean to increment your
sum variable?
first = *headptr; // getting errors that I can't assign this
Correct - you're trying to assign the value (dereference) to a pointer.
first = headptr;
Beyond that ... It's unclear what you mean about "sum a variable inside of my linked list". Your code returns 0 when it finds a price1 that equals the num you pass in.
int print_nodeprice1 (node *headptr, int num) {
node *first;
first = *headptr; // getting errors that I can't assign this
first is a pointer to node, headptr is also a pointer to node. Now you try to assign to first the result of derreferencing headptr.
You don't need the *. It should be just:
first = headptr;
first and headptr are of type node*. The * operator dereferences them so *headptr is of type node, not node*.
first is a pointer to node. headptr is a pointer to node. *headptr is a node. You cannot assign a node to a pointer to node.