Queue implementation throws incompatible pointer type error - pointers

I think I'm missing general concepts on structs and pointers. Hence, below code is producing 2 warnings/errors and I don't understand why.
Why is "queue->head = temp" producing following warning:
warning: assignment from incompatible pointer type [enabled by default]
Why is "queue->tail->next = temp" producing following error:
error: dereferencing pointer to incomplete type.
Note: The line "Node *temp = newNode(data)" does not throw any error/warnings so it's successful.
typedef struct {
int data;
struct Node *next;
} Node;
typedef struct {
struct Node *head;
struct Node *tail;
} Queue;
void enQueue(Queue *queue, int data)
{
// Create a new node
Node *temp = newNode(data);
// If queue is empty, then new node is both head and tail
if (queue->tail == NULL)
{
queue->head = temp;
queue->tail = temp;
return;
}
// Add the new node at the end of queue and change tail
queue->tail->next = temp;
queue->tail = temp;
}

How did you get this code to compile?
Your Node structure contains a pointer to another Node. In the way you declared your structure, the compiler does not know Node while parsing your structure definition. Hence, you must write:
1 typedef struct Node{
2 int data;
3 struct Node *next;
4 } Node;
In this way, the compiler knows how to handle your structure when parsing it. In line 3 it already knows that Nodeis structure. Since some of your code is missing, I created a minimal example that implements a super simple queue:
#include <stdlib.h>
#include <stdio.h>
#define MAX 5
typedef struct Node{
int data;
struct Node *next;
} Node;
typedef struct {
struct Node *head;
struct Node *tail;
} Queue;
Node* newNode(const int nodeData){
Node* tmp = malloc(sizeof(*tmp));
if (NULL == tmp){
printf("Could not allocate Node ... exiting");
exit(EXIT_FAILURE);
}
tmp->data = nodeData;
tmp->next = NULL;
return tmp;
}
void enQueue(Queue *queue, int data)
{
// Create a new node
Node *temp = newNode(data);
// If queue is empty, then new node is both head and tail
if (queue->tail == NULL)
{
printf("Queue is empty\n");
queue->head = temp;
queue->tail = temp;
return;
}
// Add the new node at the end of queue and change tail
queue->tail->next = temp;
queue->tail = temp;
}
void printQueue(Queue* q){
Node* tmp = q->head;
while (tmp != NULL){
printf("Value: %d\n", tmp->data);
tmp = tmp->next;
}
}
int main(void){
Queue q;
q.head = q.tail = NULL;
int i;
for (i = 0; i < MAX; ++i){
printf("%d is entered into the queue\n", i);
enQueue(&q, i);
}
printQueue(&q);
}

Related

when to use to double pointers and pointers

// A C program to demonstrate linked list based implementation of queue
#include <stdio.h>
#include <stdlib.h>
struct QNode {
int key;
struct QNode* next;
};
struct Queue {
struct QNode *front, *rear;
};
struct QNode* newNode(int k)
{
struct QNode* temp = (struct QNode*)malloc(sizeof(struct QNode));
temp->key = k;
temp->next = NULL;
return temp;
}
struct Queue* createQueue()
{
struct Queue* q = (struct Queue*)malloc(sizeof(struct Queue));
q->front = q->rear = NULL;
return q;
}
void enQueue(struct Queue* q, int k)
{
struct QNode* temp = newNode(k);
if (q->rear == NULL) {
q->front = q->rear = temp;
return;
}
q->rear->next = temp;
q->rear = temp;
}
void deQueue(struct Queue* q)
{
if (q->front == NULL)
return;
struct QNode* temp = q->front;
q->front = q->front->next;
if (q->front == NULL)
q->rear = NULL;
free(temp);
}
int main()
{
struct Queue* q = createQueue();
enQueue(q, 10);
enQueue(q, 20);
deQueue(q);
deQueue(q);
enQueue(q, 30);
enQueue(q, 40);
enQueue(q, 50);
deQueue(q);
printf("Queue Front : %d \n", q->front->key);
printf("Queue Rear : %d", q->rear->key);
return 0;
}
The above code is from geeksforgeeks website.
in function calls they used pointer to struct,
in function definition they passed pointer to struct.
how it works, I thought we need to use double pointers , otherwise > it is pass by value instead of pass by reference.
the above code works fine, but i have doubt about it.
In main there is a variable q declared which is a pointer to a struct. The variable q is used as the function argument which means the function receives a pointer to the struct. The function can dereference the pointer and modify the struct. The variable q is technically passed by value because its value is a pointer and that's what the function receives. But you have to remember that q points to a struct that could be modified by the function.
Because this situation causes some confusion some people have tried to introduce new terminology like "pass by sharing" or "object sharing" to distinguish it from passing primitive values like an `int' by value.
If you had passed a pointer to a pointer then the function could have modified the variable q declared in main and changed it so it points to a completely different struct. That would be (technically) pass by reference because you are passing a reference to the variable.

declaration in local vs global

#include<stdio.h>
#include<stdlib.h>
struct node
{
int data;
struct node* link;
};
void insert_last(struct node **head, int value)
{
struct node* new = malloc(sizeof(struct node));
new->data = value;
if( !*head )
{
new->link = NULL;
*head = new;
}
else
{
struct node* last = *head;
while(last->link)
{
last = last->link;
}
new->link = NULL;
last->link = new;
}
}
struct node *head;
int main()
{
insert_last( & head, 5);
insert_last( & head, 10);
insert_last( & head, 15);
printf("%d ", head->data);
printf("%d ", head->link->data);
printf("%d ", head->link->link->data);
}
If I Declare struct node *head inside of the main the programm is not working.
what is the reason ?
> if i declare globally its working, otherwise not working.
> I repeating question because stackoverflow asking add more details(> If I Declare struct node *head in side of the main the programm is not working.
what is the reason ?
> if i declare globally its working, otherwise not working.)
There is a initialization bug: In insert_last(), the variable head is tested without having been initialized explicitely. If head is declared as global, it is located in a global section that is most probably initialized to 0 by the loader (when the program is started); if head is declared in the function main() then it is located in the stack of the function and is not set to 0.

why my my function is using call by value method?

I don't know why in last line it is printing data of first element instead of last element. I want explanation.
// A simple C program for traversal of a linked list
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
// This function prints contents of linked list starting from
// the given node
void printList(struct Node* n)
{
while (n != NULL) {
printf(" %d ", n->data);
n = n->next;
}
}
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
// allocate 3 nodes in the heap
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
head->data = 1; // assign data in first node
head->next = second; // Link first node with second
second->data = 2; // assign data to second node
second->next = third;
third->data = 3; // assign data to third node
third->next = NULL;
printList(head);
printf("%d",head->data);
return 0;
}
As the function is accepting pointers so it should be call by reference.
And in last loop of function when n pointer is equal to NULL.
But in last line of this code is printing data of first list of my linked list.
Actually what you are doing is not being done in the actual linked list, it not pass by reference
void printList(struct Node* n)
{
/* some code here */
}
void main()
{
/* all your code here */
printList(head);
}
so if you want to change the head in the actual linked list you will have to pass the address of the pointer head to the function
something like this
int append_list(node **head, int data)
{
while((*head)->next!=NULL)
{
(*head) = (*head)->next;
}
}
int main()
{
struct node *head = NULL;
/* add nodes */
print_list(&head);
}
so here is the modification in your code:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
};
// This function prints contents of linked list starting from
// the given node
void printList(struct Node** n)
{
while ((*n)->next != NULL) {
printf(" %d ", (*n)->data);
(*n) = (*n)->next;
}
}
int main()
{
struct Node* head = NULL;
struct Node* second = NULL;
struct Node* third = NULL;
// allocate 3 nodes in the heap
head = (struct Node*)malloc(sizeof(struct Node));
second = (struct Node*)malloc(sizeof(struct Node));
third = (struct Node*)malloc(sizeof(struct Node));
head->data = 1; // assign data in first node
head->next = second; // Link first node with second
second->data = 2; // assign data to second node
second->next = third;
third->data = 3; // assign data to third node
third->next = NULL;
printList(&head);
printf("%d",head->data);
return 0;
}
here the output will be
1 2 3
since you have used (*head) for the traversal you no longer have the access to your list and hence will get segmentation fault if you try to access
(*head)->next
But I would not suggest to do this since now you will not be able to deallocate the memory
There is no pass-by-reference in C, everything is pass-by-value. People use pointers to emulate pass-by-reference, and this works because you can use the passed-in pointer to get at the same underlying data item.
In other words, even though the passed-in pointer is a pass-by-value copy within the function, the fact that it has the same value as the original means that both point to the same thing.
However, if the thing you're trying to change is a pointer already, you need a pointer to a pointer to do this emulation.
I could give you the code to do this but, believe me, it's not want you want. It would mean that the list printing code would be destructive to the list itself, since the head would now point to NULL.
Here is some code instead which shows how to do something similar, one that uses this double-pointer method to change the pointer outside of the function:
#include <stdio.h>
#include <stdlib.h>
void allocateSomeMem(void **pPtr, size_t sz) {
*pPtr = malloc(sz);
}
int main(void) {
void *x = NULL;
printf("%p\n", x);
allocateSomeMem(&x, 42);
printf("%p\n", x);
}
You can see by the output that the pointer is being changed:
(nil)
0x55f9ce5f96b0
Now, obviously, you wouldn't do this for the simple example shown, it would be far easier just to return the new pointer and have it assigned to x. But this is just illustrative of the method to use.

Deleting data from a linked list using pointers

I was trying to come up with a program that will use a linked list to read data off a file and delete grades that are under 50%. I came up with this code but it gives me the error "type float' argument given todelete', expected pointer". Please help if you can.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
struct node
{
int id;
char name[10];
float grade;
struct node * next;
};
void build_link(struct node * ap);
void happy (struct node * bp);
void delete_fail (struct node *np);
int main(int argc, char *argv[])
{
struct node head;
head.next = NULL;
build_link( &head);
happy(head.next);
delete_fail (head.next);
system("PAUSE");
return 0;
}
void build_link(struct node * tmp)
{
int nu_id;
char nu_nam[10];
float nu_grade;
struct node * np;
FILE *fp;
fp = fopen("Student.txt","r");
while (fscanf( fp,"%d %s %f", &nu_id, nu_nam, &nu_grade ) != EOF)
{
np = (struct node *) malloc ( sizeof (struct node) );
strcpy (np->name,nu_nam);
np->id = nu_id;
np->grade = nu_grade;
np->next = NULL;
tmp->next = np;
tmp = tmp->next;
}
}
void happy(struct node *np)
{
while (np != NULL)
{
printf(" %d %s %f \n", np->id, np->name, np->grade);
np = np->next;
}
}
void delete_fail(struct node* grade)
{
node *np;
if(np == NULL)
printf("\nElement not found");
else
{
This is where my problem lies. I am not sure how to fix this part right here.
if( np->grade <50 )
np->grade = delete(np->grade);**
else
if(np->grade > 60)
np->grade = np->grade;
}
}

GMainContext have ref_count > 0 after unref

I am not getting ref_count to decrease properly for my GMainContext. The example program here is a small version of a large program (which uses threads, hence the need to create a context and push it on the thread).
GMainLoop *loop;
GMainContext *ctx;
struct conn
{
GSocketClient *client;
GSocketConnection *conn;
GInputStream *in;
GOutputStream *out;
gchar data[8192];
unsigned int count;
};
static void
read_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
struct conn *c = (struct conn *)user_data;
gssize len = g_input_stream_read_finish(c->in, res, NULL);
g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
if (c->count++ == 1) {
printf("End of life as I know it...\n");
g_main_loop_quit(loop);
}
}
static void
write_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
}
static void
connect_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
printf("## %s\n", __FUNCTION__);
struct conn *c = (struct conn *)user_data;
c->conn = g_socket_client_connect_to_host_finish(c->client, res, NULL);
c->in = g_io_stream_get_input_stream(G_IO_STREAM(c->conn));
c->out = g_io_stream_get_output_stream(G_IO_STREAM(c->conn));
char *data = "GET /axis-cgi/mjpg/video.cgi HTTP/1.0\r\n\r\n";
g_output_stream_write_async(c->out, data, strlen(data), G_PRIORITY_DEFAULT, NULL, write_done_cb, c);
g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
}
int
main(int argc, char **argv)
{
g_type_init();
struct conn *c = g_malloc0(sizeof *c);
ctx = g_main_context_new();
loop = g_main_loop_new(ctx, FALSE);
g_main_context_push_thread_default(ctx);
c->client = g_socket_client_new();
g_socket_client_connect_to_host_async(c->client, "10.85.25.20", 80, NULL, connect_done_cb, c);
g_main_loop_run(loop);
g_io_stream_close(G_IO_STREAM(c->conn), NULL, NULL);
g_object_unref(c->client);
g_object_unref(c->conn);
g_main_context_pop_thread_default(ctx);
g_main_loop_unref(loop);
g_main_context_unref(ctx);
return 0;
}
Using gdb, inserting breakpoint just before return I can see that ctx still have one ref count:
(gdb) p ctx->ref_count
$2 = 1
If I do another g_main_context_unref(ctx); everything shuts down as expected. I do not understand where I get this ownership though.
Thanks in advance for your help
I found the error. I read_done_cb I issued another g_input_stream_read_async and immediately after quitting the main loop. g_input_stream_read_async upped the ref_count but GMainLoop never got a chance to return to my callback (and decreasing the ref_count on my GMainContext).
Moving the call to g_input_stream_read_async in my callback to below the if statement
static void
read_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
struct conn *c = (struct conn *)user_data;
gssize len = g_input_stream_read_finish(c->in, res, NULL);
if (c->count++ == 1) {
printf("End of life as I know it...\n");
g_main_loop_quit(loop);
}
g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
}
correctly resolved the number of ref counts on my main context.
Silly mistake. Hopefully someone will find some use of my post at least.
g_main_context_new(), g_main_loop_new(), and g_main_context_push_thread_default() all ref the context. g_main_context_pop_thread_default(), g_main_loop_unref(), and g_main_context_unref() all unref it. So your intuition is sound.
I would use a watchpoint in gdb: watch ctx->ref_count to find out where the extra reference is being added.

Resources