I'm learning C and trying to create dynamic double ended queue. I need to have one structure element that contains references to queue's front and end (head, tail of type node) and I'm trying to pass this element to a function and allocate memory for head and tail node. And i get segmentation fault.
My structures
struct node_st {
struct node_st* prev_node;
struct node_st* next_node;
// Value type can be changed.
int value;
bool is_zero_element;
};
typedef struct node_st node;
struct deque_link {
struct node_st* head;
struct node_st* tail;
int errorcode;
};
typedef struct deque_link dlink;
Main function
#include "deque.h"
#include <stdio.h>
int main() {
dlink* deque;
deque_create(deque);
}
deque_create() function
void deque_create(dlink* deque) {
deque->head = deque->tail = (node*)malloc(sizeof(node));
}
I guess I don't understand pointers enough, but I will be very happy if someone could help.
The pointer deque that you pass to deque_create is not initialized. It has indeterminate ("garbage") content. Therefore, it does not point to a valid deque. But you try to access it with the -> operator.
Your initialization / creation of the deque is on the wrong level: You try to create nodes, but you should create a deque (without any nodes, initally.)
You could write a constructor function that allocates memory and initializes it:
dlink *deque_create(void)
{
dlink *deque = malloc(sizeof(*deque));
// Handle allocation failure
deque->head = deque->tail = NULL;
deque->errorcode = 0;
return deque;
}
Then use it like this:
dlink* deque = deque_create();
// do stuff with deque
// delete deque and its nodes
You should also write a destructor function which deletes all nodes to complement the constructor.
Related
// Linked list implementation in C
#include <stdio.h>
#include <stdlib.h>
// Creating a node
struct node {
int value;
struct node *next; //What is this, what are we doing here?
};
// print the linked list value
void printLinkedlist(struct node *p) {
while (p != NULL) {
printf("%d ", p->value);
p = p->next;
}
}
int main() {
// Initialize nodes
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
// Allocate memory
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
// Assign value values
one->value = 1;
two->value = 2;
three->value = 3;
// Connect nodes
one->next = two;
two->next = three;
three->next = NULL;
// printing node-value
head = one;
printLinkedlist(head);
}
I want to ask what are we doing here with this line of code?
it's in the creating a node part of the code (top).
struct node *next;
Are we assigning a pointer type struct variable for the sturct node but its inside of the same struct, assigning a variable named *next inside the same struct? But that isn't allowed, right?
we can either declare the variable out side the } and between ; or in the main()
function part of the code only, Isn't it?
Like
main()
{
struct node *next;
}
Again, then I came across a post mentioning it as a pointer to the structure itself, can anyone explaine how can we do this inside the same struct?
The next member points to another instance of struct node. Graphically, we usually represent it like this:
+–––––––+––––––+ +–––––––+––––––+
| value | next |––––> | value | next |
+–––––––+––––––+ +–––––––+––––––+
A struct type cannot contain an instance of itself - we can’t create a type like
struct node {
int value;
struct node next;
};
for two reasons:
The type definition isn’t complete until the closing }, and you cannot create an instance of an incomplete type;
The type would require infinite storage (struct node contains a member next of type struct node which contains a member next of type struct node which contains a member next of type struct node...);
However, we can declare next as a pointer to struct node, since we can create pointers to incomplete types. The size and representation of a pointer is independent of the size and representation of the type it points to.
What it means
The line struct node *next; is read as "next is a pointer to another struct node".
This is just a recursive structure declaration (definition):
struct node {
int value;
struct node *next; //What is this, what are we doing here?
};
It says a node consist of two parts:
an integer value
a pointer to another node.
The wiki article on linked lists has a nice visualization showing how one node points to another (or to NULL to end the chain).
How does it work?
As you noted, the interesting part is how the declaration can include a reference back to itself. The compiler handles this in two steps:
It sizes the struct as consisting of an int and a pointer (they're all the same size regardless of what they are pointing to).
Later it type checks the assignment and generates the appropriate assembly. When you write one->value = 1;, it makes sure the 1 is an integer and generates code to move 1 to the integer slot. And when your write one->next = two;, it verified that two is a pointer to a node and generates code to move that pointer to the second slot for the struct node pointer.
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.
All the implementations I have seen online use pointer to declare nodes and then will use malloc to create space for them like this:
struct Node
{
int data;
struct Node *next;
};
int main()
{
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));
...
But I can also create the same without pointers and malloc like this:
struct node {
int id;
struct node* next;
};
struct node head = {0, NULL};
struct node one = {1, NULL};
struct node two = {2, NULL};
struct node tail = {3, NULL};
int main(){
head.next = &one;
one.next = &two;
two.next = &tail;
...
My question is, why the 1st method is mostly the one used, why do we need to declare each node as pointer and why do we need malloc?
(Just to point out I know why struct Node *next; is declared as pointer int the struct declaration).
You should do this with local variables, not global ones, but the general idea would be the same. You should also steer towards having arrays and not heaps of otherwise unrelated variables:
struct node {
int id;
struct node* next;
};
int main(){
struct node nodes[4];
for (int i = 0; i < 4; ++i) {
nodes[i].id = (3 - i);
if (i != 0) {
nodes[i].next = &nodes[i-1];
}
}
return 0;
}
Where something like that assembles them in reverse order for convenience, but they're all grouped together in terms of memory initially.
malloc is used because you often don't know how many you're going to have, or they get added and removed unpredictably. A general-purpose solution would allocate them as necessary. A specialized implementation might allocate them as a single block, but that's highly situational.
Here the lifespan of nodes is within that function alone, so as soon as that function ends the data goes away. In other words:
struct node* allocateNodes() {
struct node nodes[10];
return &nodes; // Returns a pointer to an out-of-scope variable, undefined behaviour
}
That won't work. You need a longer lived allocation which is precisely what malloc provides:
struct node* allocateNodes() {
struct node *nodes = calloc(10, sizeof(struct node));
return nodes; // Returns a pointer to an allocated structure, which is fine
}
The problem is if you malloc you are responsible for calling free to release the memory, so it becomes more work.
You'll see both styles used in code depending on the required lifespan of the variables in question.
If you know ahead of time exactly how many items will be in your list, then you're probably better off using an array rather than a list. The whole point of a linked list is to be able to grow to an unknown size at runtime, and that requires dynamic memory allocation (i.e., malloc).
struct node
{
int data;
node* pointerToNextNode;
};
Here pointerToNextNode is the type of struct node, and it is declared inside the struct.
How does the struct know the type of next pointer of its own type - when it itself hasn't been formed yet?
There is no keyword extern used. How does this work?
It doesn't need to know the structure, it's enough to know the type name, namely struct node — and that has already been defined.
Same result you can obtain by forward type declaration:
struct node; // declare the struct not defining it
struct node *pointer; // declare variable
void foo()
{
if(pointer != NULL) // OK, we use the pointer only
if(pointer->x == 0) // invalid use - struct contents unknown yet
return;
}
struct node { // supply a definition
int x;
};
void bar()
{
if(pointer != NULL)
if(pointer->x == 0) // OK - struct contents already known
return;
}
Here pointerToNextNode is the type of struct node
No, it's not. It's of type struct node *
struct node* pointerToNextNode; allocates memory for a pointer variable of type struct node.
It does not allocate memory for struct node, so, till point, it does not need to know about the size and representation of struct node. Only the (data)type name is sufficient.
Also, it's worthy to mention, without a typedef in place, node* pointerToNextNode; should not be valid. It should be written like below
typedef struct node node;
struct node
{
int data;
node* pointerToNextNode;
};
BTW, private: is not C thing, if i'm not wrong.
for me this doesn't compile using CC -- and exactly because of what you said.
you would have to use struct node * to make the compiler aware you want memory for a pointer
I'm trying to create an empty linked list, which asks the user for the maximum number of terms that the list can hold. (I didn't add my code for that as its simply a printf). I then have to create a new function which asks the user to insert input into the previously created list.
My question is, how do I make the create_q() function return the empty list?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node_t {
int value;
int priority;
struct node_t *next;
}node;
typedef struct priority_linked_list {
struct name *head;
int current_size;
int max_size;
}priority_list;
typedef node *Node;
typedef priority_list *List;
void create_q(int max_terms) {
node *head = NULL;
node *next = NULL;
List *current_size = 0;
List *max_size = max_terms;
}
In C, linked lists are usually implemented as a series of nodes stored on the heap that point to eachother. The heap is a persistent memory area that runs throughout the life-cycle of the program.
When you create a variable normally in a C function, and the function returns, the variable that you created is no longer accessible. However when you create something on the heap in a function, and the function is returned, the data you allocated on the heap is still there. However, you have no way of accessing it-- unless the function returns a pointer.
So what you would do for create_q() would be to create the linked list on the heap (using a function in stdlib.h called "malloc"), and then you would return a pointer to your first node, letting the main function know where on the heap to find the first node. Then that first node would have a pointer in it, telling the program where on the heap to find the second node, and so forth.
However, you're probably approaching linked lists the wrong way. Unless this is for some sort of homework project, you probably wouldn't want to create an empty linked list. One of the benefits of a linked list is that it's a dynamic structure in which you can easily insert new nodes. You could still have some variable keeping track of the maximum size you want the list to be, but you probably wouldn't want to actually create the nodes until you had to.
Just keep in mind what a linked list is. It's a set of nodes floating on the heap (in C) that each store some data, and contain a pointer to the next node floating on the heap. All you need, to access the linked list, is a pointer to the first node. To add a new node, you simply "walk" through the list till you reach the last node, and then create a new node and have the old-last node point to it.
Is this what you had in mind?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node_t
{
int value;
int priority;
struct node_t *next;
};
static int current_size;
static int max_size;
static struct node_t* head = NULL;
struct node_t* create_q(int);
struct node_t* create_q(int max_terms)
{
int i; // loop counter/index
current_size = max_terms;
max_size = max_terms;
if( NULL == (head = malloc(sizeof(struct node_t)*max_terms)))
{ // then, malloc failed
perror("malloc failed for struct node_t list");
exit( EXIT_FAILURE );
}
// implied else, malloc successful
// set all fields to '0,0,Null'
memset( head, 0x00, sizeof(struct node_t)*max_terms);
// set all next links, except last link
for(i=0;i<(max_terms-1);i++)
{
head[i].next = &head[i+1];
}
// set last link
head[i].next = NULL;
return( head );
} // end function: create_q
I suspect you are looking for something like the following for creating or initializing your priority linked list.
/*****
* alloc_q - allocate memory for the priority linked list
*/
struct priority_linked_list *alloc_q(void)
{
struct priority_linked_list *list;
list = malloc(sizeof(*list));
return list;
}
/******
* init_q - initialize the priority linked list
*/
void init_q(struct priority_linked_list *list, int max_terms)
{
list->head = NULL;
list->current_size = 0;
list->max_size = max_terms;
}
/******
* create_q - allocate AND initialize the priority linked list
*/
struct priority_linked_list *create_q(int max_terms)
{
struct priority_linked_list *list;
list = alloc_q();
if (list == NULL) {
return NULL;
}
init_q(list, max_terms);
return list;
}
Allocation of nodes and their addition/removal to/from the list would be handled separately.
There may be typos in the above (I have not tested it). However, it should be enough to get you on the path you want.
Hope it helps.