Segmentation fault when passing double pointer and pointer to function - c

When I do:
t_node *node1;
t_node **head;
void *elem;
int c = 1;
elem = &c;
head = NULL;
node1 = malloc(sizeof(t_node));
node1->elem = elem;
head = &node1;
//add_node(node1,head); //substitute this with line above and it doesn't work
printf("%d\n",*(int*)(*head)->elem); // prints 1 and works fine
BUT WHEN I CREATE A FUNCTION CALLED ADD_NODE IT DOESN'T WORK?!??!?
void add_node(t_node *node1, t_node **head){
head = &node1;
}
this doesn't make any sense to me... why would this cause this to not work? calling the function literally does the same exact code.
EDIT: Keep in mind the signature of the add_node is not under question. it is required of me to have that signature

C is a pass by value language. Your function actually doesn't do anything at all as far as main() is concerned.
Check out this question in the comp.lang.c FAQ.

In the call to the function the parameters have a scope that is only of that function, so your assignment of 'head = &node1' has no affect to variables outside the function.
To affect the variables you passed in, you must pass the address of the variables. Eg:
void add_node(t_node **node1, t_node ***head){
*head = node1;
}
and the call would be:
add_node(&node1, &head);
Note that you must dereference the 'head' pointer in the function so the value at 'head' would be updated with the 'node1' value.

in 'C' varaibles are passed by reference, so to change the value in function call you should pass the pointer to variable.
correct step would be -
void add_node(t_node **node1, t_node ***head){
*head = node1;
}

Related

pointers don't change after i modified it

I'm setting up a struct called Node
typedef struct node{
struct node *left;
struct node *right;
struct node *parent;
}node;
and a function that operate on the nodes:
int test(node *old,node* new){
old->parent->right = new;
new->parent = old->parent;
}
Ok, so i make 3 nodes and set up the relationship between them
node* me =malloc(sizeof(node));
node* me1 = malloc(sizeof(node));
node* me2 = malloc(sizeof(node));
me->right = me1;
me->left = me2;
me1->parent = me;
me2->parent = me;
test(me1,me);
1.However, after test(), me1->parent->right changed while me1 didn't, which is weird because me1 and me1->parent->right point are the same address. I wonder if i make any wrong assumption here?
2.In function test(), if i replace old->parent->right with old only, then after the function call, the node me1 remains the same. Isn't the pointer modified after we do operations on it inside a function,and why in this case it is not?
me, me1, and me2 are local variables inside your outer function (let's assume it was main). These pointers are never modified, so after the call to test, me1 still points to the same node as before, while the pointer me1->parent->right now points to me. So, "me1 and me1->parent->right point are the same address" isn't true anymore!
If you only modify old inside test, you will only modify the parameter old, which is a copy of me1. After test returns, this copy is forgotten, and the modification has no effect. If you want to modify the me1 variable from within test, you will have to pass a pointer to the pointer, i.e. a double pointer:
int test(node **old,node* new){
*old = new;
...
}
and call it as test(&me1,me);.
Also: Please don't name things "new", because if you ever decide to compile the code as C++, this will conflict with the reserved keyword new.
Here is what your test() method does:
int test(node *old,node* new){
old->parent->right = new;
new->parent = old->parent;
}
when you call this:
me->right = me1;
me1->parent = me;
test(me1,me);
These steps happens:
me1's parent is me and me's right is me1. So me's right becomes me again.
me's parent becomes me itself.

What is the correct syntax of Delete(node ) for SLL in C?

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.

Linked list: Initialize Head with function?

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' );

delete a link list in c

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

C pointer pointer, and seg fault

Below is my simple linked list in C. My question is in "headRef = &newNode;" which causes segmentation fault. Then I tried instead "*headRef = newNode;" which resolves the seg fault problem. Though the two lines of code seem to me to work in the same way, why is one causing seg fault and the other one not?
Thanks in advance.
struct node{
int data;
struct node* next;
};
void Push(struct node** headRef, int data){
struct node* newNode = malloc(sizeof(struct node));
if(!newNode) return;
newNode->data = data;
newNode->next = *headRef;
headRef = &newNode;
return;
}
You have a fundamental misunderstanding of reference semantics via pointers. Here's the core example:
// Call site:
T x;
modify(&x); // take address-of at the call site...
// Callee:
void modify(T * p) // ... so the caller takes a pointer...
{
*p = make_T(); // ... and dereferences it.
}
So: Caller takes address-of, callee dereferences the pointer and modifies the object.
In your code this means that you need to say *headRef = newNode; (in our fundamental example, you have T = struct node *). You have it the wrong way round!
newNode is already an address, you've declared it as a pointer: struct node *newNode. With *headRef = newNode you're assigning that address to a similar pointer, a struct node * to a struct node *.
The confusion is that headRef = &newNode appears to be similarly valid, since the types agree: you're assigning to a struct node ** another struct node **.
But this is wrong for two reasons:
You want to change the value of your function argument headRef, a struct node *. You've passed the address of headRef into the function because C is pass-by-value, so to change a variable you'll need it's address. This variable that you want to change is an address, and so you pass a pointer to a pointer, a struct node **: that additional level of indirection is necessary so that you can change the address within the function, and have that change reflected outide the function. And so within the function you need to dereference the variable to get at what you want to change: in your function, you want to change *headRef, not headRef.
Taking the address of newNode is creating an unnecessary level of indirection. The value that you want to assign, as mentioned above, is the address held by newNode, not the address of newNode.
headRef = &newNode is a local assignment, so the assignment is only valid within the scope of Push function. If changes to the headRef should be visible outside the Push you need to do *headRef = newNode. Furthermore, these two are not equivalent. headRef = &newNode assigns the address of a node pointer to a pointer to node pointer while the *headRef = newNode assigns the address of a node to a pointer to a node using indirection.
You're setting headRef to hold the address of a variable that lives on the stack; as soon as your Push() function returns, the stack is no longer valid and you can count on it getting overwritten. This is a sure recipe for a segfault.

Resources