I am a C# programmer professionally, but trying to re-learn C. I have been writing a simple linked list in C. I have gotten it working fine when the head-node is defined in main(). But now I want to try and initialize the head-node in a function "initializeHead()".
Here is the Node definition and Main() function:
struct node
{
char value;
struct node * next;
};
int main()
{
struct node * head = NULL;
initializeHead(head, 'a');
return 0;
}
Function that initializes head node:
void initializeHead(struct node * head, char vertexCategory)
{
if (head == NULL)
{
head = malloc(sizeof(struct node));
head->value = vertexCategory;
head->next = NULL;
}
else
{
printf("\nError: Head already initialized!");
}
}
...After calling initializeHead(), it doesn't seem like anything has happened because head is still NULL.
How can this be accomplished?
The term method is not a normative term in C and C++. Use the term function instead (or member function in C++).
According to the C Standard the function main without parameters shall be declared like
int main( void )
In fact the head is already initialized in the declaration
struct node * head = NULL;
You can check for example whether a list is empty by using comparison
if ( head == NULL ) { /* ...*/ }
What you are trying to do using the function is to append a value to a list. So the function name initializeHead just confuses readers.
You can use instead either push, or push_front or some other suitable name.
The function shall be declared before its usage.
Arguments are passed to functions by values in C. The term passing by reference means in C to pass a pointer to the original object. Otherwise a function will deal with a copy of the original object.
You can imagine your function definition and its call the following way (for clarity I renamed the parameter name)
initializeHead(head, 'a');
//...
void initializeHead( /*struct node * list, char vertexCategory */ )
{
struct node *list = head;
char vertexCategory = 'a';
//...
That is function parameters are its local variables that are initialized by expressions used as arguments. So any changes of a parameter do not influence on the original argument. As it was mentioned above if you want to change an original object you have to pass it by reference that is indirectly through a pointer.
Also you should free all allocated memory by the list when the list is not used any more in the program to escape memory leaks.
The function should not issue a message . It is better if it returns a code of success or failure.
For example a function that pushes a value in a singly-linked list can look the following way
int push_front( struct node **head, char value )
{
struct node *new_node = malloc( sizeof( struct node ) );
int success = new_node != NULL;
if ( success )
{
new_node->value = value;
new_node->next = *head;
*head = new_node;
}
return success;
}
Pay attention to the first parameter declaration struct node **head. As the original head of the list has to be changed in the function then it is passed to the function by reference that is by using a pointer to it.
The function can be called like
push_front( &head, 'a' );
Related
I am writing the program for single-linked-list in 'c' in two ways(They differ in the way memory is being allocated for structure).
1.
struct SingleLinkedList
{
int data;
struct SingleLinkedList* next;
};
typedef struct SingleLinkedList sll;
sll* createNode()
{
sll* node = (sll*) malloc(sizeof(sll));
node -> next = NULL;
return node;
}
2.
struct SingleLinkedList
{
int data;
struct SingleLinkedList* next;
};
typedef struct SingleLinkedList sll;
sll createNode()
{
sll node;
node.next = NULL;
return node;
}
I want to know is the way second program is written, is correct or not?
If incorrect, why is this so?
If correct, why can I not find a program like this in the internet?
Your first program returns a pointer to the (allocated) structure. The caller of createNode now has the responsibility of free()ing its memory before the pointer goes out of scope, and the benefit of the node existing until it is thusly free()d.
Your second program returns a structure, by value, without having "allocated" memory at all. As a matter of fact, the structure node created inside the createNode function ceases to exist as the function returns; the caller of the function gets a copy of that (local) structure. (Although most compilers will optimize that to nothing.)
You don't see the second type too often because:
1) it is really a redundant function call; instead of...
ssl node = createNode();
...just call...
ssl node = { 0, NULL };
2) That node would, again, only exist until the end of the current scope. If you build a linked list like that in function initList(), which e.g. returns a pointer to the first node in that list, as soon as initList() returns all those nodes would go out of scope, and your pointer would point at nothing. Well, not allocated node structures, in any case. ;-) And if you initialize those nodes in a loop, each individual node will go out of scope at the end of its loop iteration... all this is very likely not what you want. ;-)
For starters the both functions should be declared with a parameter the value of which is used to initialize the data member data of the created node.
For example the functions can be defined the following way
sll * createNode( int data )
{
sll *node = malloc( sizeof( sll ) );
if ( node != NULL )
{
node->next = NULL;
node->data = data;
}
return node;
}
and
sll createNode( int data )
{
sll node = { data, NULL };
return node;
}
The both code snippets are correct. Whether your program will be incorrect depends on whether you will correctly use the functions.
For example the second function can be used in the following context (appending a new node to the tail of the list):
int append( sll **head, int data )
{
while ( *head != NULL )
{
head = &( *head )->next;
}
*head = malloc( sizeof( sll ) );
if ( *head ) **head = createNode( data );
return *head != NULL;
}
The only drawback of the second code snippet is that in most cases it is better to combine in one function a node allocation and its initialization in one function instead of splitting these two operations as it is done in the second code snippet.
However sometimes it is make sense to place the initialization itself in a separate function because the initialization can be enough compound. This will make the code in whole more readable.
By the way in C++ this is done exactly in this way due to using constructors. That is it is the constructor (separate function) that is responsible for the initialization.
So you may consider this function
sll createNode( int data )
{
sll node = { data, NULL };
return node;
}
as a constructor of an object of the type sll.
So the purposes of the functions from the presented two code snippets are different. The first one dynamically allocates a node. And the second one is used to initialize an already existent node.
As most beginners in C, I'm implementing a simple linked list.
Each node for the list is defined as so:
typedef struct list_node {
void * data;
struct list_node * next;
} list_node_t;
I made a test program to create and iterate a list. Creation and insertion operations work correctly. However, the code below is giving me problems:
list_node_t * node = NULL;
list_iter_reset(list, node);
if (node == NULL) {
printf("Node is NULL.\n");
} else {
printf("Node is not NULL.\n");
}
fflush(stdout);
The function list_iter_reset() is defined below. Please note that list->head does not point to NULL, as I have inserted nodes in the list previously.
void list_iter_reset(list_t list, list_node_t * node)
{
node = list->head;
if (node == NULL) {
printf("Node is NULL.\n");
} else {
printf("Node is not NULL.\n");
}
fflush(stdout);
}
The output from executing that code is as follows:
Node is not NULL.
Node is NULL.
Since I'm passing a pointer to the node to the function, why is the created node in the test program still pointing to NULL after that function call?
I'm guessing a simple pointer arithmetic aspect went over my head here. I've been looking around and could not find a similar issue.
Thank you in advance.
The function is modifying the value of the pointer, but that never gets back to the caller. It seems you want to be passing a pointer to pointer (list_node_t**) to the function, not a regular pointer.
void list_iter_reset(list_t list, list_node_t** node)
{
*node = list->head;
...
}
The reasoning for this is that while a pointer is all you need to change the value of the thing it's pointing to, here you are trying to change the value of the pointer itself, i.e. where this pointer is pointing to.
As a comparison, imagine you would be passing an int to the function and expecting the function to modify that int. You would of course have to pass an int*, right? This is the same thing, except replace int with node*, and so you need to pass a pointer to that type, which in this case is node**
Assuming the relevant header files, functions for Singly Linked List in C are declared.
Is the following definition of Delete() correct?
/* The Structure for SLL
typedef struct SLL
{
int data;
struct SLL *next;
}node;
Function Delete() deletes a node*/
void Delete( node **head)
{
node *temp, *prev;
int key;
temp = *head;
if(temp == NULL)
{
printf("\nThe list is empty");
return;
}
clrscr();
printf("\nEnter the element you want to delete:");
scanf("%d", &key);
temp = search( *head , key);//search()returns the node which has key
if(temp != NULL)
{
prev = get_prev(*head, key);
if(prev != NULL)
{
prev->next = temp->next;
free(temp);
}
else
{
*head = temp->next;
free(temp);
}
printf("\nThe node is deleted");
getch();
}
}
1) What happens if I replace(node ** head) with (node *head)?
2) What happens if I replace void Delete (node **head) with node
*Delete(node *head)?
3) Is there an alternate way to delete a node in C?
Thanks in advance
This isn't a tutorial site, but here goes...
You do know that arguments in C are passed by value? Meaning the value is copied.
For example:
void some_function(int a)
{
// ...
}
When calling the function above, like
int x = 5;
some_function(x);
Then the value in x is copied into the argument a in the function. If the code inside the function assigns to a (e.g. a = 12;) then you only modify the local variable a, the copy. It does not modify the original variable.
Now, if we want the function to modify x, then we must emulate pass by reference, which is done using pointers and the address-of operator:
void some_function(int *a)
{
*a = 12; // Modify where a is pointing
}
Now to call that, we don't create a pointer variable and pass that (though it's possible as well), instead we use the address-of operator & to pass a pointer to the variable:
int x = 5;
some_function(&x); // Pass a pointer to the variable x
The pointer &x will be passed by value (since that's the only way to pass arguments in C), but we don't want to modify the pointer, we want to modify the data where it points.
Now back to your specific function: Your function wants to modify a variable which is a pointer, then how do we emulate pass by reference? By passing a pointer to the pointer.
So if you have
node *head;
// Initialize head, make it point somewhere, etc.
Now since the Delete function needs to modify where head points, we pass a pointer tohead`, a pointer to the pointer:
Delete(&head);
The Delete function of course must accept that type, a pointer to a pointer to node, i.e. node **. It then uses the dereference operator * to get where the pointer is pointing:
*head = temp->next;
1) If you replace node** head with node* head you won't modify the original head pointer. You probably have a head somewhere that marks the beginning of the linked list. When you delete a node, there's a chance that you want to delete head. In that case you need to modify head to point to the next node in the linked list.
*head = temp->next;
free(temp);
This part of your code does exactly that. Here, temp == head. We want head to point to head->next, but if we pass in node* head to the function, the pointer will get modified but the changes will disappear because you're passing the pointer by value. You need to pass in &head which will be of type node ** head if you want the changes to be reflected outside of the function.
2) You will then change the function definition to return a void pointer (which is a placeholder pointer that can be converted to any pointer. Take care to not break any aliasing rules with this. But the problem from (1) remains, although, you could return a modified head, and assign it to the returned value. In that case define the function won't fit well with other cases where the head doesn't need to be modified. So you could return a pointer for head if it's modified or return NULL when it doesnt. It's a slightly messier method of doing things imho, though.
3) Yes, but that depends on the way a linked list is implemented. For the datatype shown here, the basic delete operation is as given.
I am solving a program to delete all the elements in a linked list and i encountered the following problem:
When i used a delete function with return type void, and checked if the start pointer is NULL in the main ,it wasn't and gives me absurd result
Code:
void deletes(struct node *start)
{
struct node *current,*next;
current=start;
while(current!=NULL)
{
next=current->link;
free(current);
start=next;
current=next;
}
start=NULL;
return ;
}
But if i change the return type, it works fine:
struct node *deletes(struct node *start)
{
struct node *current,*next;
current=start;
while(current!=NULL)
{
next=current->link;
free(current);
start=next;
current=next;
}
start=NULL;
return start;
}
Why is the start=NULL working in the first code?
My entire code is here
It's because in the first version you pass the list header by value, meaning the pointer to the head is copied, and you change only the copy in the function. Those changes are not visible after the function returns as no changes are made on the original copy.
Either do as you do in the second version, returning the result, or pass the pointer by reference, meaning you pass the address of the pointer (or a pointer to the pointer) using the address-of operator. Of course this means that you have to change the function as well:
void deletes(struct node **start)
{
struct node *current = *start;
/* Deleting the list... */
*start = NULL;
}
Call it like
struct node *list_head = ...;
deletes(&list_head);
Because in C, function arguments are passed by value. If you write start = NULL; inside a function, it will be ineffective outside of that function (it will only set the start pointer to NULL, which is essentially just a copy of the pointer value passed in, and it's local to the function.).
If you want to modify a function argument, you must pass a pointer to it. So,
void delete(struct node **start)
{
// ... delete ...
*start = NULL;
}
then
delete(&list);
would work.
It is because you should have (struct node **start), which can allow you to pass a pointer to the list so you can modify the list.
Currently you are only passing in a copy of the linked list to the function and therefore aren't changing the value of the actual list just a copy. Hence why when you return the copy you see the results
Im not sure i got the concept of Linked List properly. What im trying to do is to create a linked list which receives the integer 6 as it's first "data". instead i get this access violation error when trying to write in the integer into the first node's data. is there something specific i missed here?
///////////////////////////////
typedef struct List_Node
{
int data;
struct List_Node* next;
}List_Node;
typedef struct List
{
List_Node* head;
}List;
////////////////////////////////
List* create_list();
void print_list(List_Node *x);
void add_to_node(List_Node *a,int val);
////////////////////////////////
void main()
{
List *a = create_list();
List_Node *ind = a->head;
printf("List:\n");
add_to_node(ind,6);
}
void print_list(List_Node *a)
{
while(a != NULL)
{
printf("%d \n",a->data);
a = a->next;
}
return;
}
void add_to_node(List_Node *a,int val)
{
a->data = val;
}
struct List* create_list()
{
struct List* list = (List*) malloc(sizeof(List));
list->head = NULL;
return list;
}
The code is dereferencing a NULL pointer as a->head is NULL:
list->head = NULL; /* inside create_list()` and 'list' returned to ...*/
List_Node *ind = a->head; /* ... inside main(), and then passed to */
add_to_node(ind,6); /* add_to_node() ... */
a->data = val; /* and dereferenced inside add_to_node(). */
Dereferencing a NULL pointer is undefined behaviour. To correct, malloc() memory for a List_Node and assign to a->head. Recommend creating an add_node() function that allocates memory and assigns the new int value to newly malloc()d node.
Do I cast the result of malloc?
As all have pointed out, you are dereferencing a NULL pointer as your list->head contains NULL.
Another thing I should point out is that, you are creating a List. but not any Node. There is no node in the list. You have to allocate memory for a Node and then use it.
So, instead of add_to_node(), you may use a function add_node that will take the list or the head and the value as parameters, create a node(i.e. allocating memory for the node), set the value and add it to the list.
Also, in your case, the structure List is redundant as it contains only one member. instead you can simply use List_node* head.
What you are doing:
In create_list:
Allocating memory for a List pointer.
Setting the list's head to NULL.
In add_to_node:
Setting the specified node pointer's data element to the specified val.
In main:
Creating a List pointer a by calling create_list. This list has a NULL head.
Initializing a List_Node pointer, ind, to point to the created list's head (which is NULL).
Trying to set ind's data element to 6 by calling add_to_node.
This is where your program is causing the access violation exception.
ind = NULL. Therefore NULL->data = undefined behaviour.
What you should be doing:
In create_list:
Allocate memory for a List pointer, say linked_list.
Allocate memory for linked_list's head pointer.
For the linked_list's head, initialize data and the next pointer to 0 and NULL respectively.
In add_to_node:
Do the same thing you're doing now.
In main:
Create a List pointer a by calling create_list. Now, this list will have a valid, initialized NULL head, but with no meaningful data.
Set the list's head data by calling add_to_node(a->head, 6);.
Note: This will only ensure you have a head node in your list. Nowhere are you creating additional nodes.