I was just brushing my pointer concepts and it seems its really messed up over time.
I was trying to implement BFS in binary tree.
Pseudo Code :
1) tempNode = root node
2) while tempNode is not null
print data at tempNode
enqueue left and right child
tempNode = dequeue
Here's my code :
#include <stdio.h>
#include <stdlib.h>
#define MAX_Q_SIZE 100
/**
* Using Queue to keep track of next nodes to be visited
*/
struct node
{
int data;
struct node *left;
struct node *right;
};
struct node *createQueue(int *front, int *rear)
{
struct node *queue = (struct node*)malloc(sizeof(struct node) * MAX_Q_SIZE);
*front = *rear = 0;
return queue;
}
void enQueue(struct node *queue, int *rear, struct node *newNode)
{
queue[*rear].data = newNode->data;
queue[*rear].left = newNode->left;
queue[*rear].right = newNode->right;
(*rear)++;
}
struct node *deQueue(struct node *queue, int *front)
{
(*front)++;
return &queue[*front - 1];
}
struct node *newNode(int data)
{
struct node *node = (struct node*)malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
void printBFS(struct node *root)
{
int front,rear;
struct node *queue = createQueue(&front, &rear);
struct node *tempNode = root;
while(tempNode != NULL)
{
printf("%d ",tempNode->data);
if(tempNode->left != NULL)
enQueue(queue,rear,tempNode->left);
if(tempNode->right != NULL)
enQueue(queue,rear,tempNode->right);
tempNode = deQueue(queue,front);
}
}
int main()
{
struct node *root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
printBFS(root);
return 0;
}
I am getting following 4 types of warnings :
BFS2.c: In function ‘printBFS’:
BFS2.c:60:13: warning: passing argument 2 of ‘enQueue’ makes pointer from integer without a cast [enabled by default]
enQueue(queue,rear,tempNode->left);
^
BFS2.c:23:6: note: expected ‘int *’ but argument is of type ‘int’
void enQueue(struct node *queue, int *rear, struct node *newNode)
^
BFS2.c:63:9: warning: passing argument 2 of ‘deQueue’ makes pointer from integer without a cast [enabled by default]
tempNode = deQueue(queue,front);
^
BFS2.c:34:14: note: expected ‘int *’ but argument is of type ‘int’
struct node *deQueue(struct node *queue, int *front)
Can anyone please help me to clarify the doubts as to why I am getting the warnings. I am unable to figure out the problems here. :(
You are passing int variables where int* (pointer to int) is expected. Pass the address of an int variable with & the address of operator. Multiple examples :
enQueue(queue, &rear, tempNode->left);
enQueue(queue, &rear, tempNode->right);
tempNode = deQueue(queue, &front);
As David has pointed out, the program will crash (segmentation fault). You may want to rethink the design of deQueue and/or what should happen if both tempNode->left and tempNode->right are NULL.
Instead of passing front and rear to enQueue() and deQueue(), pass &front and &rear. The & (address-of operator) takes the address of the variable. Since both front and rear are ints, this operator will create the correct result, an int *.
As an aside: don't cast the return value of malloc().
Your immediate pointer problems come from attempting to pass an int as a pointer:
int front,rear;
...
enQueue(queue,&rear,tempNode->left);
// enQueue(queue,rear,tempNode->left);
You have the same issue with deQueue immediately following. However, you have larger issues to deal with. Once you fix the pointer issues you will be faced with a Segmentation fault..
And to not leave you hanging, you simply need to go back and rework your queue implementation, it is a wreck. You will generate a Segmentation fault because your value for front in deQueue grows unchecked until i reaches a value of 100 and you attempt to write beyond the end of your MAX_Q_SIZE block of memory.
If you are brushing up on pointers, then don't torture pointers to try and shoehorn them into array syntax. There is no need for passing struct node *queue and then attempting to find array index syntax that will work:
queue[*rear].right = newNode->right;
when a simple pointer expression will do:
(queue + *rear)->right = newNode->right;
The same applies to:
return (queue + *front - 1); // syntax only your queue logic need fixing
This will make your code much more readable and reduce the chance for error when you pass pointers but then try and make the pointer work with something like:
return &queue[*front - 1];
Related
This question already has answers here:
What is self-referencing structure in C?
(3 answers)
Closed 3 years ago.
Can someone explain what we mean when we do, like what does struct Node* next do. does it create a pointer of type struct? any help and resources about structures in c would be helpful
struct Node {
int dest;
struct Node* next;
};
"struct" itself is not a type. "struct [tag]" is a type, for example "struct Node" in your code.
In your case you define a structure type. Every structure of that type will contain a pointer to another structure of that type as a member called "next".
This allows you to chain the structures together in a so called linked list. You store a pointer to the first structure in a variable, then you can follow the chain of links down to the structure you need.
For example, you can do
struct Node *start;
start = malloc(sizeof struct Node);
start->dest = 7;
start->next = malloc(sizeof struct Node);
start->next->dest = 13;
start->next->next = malloc(sizeof struct Node);
start->next->next->dest = 19;
printf("%d %d %d\n", start->dest, start->next->dest, start->next->next->dest);
free(start->next->next);
free(start->next);
free(start);
Please note that this code omits all error handling, in real code you have to handle the case when malloc returns NULL.
Also, in real code you would use such a structure in loops that traverse the chain, not directly as above.
As #Serge is pointing out in comments, is not a struct within a struct, is a reference (a pointer) to an object of the same type, an example:
#include <stdio.h>
struct Node {
int dest;
struct Node* next;
};
int main(void)
{
/* An array of nodes */
struct Node nodes[] = {
{1, &nodes[1]}, // next points to the next element
{2, &nodes[2]}, // next points to the next element
{3, NULL} // next points to null
};
/* A pointer to the first element of the array */
struct Node *node = nodes;
while (node) {
printf("%d\n", node->dest);
node = node->next; // node moves to the next element
}
return 0;
}
Output:
1
2
3
Of course, in my example there is no benefit in using a linked list, linked lists are useful when we don't know the number of elements before-hand.
Another example using dynamic memory:
struct Node *head, *node;
node = head = calloc(1, sizeof *node);
node->dest = 1;
while (more_elements_needed) {
node->next = calloc(1, sizeof *node);
node->next->dest = node->dest + 1;
node = node->next;
}
for (node = head; node != NULL; node = node->next) {
printf("%d\n", node->dest);
}
I've seen this question in multiple posts but I have yet to find one that has a good explanation for me. Im trying to create a linked list but the struct nor the functions cant be called without getting the error cannot cast to a pointer. Its really bugging me. Any help would be appreciated on how to get this working right. Heres some of the code below thats the issue.
typedef struct node
{
void *data;
struct node *next;
} node;
node *head = NULL;
node* create(void *data, node *next)
{
node *new_node = (node*)malloc(sizeof(node));
if(new_node == NULL)
{
exit(0);
}else{
new_node->data = data;
new_node->next = next;
return new_node;
}
}
node* prepend(node *head, void *data)
{
node *new_node = create(data,head);
head = new_node;
return head;
}
void preload_adz(int adz_fd)
{
struct adz adz_info;
char adz_data[40];
char adz_text[38];
int adz_delay;
char adz_delayS[2];
read(adz_fd,adz_data,40);
strncpy(adz_text,adz_data + 2,40-2);
sprintf(adz_delayS, "%c%c",adz_data[0],adz_data[1]);
adz_delay = atoi(adz_delayS);
adz_info.delay = adz_delay;
strncpy(adz_info.text,adz_text,38);
head = prepend(head, (void*)adz_info); //<---This line throws the error
while(read(adz_fd,adz_data,40) > 0)
{
}
}
struct adz adz_info;
...
head = prepend(head, (void*)adz_info); //<---This line throws the error
The problem here is adz_info is not a pointer, it's the actual struct on the stack. Passing adz_info into a function will copy the struct.
You need a pointer to that struct. Use & to get its address. Once you have the pointer, you don't need to cast it to void pointer, that cast is automatic.
head = prepend(head, &adz_info);
Note that casting is a bookkeeping thing. Casting to void * doesn't turn a struct into a pointer, it says "compiler, ignore the declared type of this variable and just trust me that this is a void pointer".
C newbie here, and I can't seem to figure this one out. So I'm starting to implement a linked-list (just something basic so I can wrap my head around it) and I've hit a snag. The program runs fine, but I can't free() the data stored in my struct.
Here's the source:
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node* next;
void* data;
size_t data_size;
};
typedef struct node node;
node* create_node(void* data, size_t size)
{
node* new_node = (node*)malloc(sizeof(node));
new_node->data = (void*)malloc(size);
new_node->data = data;
new_node->next = NULL;
return new_node;
}
void destroy_node(node** node)
{
if(node != NULL)
{
free((*node)->next);
//this line here causes the error
free((*node)->data);
free(*node);
*node = NULL;
printf("%s\n", "Node destroyed!");
}
}
int main(int argc, char const *argv[])
{
float f = 4.325;
node *n;
n = create_node(&f, sizeof(f));
printf("%f\n", *((float*)n->data));
if (n->next == NULL)
printf("%s\n", "No next!");
destroy_node(&n);
return 0;
}
I get this message in the program output:
malloc: *** error for object 0x7fff5b4b1cac: pointer being freed was not allocated
I'm not entirely keen on how this can be dealt with.
This is because when you do:
new_node->data = data;
you replaces the value put by malloc just the line before.
What you need is to copy the data, see the function memcpy
node* create_node(void* data, size_t size)
...
new_node->data = (void*)malloc(size);
new_node->data = data;
Here, (1) you are losing memory given by malloc because the second assignment replaces the address (2) storing a pointer of unknown origin.
Number two is important because you can't guarantee that the memory pointed to by data was actually malloced. This causes problems when freeing the data member in destroy_node. (In the given example, an address from the stack is being freed)
To fix it replace the second assignment with
memcpy (new_node->data, data, size);
You also have a potential double free in the destroy_node function because the next member is also being freed.
In a linked list, usually a node is freed after being unlinked from the list, thus the next node shouldn't be freed because it's still reachable from the predecessor of the node being unlinked.
While you got an answer for the immediate problem, there are numerous other issues with the code.
struct node {
struct node* next;
void* data;
What's up with putting * next to type name? You are using it inconsistently anyway as in main you got node *n.
size_t data_size;
};
typedef struct node node;
node* create_node(void* data, size_t size)
{
node* new_node = (node*)malloc(sizeof(node));
What are you casting malloc for? It is actively harmful. You should have used sizeof(*new_node). How about checking for NULL?
new_node->data = (void*)malloc(size);
This is even more unnecessary since malloc returns void * so no casts are necessary.
new_node->data = data;
The bug already mentioned.
new_node->next = NULL;
return new_node;
}
void destroy_node(node** node)
{
if(node != NULL)
{
How about:
if (node == NULL)
return;
And suddenly you get rid of indenation for the entire function.
free((*node)->next);
//this line here causes the error
free((*node)->data);
free(*node);
*node = NULL;
printf("%s\n", "Node destroyed!");
What's up with %s instead of mere printf("Node destroyed!\n")? This message is bad anyway since it does not even print an address of aforementioned node.
In a program I'm writing I need a linked list, so it's a pretty specific implementation. It needs:
the ability to add a node to the end
the ability to remove a node whose data matches a specified value
The data is a cstring, no more than 20 characters in length. I'm not very experienced with C and am getting errors with the following signature void addToEnd(llist root, char entery[51]). I tried replacing llist with node but then the error is "unknown type name node". How can I get rid of this?
Here's the code
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
typedef struct node
{
char entery[51];
struct node* next;
} llist;
/*may be losing root address permanently*/
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
node last = malloc(sizeof(struct node));
root->next = last;
strcpy(last, entery);
}
int main()
{
struct node *root = malloc(sizeof(struct node));
root->next = NULL;
strcpy(root->entery, "Hello");
struct node *conductor = root;//points to a node while traversing the list
if(conductor != 0)
while(conductor->next != 0)
conductor = conductor->next;
/* Creates a node at the end of the list */
conductor->next = malloc(sizeof(struct node));
conductor = conductor->next;
if (conductor == NULL)
{
printf( "Out of memory" );
return EXIT_SUCCESS;
}
/* initialize the new memory */
conductor->next = NULL;
strcpy(conductor->entery, " world\n");
addToEnd(root, " at the");
addToEnd(root, " end");
/*print everything in list*/
conductor = root;
if(conductor != NULL)
{
while(conductor->next != NULL)
{
printf("%s", conductor->entery);
conductor = conductor->next;
}
printf("%s", conductor->entery);
}
return EXIT_SUCCESS;
}
One thing I'm unclear about, is in all the examples I've seen is they typedef the struct. Why? Let me elaborate: how do you know if you want to be passing just node or struct node. Also I don't really see the point, struct node isn't that much longer than a single typedef'd name.
Problems:
line 12: void addToEnd(llist root, char entery[51]) shall be void addToEnd(llist *root, char entery[51]). Here root must be a pointer type or you actually can not modify its value inside the function and make it visible outside the function.
line 16: node last = malloc(sizeof(struct node)); shall be struct node *last = malloc(sizeof(struct node));. Since in C you must reference a type name with the keyword struct, and also it shall be a pointer or it cannot be initialized with malloc.
As for your typedef question, I believe it is optional and people use it only for convenience. Personally I don't use typedef on a struct very often.
EDITED:
Also your code comes with bugs. Sorry I was only focusing on the syntax before.
Please notice that malloc in C don't assure you that the allocated memory is zeored, it's actually could be anything inside. So you need to fill it manually: to add a line last->next = NULL; at the end of addToEnd.
To refer to your struct of the linked list, use struct node, after the typedef, you can also use llist. You can also ues, as the linked question uses.
typedef struct node
{
char entery[51];
struct node* next;
} node;
In this style, you can use node the same as struct node.
The syntax error you are facing is, you misused the arrow operator ->, it's used with pointers of struct. For struct, use the dot operator .
So for the function
void addToEnd(llist root, char entery[51])
{
while(root->next != NULL)
root = root->next;
You should pass in a pointer:
void addToEnd(llist* root, char entery[51])
It's amazing how even the littlest program can cause so much trouble in C.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
tree* tree = (tree*) malloc(sizeof(tree));
node *node = (node*) malloc(sizeof(node));
tree->nodes[0] = node;
return tree;
}
int main() {
return 0;
}
The compiler says:
main.c: In function 'initTree':
main.c:17: error: expected expression before ')' token
main.c:18: error: expected expression before ')' token
Can you please help?
You're using two variables named tree and node, but you also have structs typedefed as tree and node.
Change your variable names:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
/* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
tree* atree = malloc(sizeof(tree)); /* different names for variables */
node* anode = malloc(sizeof(node));
atree->nodes[0] = anode;
return atree;
}
int main() {
return 0;
}
tree and node is your case are type names and should not be used as variable names later on.
tree *initTree() {
tree *myTree = (tree*) malloc(sizeof(tree));
node *myNode = (node*) malloc(sizeof(node));
myTree->nodes[0] = myNode;
return myTree;
}
Change (tree*) and (node*) to (struct tree*) and (struct node*). You can't just say tree because that's also a variable.
Change the body of initTree as follows:
tree* myTree = (tree *)malloc(sizeof(tree));
node *myNode = (node *)malloc(sizeof(node));
myTree->nodes[0] = myNode;
return myTree;
Don't use typedef'ed names as variable names, and there is not need to cast malloc(); in C.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int value;
struct node *leftChild;
struct node *rightChild;
} node;
typedef struct tree {
int numNodes;
struct node** nodes;
} tree;
tree *initTree() {
tree->nodes[0] = malloc(sizeof(node));
return malloc(sizeof(tree));
}
int main() {
return 0;
}
I second that Mehrdad's explanation is to the point.
It's not uncommon that in C code you define a variable with the same name as the struct name for instance "node node;". Maybe it is not a good style; it is common in, e.g. linux kernel, code.
The real problem in the original code is that the compiler doesn't know how to interpret "tree" in "(tree*) malloc". According to the compiling error, it is obviously interpreted as a variable.
Apart from the original question, this code, even in it's correct forms will not work, simply due to the fact that tree::nodes (sorry for the C++ notation) as a pointer to a pointer will not point to anything usefull right after a tree as been malloced. So tree->nodes[0] which in the case of ordinary pointers is essentially the same like *(tree->nodes), can't be dereferenced. This is a very strange head for a tree anyway, but you should at least allocate a single node* to initialize that pointer to pointer:
tree *initTree() {
/* in C code (not C++), don't have to cast malloc's return pointer, it's implicitly converted from void* */
tree* atree = malloc(sizeof(struct tree)); /* different names for variables */
/* ... */
/* allocate space for numNodes node*, yet numNodes needs to be set to something beforehand */
atree->nodes = malloc(sizeof(struct node*) * atree->numNodes);
node* anode = malloc(sizeof(struct node));
atree->nodes[0] = anode;
return atree;
}
Interestingly, it does compile cleanly if you simply write the allocations as:
tree *tree = malloc( sizeof *tree );
It is often considered better style to use "sizeof variable"
rather than "sizeof( type )", and in this case the stylistic
convention resolves the syntax error. Personally, I think
this example is a good case demonstrating why typecasts are
generally a bad idea, as the code is much less obfuscated if
written:
struct tree *tree = malloc( sizeof *tree );