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;
}
Related
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 created a new struct that represents a linked list and two functions listDestroy and arr2list. The second function gets a generic array and converts it into a list. The code:
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(List* list, void freeElement(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
if (length == 0 || !copyElement || !freeElement) {
return NULL;
}
struct List* head = (struct List*) malloc(sizeof(struct List));
if (head == NULL) {
return NULL;
}
List* current_node = head;
for(int i = 0; i < length; i++) {
current_node->value = copyElement(array[i]);
struct List* new_node = (struct List*) malloc(sizeof(struct List));
if (new_node == NULL) {
listDestroy(head, freeElement);
return NULL;
}
current_node->next = new_node;
current_node = new_node;
}
return head;
}
I think that I have a problem with the copyElement(array[i]);. I want to pass a generic array of elements to arr2list but I'm not sure if void* array[] is the right way. If I change it to be void* array I get an error for array[i]. What is the right way to make it work? Is it possible to also show a working example?
The last node of the list ends up with a NULL next and a garbled value. I don't think this is what you wanted. Try this loop:
struct List* head = NULL;
struct List** tail = &head;
for(int i = 0; i < length; i++) {
*tail = malloc(sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = copyElement(array[i]);
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
This uses a pointer to pointer so that we can update head or next depending on where we are in the loop without an extra if condition. Note that the allocaction of head is inside the loop now, so we always allocate exactly as many nodes as we need.
void* array[] is completely valid in this scenario, although I don't see the point of copyElement.
Perhaps just remove it and use array[i] instead?
I'd also like to point out a few mistakes that you may want to fix in your code:
Don't cast the result of malloc and use sizeof(*var) instead of sizeof(type). They're unneeded and may cause issues later on if you change the type of head. So, change this (and any later occurrences):
struct List* head = (struct List*) malloc(sizeof(struct List));
to this:
struct List* head = malloc(sizeof(*head));
Consider returning struct List * from arr2list. Change this:
void* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
to this:
struct List* arr2list(void* array[], int length, void* copyElement(void*), void freeElement(void*)) {
Also, use either struct List * or List *. Inconsistencies may make it hard to understand your code.
It may be clearer if you pass function pointers to your functions instead of just functions. So, instead of doing this:
returntype func(params),
do this:
returntype (*func)(params),
You may also want to change malloc calls to calloc calls. calloc zeroes out memory, which can help in debugging. Change:
malloc(...)
to:
calloc(1, ...)
Here's an example combining code fixes from Joshua's post and mine:
list.c:
#include <stdlib.h>
typedef struct List {
struct List* next;
void *value;
} List;
void listDestroy(struct List* list, void (*freeElement)(void*)) {
while(list != NULL) {
freeElement(list->value);
struct List* temp_node = list;
list = list->next;
free(temp_node);
}
}
struct List* arr2list(void* array[], int length, void (*freeElement)(void*)) {
struct List* head = NULL;
struct List** tail = &head;
if (length == 0 || !freeElement) {
return NULL;
}
for(int i = 0; i < length; i++) {
*tail = calloc(1, sizeof(struct List));
if (*tail == NULL) {
listDestroy(head, freeElement);
return NULL;
}
tail[0]->value = array[i];
tail = &(tail[0]->next);
}
*tail = NULL;
return head;
}
test.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.c"
void free_element(void *el)
{
free(el);
}
int main(void)
{
List *list;
int ctr;
void *array[4];
for(ctr = 0; ctr < 4; ctr++)
{
/* Don't usually pass sizeof(type) to malloc(),
* but these are extenuating circumstances. */
array[ctr] = malloc(sizeof(int));
if(!array[ctr]) return 1;
*(int *)array[ctr] = ctr * 4;
}
list = arr2list(array, sizeof(array)/sizeof(array[0]), free_element);
while(list)
{
printf("%d\n", *(int *)list->value);
list = list->next;
}
listDestroy(list, free_element);
return 0;
}
Output:
0
4
8
12
One last note: you may consider creating a header file that defines these structures and functions (and remove the structure from list.c). Here's an example:
#ifndef LIST_H
#define LIST_H 1
typedef struct List { // Remove this from list.c
struct List* next;
void *value;
} List;
void listDestroy(struct List*, void (*)(void*));
struct List* arr2list(void* [], int, void (*)(void*));
#endif
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node, *LinkedList;
void CreateList(LinkedList N, int n)
{
N = (LinkedList)malloc(sizeof(Node));
N->next = NULL;
LinkedList new = N;
Node *p;
for (int i = 0; i < n; ++i) {
p = (Node *)malloc(sizeof(Node));
scanf("%d", &(p->data));
new->next = p;
new = p;
}
new->next = NULL;
}
int main()
{
LinkedList list;
CreateList(list, 20);
printf("%d", list->data);
return 0;
}
As you can see, I want to create a linkedlist and make it a function.
But when I "printf" linkedlist's data, it can't appear what i want.
Can you help me?
The direct problem, as M. Oehm notes, is that you pass the list object to the create function. The create function creates the list, but because the list object is not returned to main, main cannot see the list. To achieve what you want, do:
In main, declare the list as:
LinkedList *N; // a pointer
declare create as:
void CreateList(LinkedList **N, int n) // address of a pointer that receives the value
and dereference it in create:
*N = malloc(sizeof(Node)); // assign the value to the pointer in main
and now call it from main as:
CreateList(&N, 20); // pass the address of the pointer
I further note that you pass create an int, the number of elements in the list, but a list is typically made for an unknown number of elements. So you should read until end-of-file.
(All other required modifications in create I leave to you.)
Thank you all!! I solved this problem, and this is my code.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int data;
struct Node* next;
} Node;
void create(Node* *head, int n)
{
*head = malloc(sizeof(Node));
(*head)->next = NULL;
Node* new = *head;
Node* p;
for (int i = 0; i < n; ++i) {
p = malloc(sizeof(Node));
scanf("%d", &(p->data));
new->next = p;
new = p;
}
}
int main()
{
Node* list;
create(&list,20);
printf("%d", ((list->next)->next)->data); //for test
return 0;
}
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int value;
struct node* next;
} node;
void print(node* list);
int main()
{
node* n1;
node* n2;
n1 = (node *) malloc(sizeof(node));
n2 = (node *) malloc(sizeof(node));
n1->value = 4;
n1->next = n2;
n2->value = 5;
n2->next = NULL;
print(n1);
return 0;
}
void print(node* list)
{
node* p;
p = list;
while (p != NULL)
{
printf("%d ", p->value);
p = p->next;
}
}
The code works but my compiler (gcc) gives a warning that n1->next = n2 is (assignment from incompatible pointer type)
What does it mean? and how do I avoid it?
typedef struct {...} node declares node to be a type alias for a struct without a tag. In C, two otherwise identical structs with different tags are not the same structure. (Furthermore, two declarations of structs without tags are different structs.) The declaration does not declare struct node at all. So struct node* next; refers to a different, incomplete struct. (It's ok that its incomplete, because you only use it as a pointer.)
Here's a a better way of doing it. (Changing node to Node is just my style; I find it easier when type names are easily distinguishable from variable names.) Note the predeclaration of the typedef, which allows its use inside the later struct definition. (It's still incomplete when its used inside the definition, but that's OK because it's a pointer.)
I also changed the malloc calls to use the type of the variable being defined rather than the typename, which is generally better style. (And I removed the unnecessary casts; if you plan to use C++, you should change the malloc to a new rather than adding a C-style cast.)
#include <stdio.h>
#include <stdlib.h>
typedef struct Node Node;
struct Node {
int value;
Node* next;
};
void print(Node* list);
int main()
{
Node* n1 = malloc(sizeof *n1);
Node* n2 = malloc(sizeof *n2);
n1->value = 4;
n1->next = n2;
n2->value = 5;
n2->next = NULL;
print(n1);
return 0;
}
void print(Node* list)
{
Node* p;
p = list;
while (p != NULL)
{
printf("%d ", p->value);
p = p->next;
}
}
(Live on coliru)
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?