This simple code (adding element to linked list and printing it) works fine
#include <stdio.h>
struct node{
int item;
struct node* next;
};
void print_node (struct node* n){
while (n!= NULL){
printf("%d ", (*n).item);
n = n->next;
}
printf("\n");
}
void append_node(struct node *list, struct node *n){
while(list->next != NULL)
list = list->next;
list->next = n;
}
int main(){
struct node n1, n2;
n1.item = 1;
n1.next = NULL;
n2.item = 2;
n2.next = NULL;
print_node(&n1);
print_node(&n2);
append_node(&n1,&n2);
print_node(&n1);
printf("done\n");
return 0;
}
If instead I define the append_node as following
void append_node(struct node *list, struct node n){
while(list->next != NULL)
list = list->next;
list->next = &n;
}
and call it accordingly in the main (i.e., append_node(&n1, n2) ) I get a segmentation fault when running the program. And I don't understand why :)
When you call append_node(struct node *list, struct node n), the argument n is copied on the function context.
When the function is leave, the context is freed, and the copy n of your data is lost.
You could use your function append_node(struct node *list, struct node n) if you make a copy of n (using malloc) before putting it in linked list.
EDIT
This may help you: What's the difference between passing by reference vs. passing by value?
Related
Im trying to learn doubly linked lists. I used the following to print:
typedef struct Node{
int data;
struct Node* prev;
struct Node* next;
}node;
typedef struct List{
node *head;
}list;
node * createNode(int data) {
node * newNode = (node*)malloc(sizeof(node));
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
_Bool isEmpty(const list *L)
{
if (L->head == NULL)
return 1;
return 0;
}
_Bool insert(list *L, node *N) {
if(isEmpty(L)) {
L->head = N;
}
else{
L->head->prev = N;
N->next = L->head;
L->head = N;
}
if (L->head==N)
return 1;
return 0;
}
void _print(list *L){
node *temp=L->head;
while(temp!=NULL){
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
int main(int argc, char *argv[]){
list *L1=(list *)malloc(sizeof(list));
node *N1=createNode(3);
node *N2=createNode(1);
node *N3=createNode(5);
insert(L1, N3);
insert(L1, N2);
insert(L1, N1);
_print(L1);
}
for reference my list struct only contains a pointer "head" and my node struct contains next, prev and data.
It prints the correct data but goes into infinite loop.
What is the reason ?
The problem is that this line in main:
list *L1=(list *)malloc(sizeof(list));
Allocates memory for the list, but does not initialize it.
Without initialization the value of L1->head can be anything.
And if it happens to be different than 0 (i.e. NULL), insert will interpret it as pointing to a valid node (which it isn't).
The result is undefined behavior (UB), which means anything can happen. It might seem to work, it can crash, or get into an infinite loop etc.
In order to fix it, you need to initialize the list pointed by L1.
You can do it at least in 2 ways:
Replace the call to malloc with calloc, which also zeroes the allocated memory:
list* L1 = (list*)calloc(sizeof(list), 1);
Add an explicit initialization after the malloc:
list* L1 = (list*)malloc(sizeof(list));
L1->head = NULL; /* <--- initialization */
You can also add a function for encapsulating the initialization.
I'm having a trouble in my project, at first I made one linked list and it worked properly but then I had to edit it and make it an array of linked list, but it just stores in a wrong way I guess, here is my code, what's wrong with it?
#include <stdio.h>
#include <stdlib.h>
struct node
{
int coeff;
int power;
struct node* Next;
};
void Insert(int X,int Y, struct node* L, struct node* P)
{
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->coeff = X;
temp->power = Y;
temp->Next = P->Next;
P->Next = temp;
}
void PrintList(struct node* L)
{
struct node* P = L;
printf("%d %d ",P->coeff,P->power);
printf("\n");
P=P->Next;
}
int main()
{
struct node* head[3] ;
for(int q =0 ; q!= 3 ; q++)
{
head[q] = malloc(sizeof(struct node));
}
Insert(1,2,head[0],&head[0]);
Insert(2,3,head[0],&head[0]);
Insert(1,2,head[1],&head[1]);
Insert(2,2,head[1],&head[1]);
for(int i=0 ;i!=3;i++){
PrintList(head[i]);
}
return 0;
}
In a LinkedList there is only 1 head. You have allocated 3 different heads and are trying to add nodes to these heads. So the following answer assumes you intend to have 3 different LinkedLists with each list's head in an array.
The memory from malloc() in this line
head[q] = malloc(sizeof(struct node));
was uninitialized. Using calloc() appeared more prudent here. So,
head[q] = calloc(sizeof(struct node), 1); //Initialize everything to 0
Next, one of the arguments in your Insert() was redundant and also didn't go with your calling code. It is of the signature
void Insert(int ,int , struct node* , struct node*)
but you're invoking it with
void Insert(int ,int , struct node* , struct node**)
Dropping the last argument should be fine, I guess, in this case since you aren't modifying the incoming struct node* pointer but its contents instead. In case you were changing the struct node* to point to something else within the Insert() function (e.g. P = temp; etc.), then passing in a struct node** would have more meaning. So, changing your code to
void Insert(int X,int Y, struct node* P)
{
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->coeff = X;
temp->power = Y;
temp->Next = P->Next;
P->Next = temp;
}
And the calling code to
Insert(2,3,head[0]);
Insert(1,2,head[0]);
Insert(1,2,head[1]);
Insert(2,2,head[1]);
Next, changing your PrintList to actually traverse the LinkedList:
void PrintList(struct node* L)
{
struct node* P = L;
while(P) {
printf("%d %d\n",P->coeff,P->power);
P=P->Next;
}
}
Apart from that, I just added some logging to better clarify the LinkedList being printed.
for(int i=0 ;i!=3;i++){
printf("Printing list %d:\n", i);
PrintList(head[i]);
printf("*****\n");
}
This gives the output:
Printing list 0:
0 0
1 2
2 3
*****
Printing list 1:
0 0
2 2
1 2
*****
Printing list 2:
0 0
*****
Obviously, all the head of the LinkedLists are 0 initialized and hence show up as 0 0. They could be initialized as deemed fit, or could be dropped from the PrintList() function altogether, depending on your program's expectations.
When working on a C project you should always enable compiler warnings. If you do the compiler will issue a warning like
warning: passing argument 4 of ‘Insert’ from incompatible pointer type [-Wincompatible-pointer-types]
This is just the first problem in your code. You also have uninitialized fields in the nodes you allocate in the main function.
Instead of having a function which modifies the list, it is more flexible to define a function which adds a new node to a list and returns the new list. Below is an alternative approach which also uses convenience macro functions for allocating memory and calculating the length of an array. The code also hides the pointer behind a type definition and defines a function which frees a list.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN(array) ((int) (sizeof (array) / sizeof (array)[0]))
#define NEW_ARRAY(pointer, length) \
{ \
(pointer) = malloc(((size_t) length) * sizeof (pointer)[0]); \
if ((pointer) == NULL) { \
fprintf(stderr, "Allocating memory with malloc failed: %s\n", strerror(errno)); \
exit(EXIT_FAILURE); \
} \
}
#define NEW(pointer) NEW_ARRAY((pointer), 1)
typedef struct node *List;
struct node {
int coeff;
int power;
struct node *next;
};
List NewList(int coeff, int power, List next)
{
List node;
NEW(node);
node->coeff = coeff;
node->power = power;
node->next = next;
return node;
}
void FreeList(List list)
{
if (list != NULL) {
FreeList(list->next);
free(list);
}
}
void PrintList(List list)
{
while (list != NULL) {
printf("%d %d\n", list->coeff, list->power);
list = list->next;
}
}
int main(void)
{
List head[3] ;
head[0] = NewList(1, 2, NewList(2, 3, NULL));
head[1] = NewList(1, 2, NewList(2, 2, NULL));
head[2] = NULL;
for (int i = 0; i < LEN(head); i++) {
PrintList(head[i]);
FreeList(head[i]);
}
return 0;
}
This program should delete the N-node in a singly linked list. If i put N = 1 or N = 2 it's ok, the program works. But with N = 0 the output prints infinite nodes with random values (after deleting the node 0). I think the program can't see the new head. Thx for the help!
#include <stdio.h>
#include <stdlib.h>
#define N 0
struct node {
int data;
struct node *next;
};
void printlist(struct node *head){
struct node *current=head;
int i=0;
while (current!=NULL){
printf("node number %d \t : %d\n", i, current->data);
current=current->next;
i++;
}
}
int deletenode(struct node *head,int n){
struct node *current=head;
struct node *previous=head;
int i=0;
while(current!= NULL){
if (n==i && i!=0){
previous->next=current->next;
free(current);
return 1;
}
else if (n==i && i==0){
head=head->next;
free(current);
return 1;
}
i++;
previous=current;
current=current->next;
return 0;
}
printf("error\n");
exit(EXIT_FAILURE);
}
void main(){
struct node *n1=malloc(sizeof(struct node));
struct node *n2=malloc(sizeof(struct node));
struct node *n3=malloc(sizeof(struct node));
struct node *head=n1;
n1->data=5;
n1->next=n2;
n2->data=10;
n2->next=n3;
n3->data=15;
n3->next=NULL;
printf("\n\nbefore\n");
printlist(head);
deletenode(head,N);
printf("\n\nafter\n");
printlist(head);
}
I'm using currentas a temp pointer , because after the head shift on the second node i need a pointer to the old head and use free.
C always passes by value, so changing a parameter has no effect on the caller.
void foo(int i) {
i = 1234; // No effect on caller.
}
void foo(int *p) {
p = NULL; // No effect on caller.
}
If you want to modify a variable (such as the caller's head), you need to pass a pointer to it. (You can still change that to which a pointer references.)
int deletenode(struct node **head, int n) {
...
}
deletenode(&head, N);
Now, you could simply replace every instance of head in your code with (*head) to account for the new calling convention, but that would waste an opportunity for simplification. By having a pointer to a struct node *, we don't need to handle head (a struct node *) and prev_node->next (a struct node *) differently.
int delete_node_n(struct node **ptr, unsigned n) {
// Make `ptr` point to the pointer we want to modify.
// This will either be the `head` variable
// or the `next` field of some node.
while (1) {
if (!*ptr)
return 0;
if (!n)
break;
ptr = &( (*ptr)->next );
--n;
}
struct node *to_free = *ptr;
*ptr = (*ptr)->next;
free(to_free);
return 1;
}
I have a program that I am supposed to change it from a singly linked list to a doubly linked list. This means that I use pointer that points to the next node and a pointer that points to previous node.
How do I do this while recycling my previous code. Is there a way to do this with minimum steps involved?
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)
//declaring structure
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
}node;
//prototypes
node *create(int n);
void display_recursive(node *n);
int main()
{
int n = 0;
node *head = NULL;
printf("How many entries?\n");
scanf("%d", &n);
//call to create list
head = create(n);
printf("\nThe linked list in order is:\n");
display_recursive(head);
return 0;
}
node *create(int n)
{
node *head = NULL;
node *temp = NULL;
node *p = NULL;
for (int i = 0; i < n; i++)
{
temp = (node*)malloc(sizeof(node));
printf("What is the name of song %d\n", i + 1);
scanf("%s", &temp->songName);
printf("What is the length of song %d (in seconds)?\n", i + 1);
scanf("%d", &temp->songLength);
printf("Is song %d copyrighted?(1 = YES, 0 = NO)\n", i + 1);
scanf("%d", &temp->copyright);
temp->next = NULL;
if (head == NULL)
{
head = temp;
}
else
{
// if not empty, attach new node at the end
p = head;
while (p->next != NULL)
{
p = p->next;
}
p->next = temp;
}
}
return head;
}
void display_recursive(node *n) {
if (!n) {
return;
}
display_recursive(n->next);
printf("Song: %s, ", n->songName);
printf("%d minutes, ",n->songLength);
if (n->copyright == 1)
{
printf("Copyrights\n");
}
else if (n->copyright == 0)
{
printf("No copyrights\n");
}
}
I don't really know how the code should look or what I have to add to achieve a doubly linked list.
You just need a pointer point to previous node
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
struct node* prev;
}node;
just like #T1412 said, you need to add a new member to the structure.
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
struct node* prev;
}node
now you need to modify the create() function so that each node's prev pointer is pointing to previous node, and the HEAD node's prev points to NULL.
Similarly, you need to modify all the linked list related functions to incorporate the prev pointer.
1) strongly suggest changing:
typedef struct node
{
char songName[20];
int songLength;
int copyright;
struct node * next;
}node;
to:
struct NODE
{
char songName[20];
int songLength;
int copyright;
struct NODE * prev;
struct NODE * next;
};
typedef struct NODE node;
Then wherever in the code that it is linking in a new node, add the necessary statement to set the 'prior' field. Remember that the firs node will contain NULL in the 'prior' field.
I need to go through a list linked by the middle of a function with a parameter that is a triple pointer, by means of a recursive void function.
The program is as follows
typedef struct node
{
int data;
struct node* next;
}Node;
void insert(Node** first,int d){
Node* new= createNode(d);
new->next= *first;
*first=new;
}
Node* createNode(int d){
Node* new= (Node*)malloc(sizeof(Node));
new->data= d;
new->next=NULL;
return new;
}
void printList(Node***p)
{
Node**temp = *p;
if(temp == NULL)
return;
else
{
printf("\nValue: %d", (*temp)->data);
*temp = (*temp)->next;
printList(&temp);
}
}
int main()
{
Node *first = NULL;
int n =10;
while(n>0){
insert(&first,n);
n=n-1;
}
Nodo **ptr_first= &first;
printList(&ptr_first);
return 0;
}
The function prints all the values, but the program hangs and returns a negative value. What is wrong with this implementation?
PD: The use of the triple pointer is only for teaching purposes
Your recursion termination condition is wrong.
You have tho change if(temp == NULL) to if(*temp == NULL), since *temp is pointing to the element and not temp.
I also think that it is not good for teaching if you use triple pointers since they are not necessary here.