I get this weird side effect while using operator '->' in code I wrote in C. The pointer which I used -> on , is changed to have some garbage.
More specifically:
I have the following structs:
typedef void* ListElement ;
typedef struct List_t* List ;
typedef struct Node_t* Node;
Struct Node_t {
ListElement data ;
Node next;
}
Struct List_t {
Node* head;
Node* current
}
when I use the following ListGetFirst(), I get wired behavior :
ListElement ListGetFirst(List list)
{
if( list == NULL || list->head==NULL)
{
return NULL;
}
list->current=list->head;
Node* head =list->head; // here is the problem
ListElement data = (*head)->data;
return data;
}
when I used debugger I figured out that the pointer list->head is changed on the marked aformentioned line .
I realy have no idea why, and I didn't knew that '->' can have side effect
thanks in advance
Are you sure this is exactly what you want to do?
typedef struct Node_t* Node;
Node* head =list->head;
Since you defined Node as a pointer to Node_t, shouldn't you be doing:
Node head =list->head;
EDIT:
To summarize the whole thing, I think this typedef is misleading you:
typedef struct Node_t* Node;
It would made more sense if it were simply:
typedef struct Node_t Node;
Gah, pointers hidden behind typedefs; unless the type's meant to be totally opaque, that's almost always bad juju. For my benefit, I'm going to take out the typedefs so I have an easier time seeing what you're really playing with.
struct Node_t {
void *data ;
struct Node_t *next;
};
struct List_t {
struct Node_t **head;
struct Node_t **current;
};
void *ListGetFirst(struct List_t *list)
{
if( list == NULL || list->head==NULL
{
return NULL;
}
list->current=list->head;
struct Node_t **head =list->head; // here is the problem
void *data = (*head)->data;
return data;
}
I got nuthin'. Types all appear to match up. The -> operator most emphatically does not have any side effects; all it does is dereference a pointer. The extra level of indirection for head and current in struct List_t is a head-scratcher, and it makes me wonder if they're being allocated or assigned correctly. All I can figure is that list->head isn't pointing to memory that you actually own, and is getting overwritten somehow when you reach that point (IOW, you've invoked undefined behavior somewhere else in your code).
In short, the problem isn't in the code that you've posted. It's probably where you allocate and assign list elements.
You are using pointers to pointers, where most likely you want pointers.
In List_t you define head as Node*, where Node is already a Node_t* .
hth
Mario
Related
I am following an online tutorial which presents me with the following (simplified) code:
typedef struct {
int data;
Node* next;
} Node;
int main(){
Node *head;
init(&head);
return 0;
}
What is the purpose & functionality of the init function? I did not define it myself, however am struggling to find documentation online as well.
For starters this declaration
typedef struct {
int data;
Node* next;
} Node;
is incorrect. The name Node used in this data member declaration
Node* next;
is undefined.
You need to write
typedef struct Node {
int data;
struct Node* next;
} Node;
As for your question then in this declaration
Node *head;
the pointer head has an indeterminate value because it is not initialized.
So it seems the function init just initializes the pointer. You need to pass the pointer by reference through a pointer to it. Otherwise the function will deal with a copy of the pointer head. Dereferencing the pointer to pointer you will get a direct access to the original pointer head that can be changed within the function. That is the function can look the following way
void init( Node **head )
{
*head = NULL;
}
Pay attention to that you could just write in main
Node *head = NULL;
without a need to call the function init.
I think that the init function is gonna be implemented in the next videos. I suppose that your teacher wants to use an init function to set some values if you create a new Node (or a struct in this case) to prevent some easter eggs undefined behaviour.
I get a lot of "assignment from incompatible pointer type" warnings, and I don't know why.
The warnings appear in this part:
void addNode(linkedList* list, int board)
{
Node* newNode = createNode(board);
(list->last)->next = newNode; // this line has warning
newNode->prev = list->last; // this line has warning
}
The structs and the rest of the code is:
typedef struct{
int board;
struct Node* next;
struct Node* prev;
}Node;
typedef struct{
int length;
Node* first;
Node* last;
}linkedList;
Node* createNode(int board)
{
Node* node = (Node*)malloc(sizeof(Node));
node->next = NULL;
node->prev = NULL;
node->board = board;
return node;
}
linkedList* createList()
{
linkedList* list = (linkedList*)malloc(sizeof(linkedList));
list->first = NULL;
list->last = NULL;
list->length = 0;
return list;
}
This ...
typedef struct{
int board;
struct Node* next;
struct Node* prev;
}Node;
... declares a tagless structure type, and defines Node as an alias for that type. It does not define the type struct Node to which its members next and prev point. That doesn't prevent pointers to such a type being declared, but that type is not the same as Node, and not compatible with it.
The easiest solution, supposing that there isn't any definition of struct Node elsewhere, is to just add that tag:
typedef struct Node {
int board;
struct Node* next;
struct Node* prev;
}Node;
That gives you what you surely meant.
Note, too, that you don't inherently need a typedef at all. Having added the tag, you can refer to that type everywhere as struct Node. The typedef'd alias is a convenience only, and one that I think is way overused. All too often, typedefs obfuscate more than they help.
You never actually define struct Node.
The type which you alias (typedef) as Node is an untagged struct. When you later declare a pointer struct Node*, the compiler allows it as a pointer to an incomplete type (which is implicitly declared), but that's not the same as any type declared in your program.
A good way to declare a struct with self-referring pointers is:
typedef struct Node Node;
struct Node {
int board;
Node* next;
Node* prev;
};
In that formulation, the first line defines Node as an alias for the still incomplete type struct Node, which is then defined by the second declaration. struct Node is still incomplete when the Node* member declarations are encountered, but pointers to incomplete types are allowed.
One reason I'm fond of that style is that it works well with the common case in which the struct is an opaque datatype whose members are not intended for public use. In that case, the typedef can be placed in the header file, allowing pointers to the opaque type to be used in function prototypes or as local variables. The struct definition itself then goes into the implementation.
I am new to pointers and there is this code for merge sort of linked lists. And here it has declared a dummy node as struct node dummy; and the next node for dummy node is NULL so to set it we use dummy.next = NULL;.
/* Link list node */
struct node
{
int data;
struct node* next;
};
struct node* SortedMerge(struct node* a, struct node* b)
{
/* a dummy first node to hang the result on */
struct node dummy;
/* tail points to the last result node */
struct node* tail = &dummy;
/* so tail->next is the place to add new nodes
to the result. */
dummy.next = NULL;
//Code continues...
}
I understand that i can use it if it was struct node *dummy;
but we cant use it here as it is not a pointer node.
So my question is why doesn't dummy->next = NULL work here?
and what is the difference between struct node and struct node* ??
a -> b is shorthand for (*a).b.
If a is not a pointer, *a is not valid, and neither is a -> b.
dummy is not a pointer to a structure. It is the structure variable itself.
You can derefer attributes of a structure with the operator -> only if it is a pointer to the structure.
If you are using the struct variable, then . is the way to go about, which is very much the case with dummy.
I understand that i can use it if it was struct node *dummy;
If by "it" you mean struct node dummy; then the answer is no. You cannot use a pointer to node in the same way as a pointer to node.
So my question is why doesn't dummy->next = NULL work here?
Because dummy is a node, not a pointer, and operator -> if for pointers. The expression dummy->next has the same semantics as (*dummy).next.
. So my question is why doesn't dummy->next = NULL work here? and what is the difference between struct node and struct node* ?
Declared as this struct node dummy;
dummy->next=NULL doesn't work because dummy is not a pointer to struct .
If you write so -
struct node A; // then A is a struct variable which can access struct members using '.' operator
and this -
struct node* B; // then B is a pointer to struct node which can access struct member using '->` or like this (*B).data=something.
SO, I'm trying to write a generic singly linked list implementation that works with all types, and keep coming across the error of: Assignment from incompatible pointer type for the line of code that is as follows:
node->next = newNode;
This is in the context of the following declarations and structs:
typedef struct{
void* data; // The generic pointer to the data in the node.
Node* next; // A pointer to the next Node in the list.
} Node;
void insertAfter(Node* node, Node* newNode){
// We first want to reassign the target of node to newNode
newNode->next = node->next;
// Then assign the target of node to point to newNode
node->next = newNode;
}
I have tried to use both this: node->next = *newNode; and this: node->next = &newNode; But as you can imagine, they do not work, what am I doing wrong here, what and why is this error being caused and how do I fix it?
Change the definition of your struct from
typedef struct{
void* data; // The generic pointer to the data in the node.
Node* next; // A pointer to the next Node in the list.
} Node;
to
typedef struct Node Node;
struct Node {
void* data; // The generic pointer to the data in the node.
Node* next; // A pointer to the next Node in the list.
};
Reason being that you can not reference the typedef inside your struct until the typedef is complete.
Not sure why you thought the other line was the issue. It was not.
struct node {
int data;
struct node *next,*prev;
};
void insert(struct node *head,int data){
if(head == NULL){
head = (node *)malloc(sizeof(node));
--- code continues-----
I just want to know the difference between
head = (node *)malloc(sizeof(node)); and struct node *head = malloc(sizeof(struct node));
And if I pass **head as a parameter of the insert function what does it do ?
The difference between:
head = (node *)malloc(sizeof(node));
struct node *head = malloc(sizeof(struct node));
is that a C compiler will reject the first and allow the second, but a C++ compiler will accept the first and reject the second.
In C, the code shown does not create a type name node when you define or declare struct node. You would need to add typedef struct node node; in the C source. C++ automatically creates the type name node from the definition of struct node. (A C++ compiler rejects the second because of the implicit cast from void * to struct node *; C++ does not allow that, and would require struct node *head = (struct node *)malloc(sizeof(struct node));)
And if I pass **head as a parameter of the insert function, what does it do?
You'd have to adjust the body of the function, but it would allow you to change the location of the head of the list in the calling function.
The answer for your first question is:
head=(node *)malloc(sizeof(node));
malloc() returns a pointer of type void so here you are explicitly converting it to a pointer of type node .But remember, in C a pointer of type void() converts implicitly into the type of pointer that it is assign to. So if you write like:
head=malloc(sizeof(node));
It will stil work correctly. But with the C++ compiler it is not the case, In C++ pointer of type void is not implicitly cast to the type of pointer that it it assign to.
Also to answer your question,
void insert(struct node *head,int data)
If you pass **head as parameter it will show an error declaring that the type of operator is not matched. This is because you had declared it as struct node *head not as struct node **head.
If you type in
typedef struct node{
int data;
struct node *next, *prev;
} node;
the compiler will accept your head = (node *)malloc(sizeof(node)); code. Remember that typedef allows you to use the struct the same way it's used in C++.
Technically there isn't a difference between sizeof(node) and sizeof(struct node) (at least in C++), since both will return the size of the struct.
In C however it's mandatory to write struct node, just like it's mandatory to write struct node when declaring a variable of that type, simply because there is no type node.
C only understands primitives (int, char, long) and custom types declared with struct. Every C compiler is very strict with this keyword struct and assumes you're talking about a variable if you forget it.
Regarding your second question: You can't. You can't pass a pointer to a pointer to a function, which only accepts a regular pointer, unless you cast it. In that case however, it will point to a completely arbitrary position on the stack (where your pointer is located) and probably make your program crash.
create (struct node **p)
{
struct node *temp,*q;
int n;
printf("enter the length of link list");
scanf("%d".&n);
while(n>0)
{
if(*p == NULL)
{
*p=(struct node*)malloc(sizeof(struct node*));
printf("enter the element");
scanf("%d".&((*p)->data));
(*p)->next=NULL;
}
else
q=*p;
while(q->next=NULL)
q=q->next;