I have written some code creating a singly linked list and then converting it to a dynamic array in C.
The code works just fine if I only create a global variable for the list header. If I want to create the list in my main function, however, I always get a segmentation fault.
The code below works just fine as soon as I create a global list variable instead and remove the list as parameter from all functions.
Can anyone tell me why this won't work if I want to pass the list as a parameter to the function and thus be able to create multiple lists?
#include <stdlib.h>
#include <stdio.h>
typedef struct NodeStruct* Node;
typedef struct NodeStruct {
Node next;
int val;
} NodeStruct;
typedef Node List;
Node newNode(int x){
Node n = (Node)malloc(sizeof(NodeStruct));
if(n!=NULL){
n->val = x;
n->next = NULL;
return n;
}
else{
printf("ERROR: Could not allocate memory!\n");
}
exit(1);
}
void prepend(List l, Node node){
if (l == NULL) l = node;
else{
node->next = l;
l = node;
}
}
void printList(List l){
if(l!=NULL){
Node n = l;
while(n->next != NULL){
printf("%d, ", n->val);
n = n->next;
}
printf("%d\n", n->val);
}
else{
printf("ERROR: List empty!\n");
}
}
/*=============================*/
int* arrOf(List l){
if(l==NULL){
printf("ERROR: List empty\n");
exit(1);
}
int size = 0;
Node n = l;
while(n!=NULL){
size++;
n = n->next;
}
int* arr = (int*)malloc((size+1)*sizeof(int));
n = l;
int i = 0;
arr[i++] = size;
while(n != NULL){
arr[i++] = n->val;
n = n->next;
}
printf("Returning Array\n");
return arr;
}
int main(int argc, char *argv[]){
List l;
prepend(l, newNode(5));
prepend(l, newNode(6));
prepend(l, newNode(7));
prepend(l, newNode(8));
prepend(l, newNode(9));
prepend(l, newNode(4));
printList(l);
printf("\n===========================================\n");
int* arr = arrOf(l);
for(int i = 0; i < 10; ++i){
printf("%d, ", arr[i]);
}
return 0;
}
When you initialize List l in main, you are not assigning a default value. It is stored on the stack and not initialized. This means the value is undefined and not necessarily null.
When you are creating List l globally, the variable is stored in the bss segment and initialized with null.
Change your declaration of List l to:
List l = NULL;
This function
void prepend(List l, Node node){
if (l == NULL) l = node;
else{
node->next = l;
l = node;
}
}
deals with a copy of the value of the pointer l declared in main
List l;
that moreover was not initialized.
So changing of the copy in these statements within the function
if (l == NULL) l = node;
//...
l = node;
does not influence on the original value of the pointer declared in main.
You have to write at least like
void prepend(List *l, Node node){
node->next = *l;
*l = node;
}
and in main
List l = NULL;
The function can be called like
prepend( &l, newNode(5) );
That is the pointer to the head node must be passed to the function by reference.
Also you need to free all the dynamically allocated memory for the list and the array.
Related
i'm working on a simple doubly linked list implementation in c, i've created my structures as follows.
typdef struct node{
void *data;
struct node *next, *prev;
}node;
typedef struct list{
struct node *head, *tail;
size_t size;
}list;
I'm inserting elements in my linked list using this function and everything seems to work fine. Let's
assume i'm filling my list with integers calling the function 4 times to insert {2,4,6,8}.
When i execute my print function it correctly returns 2,4,6,8.
void insert_node(list *l, void *elem)
{
node *n = create_node(elem); //here i just create and initialize the new node;
if(l->size == 0){
l->head = n;
l->tail = n;
}else{
l->tail->next = n;
n->prev = l->tail;
l->tail = n;
}
l->size++;
}
The problem rises when i try to test my function with unity, i wrote this simple unit test:
void test_list_insert(){
list *l = list_test(); //this function creates a list and inserts in it {2,4,6,8} as values
TEST_ASSERT_EQUAL_INT(2, *(int*)(get_node_i(l,0))->data);
TEST_ASSERT_EQUAL_INT(4, *(int*)(get_node_i(l,1))->data); //problem seems to be here..
TEST_ASSERT_EQUAL_INT(6, *(int*)(get_node_i(l,2))->data);
TEST_ASSERT_EQUAL_INT(8, *(int*)(get_node_i(l,3))->data);
}
When i execute my unit test i get this output:
test.c:73:test_list_insert:FAIL Expected 4 was 1
At this point the problem seems related to the 'get_node_i' function
which is used to retrieve the element in the i-th position of the list... here's the function:
node *get_node_i(list *l, int pos){
if(pos > l->size || pos < 0){
return NULL;
}
node *curr = l->head;
int currPos = 0;
if(pos == 0) return curr;
while(curr != NULL){
if(currPos == pos){
return curr;
}
currPos++;
curr = curr->next;
}
return NULL;
}
I've tried to execute my print function inside the unit test and i discovered that it prints correctly just the first two nodes (2,4) and for the other nodes it prints pointers... That for me is quite strange as if i try to execute the print function in any other part of my code it returns the list correctly..
Here's how i create lists and nodes
//create new node
node* create_node(void * elem){
node *n = (node *)malloc(sizeof (node));
n->data = elem;
n->next = NULL;
n->prev = NULL;
return n;
}
//create an empty list
list *create_list(){
list *l = (list *)malloc(sizeof(list));
l->size = 0;
l->head = NULL;
l->tail = NULL;
return l;
}
Here's the list_test function and the print function,
list* list_test(){
list *l = create_list();
int a = 2;
int b = 4;
int c = 6;
int d = 8;
insert_node(l, &a);
insert_node(l, &b);
insert_node(l, &c);
insert_node(l, &d);
return l;
}
//print the list
void print_list(list *l){
node *tmp = l->head;
while(tmp != NULL){
printf("%d\t" , *(int *)tmp->data);
tmp = tmp->next;
}
}
if something else needs to be clarified, let me know, thanks.
In your function list_test you insert the address of local variables. So node->data is assigned the address of a local variable. When the function returns, the data pointed by these address will change.
The function list_test should be something like the following:
list* list_test(){
list *l = create_list();
int a = 2, *ap = malloc(sizeof(int));
int b = 4, *bp = malloc(sizeof(int));
int c = 6, *cp = malloc(sizeof(int));
int d = 8, *dp = malloc(sizeof(int));
*ap = a;
*bp = b;
*cp = c;
*dp = d;
insert_node(l, ap);
insert_node(l, bp);
insert_node(l, cp);
insert_node(l, dp);
return l;
}
I am learning singly-linked lists in C and trying to link components of an array. I have written a few lines of code but it is not giving required results i-e making and printing linked list from array. Can someone please explain why it is not working? Thanks
#include <stdio.h>
#include <stdlib.h>
typedef struct list
{
int data;
struct list *next;
}
list;
list *createlinkedlist(int *arr);
void printlist(list * head);
int main(void)
{
int arr[]={1,2,3,4,5};
list *head=NULL;
head = createlinkedlist(arr);
printlist(head);
}
list *createlinkedlist(int *arr)
{
list *head=NULL;
list *temp=NULL;
list *p=NULL;
for (int j=0, O=sizeof(arr); j<O; j++)
{
temp= (list*)malloc(sizeof(list));
temp->next = NULL;
if(head == NULL)
head=temp;
else
{
p=head;
while(p->next!=NULL)
{
p=p->next;
}
p->next = temp;
}
}
return head;
}
void printlist(list *head)
{
list * p = head;
while (p !=NULL)
{
printf("%d\n", p->data);
p = p->next;
}
}
Two problems,
Array passed to function decays to pointer.
for (int j=0, O=sizeof(arr); j<O; j++)
Here you are looping till sizeof pointer not till size of actual array.
Pass the array size from main itself.
list *createlinkedlist(int *arr, int length); //prototype becomes
head = createlinkedlist(arr, sizeof (arr)); // function call becomes
for (int j=0; j<length; j++) //for loop becomes
You are not storing array contents into linked list.
temp= (list*)malloc(sizeof(list));
temp->data = arr[j]; //store the content into list
temp->next = NULL;
#include <stdio.h>
#include <stdlib.h>
typedef struct list
{
int data;
struct list* next;
}
list;
list* createlinkedlist(int* arr, int length);
void printlist(list* head);
void deleteList(list* _list, int length);
int main(void)
{
int arr[] = { 1,2,3,4,5 };
list* head = NULL;
head = createlinkedlist(arr, 5);
// Result is '1\n,2\n,3\n,4\n,5\n'
printlist(head);
deleteList(head, 5);
// Below value is garbage
printf("%p\n", head->next);
}
void deleteList(list* p, int length)
{
list** nodeArr = (list **)malloc(sizeof(list*) * length);
for (int i = 0; p != NULL; i++, p = p->next)
{
nodeArr[i] = p;
}
for (int i = 0; i <= sizeof(nodeArr); ++i)
{
free(nodeArr[i]);
}
free(nodeArr);
}
list* createlinkedlist(int* arr, int length)
{
list* head = NULL;
list* temp = NULL;
list* p = NULL;
// repeat until j == length
for (int j = 0; j < length; j++)
{
temp = (list*) malloc(sizeof(list));
// assign value of arr[j]
temp->data = arr[j];
temp->next = NULL;
if (head == NULL)
head = temp;
else
{
p = head;
while (p->next != NULL)
{
p = p->next;
}
p->next = temp;
}
}
return head;
}
void printlist(list* head)
{
list* p = head;
while (p != NULL)
{
printf("%d\n", p->data);
p = p->next;
}
}
First, You have not assigned the value of the array into the list.
Second, While Statement must repeat until length of arr, and you have not passed the length of arr.
('arr' is int pointer pointing to the first element (address of 1) of an array. and, sizeof(arr) is 'int pointer size', not length of arr.)
So, you need to put the length in the second argument of 'createdlinkedlist'.
If you fix it like the code above, it works.
To add that, You must call 'free' function to return used memory after using heap memory.
(Namely after using malloc)
In this case, you could define 'deleteList' function to free all the 'next' in the list.
Or, If you can use c++, you can define destructor in the list
typedef struct list
{
int data;
struct list* next;
~list (){
delete next;
}
}
list;
Calling delete of the head of the list calls a series of delete call chain.
In this case, you must use 'delete' keyword instead of 'free' function
As the title says I need to write a function which fill a list with int typed by the user, and later on print them, but i'm having troubles with the insert function, which does not actually put the values typed in the list. Here's the code:
the typedefs:
typedef struct list_element {
int value;
struct list_element *next;
} item;
typedef item *list;
and the functions:
list lins(list l)
{
int i;
list root = NULL;
printf("inserire dati ('0' per terminare):\n");
do
{
scanf("%d", &i);
l = (list)malloc(sizeof(item));
l->value = i;
l->next = root;
root = l;
} while (i != 0);
return l;
}
void showlist(list l)
{
printf("lista completa:\n");
while (l != NULL)
{
printf("%d ", l->value);
l = l->next;
}
printf("\n");
}
Sorry if my code is poorly written but I'm having a hard time understanding the concept of lists.
Edit: added functions calls
main()
{
lins(l);
showlist(l);
}
Edit 2: here's the output of the code:
output
Edit 3: Here's the sample of code my professor give us to work with lists:
http://www.mediafire.com/file/wj152pw1ojkxf1j/10a_-Liste-_2018.pdf
Your insertion function inserts in reverse order. That is because you assign root to l->next and l to root. Also the number 0 is included in the list when the user tries to end the insertion process.
In main(), you don't seem to assign the return value of the function lins() to a variable, and if you passed l declared as List l = NULL; to the function lins(), then a copy of it will be used, and so, the original variable won't be altered. What you really need is something like:
#include <stdio.h>
#include <stdlib.h>
typedef struct list_element {
int value;
struct list_element *next;
} item;
typedef item *list;
list lins(void)
{
list node = NULL;
list root = NULL;
list tail = NULL;
printf("inserire dati ('0' per terminare):\n");
int i;
scanf("%d", &i);
while(i != 0)
{
node = (list)malloc(sizeof(item));
node->value = i;
node->next = NULL;
if (!root)
root = node;
else
tail->next = node;
tail = node;
scanf("%d", &i);
}
return root;
}
void showlist(list l)
{
printf("lista completa:\n");
while (l != NULL)
{
printf("%d ", l->value);
l = l->next;
}
printf("\n");
}
int main(void)
{
list head = lins();
showlist(head);
system("pause");
return 0;
}
Of course, I should point out that you should free the list once you are done with it.
First of, I see no point in passing item *l as an argument to lins function.
The root or better, head of the list should not be changed once you assign something to it, unless you want to delete the list.
void lins(item **head){
item *new_node = malloc(sizeof(item));
int i;
if(!new_node){
printf("Memory allocation failed!\n");
exit(1);
}
scanf("%d", &i);
new_node->value = i;
new_node->next = NULL;
node *temp = *head;
if(!temp)
*head = new_node;
else{
while (temp->next != NULL){
temp = temp->next;
}
temp->next = new_node;
}
return ;
}
After you write lins like this, showlist can look as follow:
void showlist(item *head){
printf("List is: \n");
do{
printf("%d", head->value);
head=head->next;
}while(head!=NULL);
}
As for the main function you need to declare the head first.
int main(){
item *head = NULL;
lins(&head);
showlist(head);
return 0;
}
more detailed explanation to follow...
So from what I understand, you want to prepend to your linked-list. I will try to use your typedefs, though many comments have given better options to use, you could change the implementation later.
Realise that lins(list l) is never utilising the value of the parameter l passed to it. That is overriden by the malloc. It is prepending elements to the list, and finally returns the new head of your list. That new head has to be passed to showlist() for printing. What you might be doing is initialising one element of the list in main, and passing that to lins and showlist. lins doesnt bother with the parameter and returns a completely new list, but when you pass that old list to showlist it is interpreted as an empty list.
So you can simply change usage of lins to be used as a creator of linked-lists.
So declaring list lins() {...} and using it in main() like this should work:
int main() {
list l;
l = lins();
showlist(l);
return 0;
}
struct list_element {
int value;
struct list_element *next;};
typedef struct list_element * list;
void lins(list *l){
list tmp = NULL;
list last = *l;
int i;
if (last){
while(last->next){ // go to last child of list
last = last->next;
}
}else{
last = (list)malloc(sizeof(struct list_element));
}
printf("inserire dati ('0' per terminare):\n");
do
{
scanf("%d", &i);
last->value = i;
last->next = (list)malloc(sizeof(struct list_element));
last = last->next;
} while (i != 0);}
void show(list li){
list tmp = li;
if(li){
while(tmp){
printf("%d at %p\n",tmp->value, tmp);
tmp = tmp->next;
}
}}
int main(){
list a = (list)malloc(sizeof(struct list_element));
lins(&a);
show(a);
return 0;}
I'm getting assignment makes pointer from integer without a cast errors on lines 46 and 53, the two lines with double asterisks on either side, and for the life of me, I cannot figure out why. Linked lists are very new to me, I don't know how they work completely yet.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct node_def
{
int data;
struct node_def *next;
};
typedef struct node_def node;
node *makeNode (int a);
node *insertFront(node *head,node *new);
void printList(node *head);
int numNodes = 0;
int main()
{
srand(time(0));
int r = rand() % 10000;
int i = 0;
node *head = NULL;
node *tmp = NULL;
printf("How many nodes? ", numNodes);
scanf("%d", numNodes);
printf("\n");
head = insertFront(head, tmp);
for(i = 0; i < numNodes; i++)
{
makeNode(r);
printList(head);
}
printf("\n");
return 0;
}
node *makeNode (int a)
{
node *new = malloc(sizeof(node));
**new = a;**
return new;
}
node *insertFront(node *head, node *new)
{
**new->data = head;**
new->next = new;
return 0;
}
void printList(node *head)
{
int j = 0;
for(j = 0; j < numNodes; ++j)
{
while (head != NULL)
{
printf(" %4d", head->data);
head = head->next;
}
if(j % 10 == 0)
printf("\n");
}
return;
}
new = a is meant to make new nodes and assign them a random number from 0 - 9999.
You try to assign r to new, but new is a struct.
You make a pointer to struct : node *new
What you want to do is assigning r to new->data, which is an int.
node *insertFront(node *head, node *new)
{
**new->data = head;** // ** is meaningless
new->next = new; // new is a reserved key word, don't use it this way
return 0;
}
What you try to do is to put a NULL pointer as the head of your list.
Just push element into it within your makeNode function.
insert like this :
void createNode(node *head)
{
Node *new_node = malloc(sizeof(Node*));
new_node->data = rand() % 100000;
new_node->next = NULL;
if(head == NULL)
head = new_node;
else if(head != NULL)
//Here you have to adapt your list, search (linked list crud functions)
}
You have a bad understanding about what pointers are.
Hope it helps bro
I've just tried to implement a recursive linked list append in C, and for some reason l keeps being NULL no matter what I do, even though I malloc when encountering a NULL value.
The following code prints nothing. Any ideas?
#include <stdlib.h>
#include <stdio.h>
typedef struct node {
unsigned v;
struct node* next;
} node;
void insert(unsigned x, node* l) {
if (l == NULL){
node* new_node = (node*)malloc(sizeof(node));
new_node->v = x;
new_node->next = NULL;
l = new_node;
}
else {
insert(x, l->next);
}
}
void print(node *l) {
if (l == NULL) return;
printf("%d\n", l->v);
print(l->next);
}
int main(){
node* l = NULL;
insert(1, l);
insert(2, l);
print(l);
return 0;
}
Help much appreciated.
EDIT: Even if I initialize it, it's still the same.
#include <stdlib.h>
#include <stdio.h>
typedef struct node {
unsigned v;
struct node* next;
} node;
node* insert(unsigned x, node** ll) {
if (*ll == NULL){
*ll = (node*)malloc(sizeof(node));
(*ll)->v = x;
(*ll)->next = NULL;
}
else {
insert(x, &(*ll)->next);
}
}
void print(node *l) {if (l == NULL) return;
printf("%d\n", l->v);
print(l->next);
}
int main(){
node* l = NULL;
insert(1, &l);
insert(2, &l);
print(l);
return 0;
}
compiled with no gcc no switches
output:
1
2
First off, you're passing l to your function by value so you won't see any changes made to it. Currently, when you set l to new_node, you only change the local value of l in the method insert. You may want to modify your function to return l and set l in your main to the return value of this function.
node *insert(int x, node *l){
//.... your method
return l;
}
In main:
node *l = NULL;
l = insert(1, l);
l = insert(2, l);
Second, your recursive call will not append nodes to your LL for the same reason. Change that call to this:
l->next = insert(x, l);