Add an element to a single linked list - c

typedef struct list
{
struct list * next;
int val;
}*list_t;
list_t add(list_t l,int e)
{
list_t head;
if(l == NULL)
{
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return l;
}
head = l;
while(l != NULL)
l=l->next;
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return head;
}
Sample driver:
int main()
{
list_t ints=NULL;
int i;
for(i=0;i<156;i+=2)
ints = add(ints,i);
while(ints->next != NULL)
{
printf("%d\n",ints->val);
ints=ints->next;
}
system("pause");
return 0;
}
Program works, but "add" function rewinds the list so that the body of main's loop is never achieved.It surprised me a lot, because I thought that I'd been passing list as a value! Could you explain this phenomenom?

The problem is not that the add function rewinds the list, is that it's not working at all: Nowhere in your code are you stating that the previous end of the list should link to the newly added element.
I've modified it slightly:
typedef struct list
{
struct list * next;
int val;
} list_t;
list_t *add(list_t *l,int e)
{
list_t *head;
if(l == NULL)
{
l = malloc(sizeof(list_t));
l->val = e;
l->next = NULL;
return l;
}
head = l;
while(l->next != NULL)
l=l->next;
l->next = malloc(sizeof(list_t));
l=l->next;
l->val = e;
l->next = NULL;
return head;
}
int main()
{
list_t *ints=NULL;
int i;
for(i=0;i<156;i+=2)
ints = add(ints,i);
while(ints->next != NULL)
{
printf("%d\n",ints->val);
ints=ints->next;
}
return 0;
}
The code now works as expected.
Remember that l is a local variable in the add function. Any changes made to l will be lost if it's not allowed to leave the scope of the function somehow (like you do when you return it, inside the first if). Changes made to the variable l points to, using either the * or the -> operators, will be effective to whoever has access to that variable.
I recomend that you start reading on debugging techniques. They vary depending on your environment, and can go from cryptic commandline tools like gdb to full-fledged graphical object browsers and such. This way you will be able to see what happens step by step and monitor memory changes and check what's really being stored in your variables.
EDIT: Fixed pointer trouble as commented. Memory allocations now provide for the whole struct variable, and pointers are no longer used implicitly.

Avoid the special cases. The add() function can do only one thing: allocate a list node and assign its pointer value to the first node in the chain that happens to be null. There is no difference between a NULL node at the head of the chain, in the middle, or at the tail. (of course null nodes cannot exist in the middle of the list. They can exist at the head of the list, but then the list would be empty) Find the first NULL and put the fresh node there.
struct list *add(struct list *lp, int e)
{
struct list **pp;
for (pp= &lp; *pp; pp = &(*pp)->next) {;}
*pp = malloc(sizeof **pp);
(*pp)->val = e;
(*pp)->next = NULL;
return lp;
}

l = malloc(sizeof(list_t));
that allocate a pointer to the struct, not the struct itself.
for example, on a 64 bit machine, the malloced size is 8, but it's supposed to be 16.
when you subsequently say
l->val = ..
l->next = ..
only God knows where you are writing to..
Go search some sample code of linked list, and read it through, I mean in the debugger.

Related

How can i create multiple linked lists in C for same types of data?

struct clist {
int pos;
char* color;
struct clist *next;
};
typedef struct clist sl_clist;
sl_clist *head = NULL;
sl_clist* link[5];
So i am trying to create multiple single linked circular lists and put them into a stack, every list will have the same types of data. In this case i am using the stack as an array. But i just cannot figure out how to create multiple linked lists from single type. I am a student so i am not very experienced on C. Thaks for the help in advance.
void create_list (int N, sl_clist* head){
int i;
sl_clist *new;
sl_clist *old;
if(N == 0){
head = NULL;
}
srand(time(0));
for(i = 0; i < N; i++){
new = (sl_clist*)malloc(sizeof(sl_clist));
if(i == 0){
head = new;
new -> color = color[(rand()%10)];
new -> pos = pos[i];
new -> next = head;
}
else{
new -> color = color[(rand()%10)];
new -> pos = pos[i];
old -> next = new;
new -> next = head;
}
old = new;
}
}
I have also tried creating multiple "head" variables but for some reason when i use them in this function(just imagine there are arrays for color and pos) they always return NULL.
Do not use global variables. Remove them.
sl_clist *head = NULL;
sl_clist* link[5];
Using local varaibles will "force" you to use a modular design that supports multiple lists.
Variables are passed by value:
head = new;
modifies a copy sl_clist* head of the original pointer passed as the argument. The original pointer is unaffected.
There are multiple ways you can solve that problem. You can return the new value:
sl_clist *create_list (int N, sl_clist* head){
...
return new; // or old value
}
int main() {
sl_clist *head = NULL;
head = create_list(5, head);
}
You can take the pointer by reference:
int create_list (int N, sl_clist **head){
...
*head = new; // set new value
(*head)->something = something; // be aware of operator precedence
}
int main() {
sl_clist *head = NULL;
create_list(5, &head); // head is getting modified
}
But I recommend doing a separate type for the head. That way the function is clear - it takes the head, specifically, not any list element. Be verbose:
struct sl_head {
struct clist *head;
};
int create_list(int N, struct sl_head *head) {
// ^^^^^^^^^^^^ - verbose, this is the head, not some element, less mistakces
head->head = new; // a bit more to type
head->head->something = something;
}
int main() {
struct sl_head head = {0}; // no longer a pointer
create_list(5, &head); // head is getting modified
}
Move srand(time(0)); to main(). It's not a function that you call when creating a list.

Pointers to pointers - linked list mess

I'm writing a simple C program to manage a linked list defined as follow:
typedef struct node {
int value;
struct node *next;
} *List;
I reviewed the code and it seems okay but when printing results something is not working well.
My main, with problems on comments:
int main(void) {
List n = list_create(1);
insert(n, 2);
insert(n, 3);
insert(n, 5);
insert(n, 4);
//something here does not work properly. It produces the following output:
//Value: 1
//Value: 2
//Value: 3
//Value: 4
//where is value 5?
print_list(n);
delete(n, 3);
print_list(n);
return 0;
}
I don't know where am I destroying list structure. These are my functions, to debug, if you are too kind.
List list_create(int value) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = NULL;
return new;
}
List new_node(int value, List next_node) {
List new = malloc(sizeof(struct node));
new->value = value;
new->next = next_node;
return new;
}
void print_list(List l) {
List *aux;
for (aux = &l; (*aux) != NULL; aux = &((*aux)->next))
printf("Valor: %d\n", (*aux)->value);
}
void insert(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value > value) {
List tmp = *p;
List new = new_node(value, tmp);
*p = new;
break;
}
*p = new_node(value, NULL);
}
void delete(List l, int value) {
List *p;
for (p = &l; (*p) != NULL; p = &((*p)->next))
if ((*p)->value == value) {
List del = (*p);
(*p) = ((*p)->next);
free(del);
break;
}
}
This code has (at least) two bugs:
The line
if ((*p)->value > value){
means that if you start the list with 1 as the first value and then try to insert 2,3,4..., the body of the 'if' statement never runs, so nothing ever gets inserted.
If you insert a value below the starting value, you have to modify the list pointer itself. However, as #EOF alluded, you are trying to modify a value passed to a function by taking its address. This won't work. &l does not give you the address of the List you passed, it gives you the address of the local copy on insert()'s stack. You are better off modifying the values of first element of the list 'in place'. If you really want to make the List parameter mutable, you'll need to pass it as a List *, and call the function with the address of the list (e.g. insert(&n,2); ) Your delete() function suffers from the same problem - try deleting the first element of the list.
Try this for your insert function:
void insert(List l, int value)
{
List p;
// Find end of list or highest item less than value
for(p = l; p->next != NULL && p->next->value < value; p = p->next);
if (p->value >= value) {
// Over-write p with new value, and insert p as a new one after.
// This saves having to modify l itself.
int tmpval = p->value;
p->value = value;
p->next = new_node(tmpval, p->next);
} else {
// Insert new item after p
p->next = new_node(value, p->next);
}
}
A comment: it is possible the way you are using pointers is not helping the debugging process.
For example, your print_list() could be re-written like this:
void print_list(List l){
List aux;
for(aux = l; aux != NULL; aux = aux->next)
printf("Valor: %d\n", aux->value);
}
and still behave the same. It is generally good practice not to 'hide' the pointer-like nature of a pointer by including a '*' in the typedef.
For example, if you define your list like this:
typedef struct node{
int value;
struct node *next;
} List
And pass it to functions like this:
my_func(List *l, ...)
then it'll make some of these issues more apparent. Hope this helps.
There are many problems in your code:
Hiding pointers behind typedefs is a bad idea, it leads to confusion for both the programmer and the reader.
You must decide whether the initial node is a dummy node or if the empty list is simply a NULL pointer. The latter is much simpler to handle but you must pass the address of the head node to insert and delete so they can change the head node.
printlist does not need an indirect pointer, especially starting from the address of the pointer passed as an argument. Simplify by using the Node pointer directly.
in insert you correctly insert the new node before the next higher node but you should then return from the function. Instead, you break out of the switch and the code for appending is executed, replacing the inserted node with a new node with the same value and a NULL next pointer. This is the reason 5 gets removed and lost when you insert 4. Furthermore, you should pass the address of the head node so a node can be inserted before the first.
delete starts from the address of the argument. It cannot delete the head node because the pointer in the caller space does not get updated. You should pass the address of the head node.
You should avoid using C++ keywords such as new and delete in C code: while not illegal, it confuses readers used to C++, confuses the syntax highlighter and prevents compilation by C++ compilers.
Here is a simplified and corrected version:
#include <stdio.h>
#include <stdlib.h>
typedef struct Node {
int value;
struct Node *next;
} Node;
Node *new_node(int value, Node *next_node) {
Node *node = malloc(sizeof(*node));
if (node != NULL) {
node->value = value;
node->next = next_node;
}
return node;
}
void print_list(Node *list) {
for (; list != NULL; list = list->next)
printf("Valor: %d\n", list->value);
}
void insert_node(Node **p, int value) {
while ((*p) != NULL && (*p)->value < value)
p = &(*p)->next;
*p = new_node(value, *p);
}
void delete_node(Node **p, int value) {
while (*p != NULL) {
if ((*p)->value == value) {
Node *found = *p;
*p = (*p)->next;
free(found);
// return unless delete() is supposed to remove all occurrences
return;
} else {
p = &(*p)->next;
}
}
}
int main(void) {
Node *n = NULL;
insert_node(&n, 2);
insert_node(&n, 3);
insert_node(&n, 5);
insert_node(&n, 4);
insert_node(&n, 1);
print_list(n);
delete_node(&n, 3);
print_list(n);
delete_node(&n, 1);
print_list(n);
return 0;
}

Linked List head not being updated across function calls

I trying to implement my own linked list and have been messing around with the code learning about dynamic memory allocation and pointers and such. When I try to add something to my linked list I get a segfault, and upon using the debugger I realized that it was because initially my linked list's head pointer was not pointing to null and then my add function was not recognizing the head as being empty. But I have an initialize function that is setting the linked list's head pointer to NULL but for some reason once I exit out of the initialize function and into the add function, the head is no longer pointing to NULL.
Here's my code:
list.h
typedef struct node{
int value;
struct node *next;
} Node;
typedef struct list{
Node *head;
} List;
list.c
void initialize(List *l){
if(l != NULL){
l = malloc(sizeof(List));
l->head = NULL;
}
}
void add(List *l, int a){
//Code
}
int main(){
List l;
initialize(&l)
add(&l, 2);
}
As soon as I step into the add function and print out *l, I see that the head is not pointing to 0x0. And I've been scratching my head as to why it's not. I thought it was something to do with pass by value but I don't think it is. What am I doing wrong here?
Yes, pass-by-value is your culprit. You are passing a pointer by value.
Suppose l in your main() is at address 0xABCD. Then your main() gets compiled to
int main(void) {
List l;
initialize(0xABCD);
add(0xABCD, 2);
}
and your initialize() call looks like this (suppose malloc() succeeds and allocates memory at address 0xCDEF:
void initialize(List *l) {
if(l != 0x0) {
l = 0xCDEF; // malloc()
l->head = 0x0;
}
}
That l = 0xCDEF does not propagate to main(), because l was passed by value.
What you want to do is
void initialize(List **l) {
if(l != NULL) {
*l = malloc(sizeof(List)); // note dereferencing the passed-by-value pointer
(*l)->head = NULL;
}
}
int main(void) {
List * l;
initialize(&l);
add(l, 2);
}
which will pass pointer to pointer to list (actually the address of the pointer in your main(). It allows the code in initialize() to change the l variable in main().
Alternatively, you can use
List * list_init() {
List * retval = malloc(sizeof(List));
if(retval == NULL) { // you should check malloc return value
// abort(), print warning or just
return NULL;
}
retval->head = NULL;
return retval;
}
int main(void) {
List * l = list_init();
if(l == NULL) {
// handle the error
}
add(l, 2);
}
You declare a List in main() that lives on the stack. You pass a pointer to that List to initailize(). You then create a new List on the heap. When you return from initialize() you still are using the List on the stack that you had in the beginning. The List on the heap is leaked and you cannot access it. So you never initialized the List you pass as a pointer to add(). You can forget about initialize() and just have
l.head = NULL;
instead.
Did you code compile this line l->malloc(sizeof(list)); seems odd.
Create a structure with only one argument is not really useful, a simple typedef should do the job : typedef Node* List

c - Implementation of queue using linked list

I tried to do implementation of queue by using linked list, but there always occurred error: incompatible types in assignment and assignment makes pointer from integer without a cast.
Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include "Queue.h"
struct QUEUE_ELEMENT{
int element;
struct QUEUE_ELEMENT *next;
};
int size;
struct QUEUE_ELEMENT *head, *tail;
void initQueue(){
head = NULL;
tail = NULL;
size = 0;
} // void initQueue()
int queueEmpty(void) {
return (head == NULL && tail == NULL);
} // int queueEmpty(void)
int enqueue(QUEUE_ELEMENT e) {
struct QUEUE_ELEMENT *temp;
if (tail == NULL){
tail -> next = NULL;
tail -> element = e;
head = tail;
}
else {
temp = malloc(sizeof(QUEUE_ELEMENT));
tail -> next = temp;
temp -> element = e;
temp -> next = NULL;
tail = temp;
}
return size++;
} // int enqueue(QUEUE_ELEMENT e)
int dequeue(QUEUE_ELEMENT *e){
struct QUEUE_ELEMENT *temp;
temp = malloc(sizeof(QUEUE_ELEMENT));
if (queueEmpty() != 0 ){
temp = head;
if(temp -> next != NULL){
temp = temp -> next;
free(head);
head = temp;
}
else{
free(head);
head = NULL;
tail = NULL;
}
}
return size--;
} // int dequeue(QUEUE_ELEMENT *e)
I revised my code a lot.
Why 'tail -> element = e;' in enqueue() occurs error 'incompatible types in assignment'? How can I fix it?
Is it a homework or for a real need? For the first one I won't say anything. But if you need it in practice, it's better to use already implemented solution.
There is a popular style where, in a linked list, head looks like a usual entry and the only thing which distinguishes it is the head pointer value itself. The first good example is Linux linked lists implementation (a description). Its specifics is a trick to get the whole entry address from its link member. This one is trivial to study and can answer your goals immediately.
The second good example is BSD list and queue macro set (a manpage; particularly, you could start with TAILQ macro set). It's more cumbersome due to some tricks (e.g. forward pointers address link field but backward pointers address the whole structure) but still efficient.
I hope both can satisfy you and prevent reinventing a wheel :)
You are assigning tail->element, which is an int, to e which is a QUEUE_ELEMENT. if you want to access the element in e you have to deference it like you did with tail first.
so tail->element = e->element

Recursive Linked List Reversal Function in C

My List is implemented via these two structs. The first contains the items in the list while the second contains the list itself.
typedef Employee Item;
typedef struct ListNodeTag {
Item item;
struct ListNodeTag *next;
} ListNode;
typedef struct {
int size;
ListNode *first;
} List;
I am trying to use the following recursive function to reverse the contents of the list however, I am getting a segmentation fault once there is more than one item in the list.
void Reverse(List *L){
ListNode *q,*p;
q = L->first;
p = q->next;
if(p == NULL)
return;
Reverse(L);
q->next->next = q;
q->next = NULL;}
I believe that the issue lies in the fact that instead of passing a member of the list as a function argument I am passing a pointer to the list itself. How would I change this code to let it work without passing a different argument?
You need to pass another parameter to the function to advance the recursive function to the end of the list. This can be done like this-
void Reverse(ListNode *f, List *l){
if(l->first == NULL)
return;
//Last node reached
if(f->next==NULL){
l->first->next = NULL;
l->first = f;
return;
}
ListNode *p,*q;
p = f;
q = f->next;
Reverse(f->next,l);
q->next = p;
}
Though this function works, it takes a lot of memory, so I'd recommend an iterative approach, like this one-
void Reverse(List *l){
ListNode *f = l->first;
ListNode *fn,*fnn;
if(f==NULL)
return;
fn = f->next;
if(fn==NULL)
return;
fnn = fn->next;
while(fnn!=NULL){
fn->next = f;
f = fn;
fn = fnn;
fnn = fnn->next;
}
fn->next = f;
l->first->next = NULL;
l->first = fn;
}
Have you made sure to initialise all your next pointers to NULL as you append items to the list?
Also, as I read it, the function won't actually recurse as you're always passing L. In other words, after the first call, how does the function know to go one further step down the list?

Resources