segmentation fault, lists in C - c

I tried to sort directly the numbers I enter in a linked list using two functions the first one add the element at the head the second one which contain the segmentation fault is supposed to exploit the first one to do the job.
#include <stdio.h>
#include <stdlib.h>
typedef struct cellule
{
int val;
struct cellule *suivant;
} cellule;
typedef struct cellule* liste;
liste insert_tete(liste L,int n)
{
liste p;
p=malloc(sizeof(cellule));
p->val=n;
p->suivant=L;
return p;
}//ok :)
liste insert_croissant(liste L,int n)
{
if(!L)
{
L=insert_tete(L,n);
return L;
}
liste p,q;
for(q=L,p=L; (p!=NULL )&&(n> (p->val)) ; q=p,p=p->suivant); //
p=insert_tete(p,n);
q->suivant=p;
return L;
}

By no means do I believe this will fix it, but there is at least one bug in your code.
Consider the case where L is initialized, but n < L->val:
// p = L, q = L;
// Let L = [val|->...
p=insert_tete(p,n);
// p = [n|->[val|->...
q->suivant=p;
// q = L
// Therefore [val|->[n|->L
// And you've just made your linked list circular.

liste insert_croissant(liste L,int n)
{
if(!L)
{
L=insert_tete(L,n);
return L;
}
Here we know that L is not NULL
liste p,q;
for(q=L,p=L; (p!=NULL )&&(n> (p->val)) ; q=p,p=p->suivant); //
The only way to get a legitimate segfault here is that one of the pointers p follows is a non-0 pointer that doesn't point to a properly allocated struct cellule, but to some inaccessible memory. Then trying to access p->val (or p->suivant) causes a segfault.
The most common way (in my limited experience) to get into that situation is forgetting to initialise the first pointer to 0.

The code has a problem where the list can get corrupted in certain cases; it's easy to get the list into a state where it's not properly terminated (and possibly 'lose' nodes from the list). And that situation could cause problems depending on how other code might manipulate the list.
If you try to add a new node on a list that isn't empty, but the new value is less than or equal to the first node's value, the list will end up being a circular list with two nodes on it. Any nodes after the one that was at the head of the list are lost.
This happens because in that case both p and q will point to that node when insert_tete(p,n) is called. After insert_tete(p,n) returns, p-suivant and q will be pointing to the node at the head of the list. so when
q->suivant = p;
is executed, the list will be circular and 'extra' nodes will be lost.
Depending on how your other operations act on the list, (especially if/how you delete elements) you could find yourself with a dangling pointer left in a suivant field (which may cause a segfault), or end up in an infinite loop.

Simplified version using pointer-to-pointer. Note: there is no special case for the empty list.
struct cellule {
int val;
struct cellule *suivant;
};
struct cellule *insert_croissant(struct cellule **LL, int val)
{
struct cellule *p,**pp;
for(pp=LL ; *pp && (*pp)->val < val ; pp = &(*pp)->suivant) {;}
/* When we arrive here, pp points to whatever pointer happens
** to point to our current node.
** - If the list was empty, *pp==NULL
** - if the place to insert happens to be the tail of the list, *p is also NULL
** - in all cases, *pp should be placed after the new node, and the new node's pointer should be assigned to *pp
*/
p = malloc(sizeof *p);
p->val = val;
p->suivant = *pp;
*pp = p;
return *LL;
}

Related

How can a Linked List be implemented using only pointers (w/o structures)?

I'm trying to create a linked list without using structures in C.
I want to be able to store an int variable on every node and a pointer to the next node, add unlimited numbers to the list, remove the first item, print all of the elements, etc.
I was thinking that every node of type int** should have 2 pointers of type int*.
the first one will point to an int address and the second will point to NULL.
Then, if I like to add a number to the list, I'll use the last pointer to point to a new allocated node of type int** and so on.
I'm having trouble writing the proper code for this though, and can't seem to reach to the actual int values. See the image below:
You can achieve this by allocating two uintptr_t each time: the first allocated memory space will be responsible for storing the value of the integer and the second one will be pointing to the next memory location.
uintptr_t nodeFirst = malloc(2 * sizeof(uintptr_t));
...
...
uintptr_t nodeNext = malloc(2 * sizeof(uintptr_t));
....
....
*nodeFirst = someIntValue;
*(nodeFirst + 1) = nodeNext;
...
The fact is, my solution above is still using the struct analogy, but w/o the struct keyword.
Here is a complete solution of a LinkedList managed as int ** pointers.
Step 1 - the addNode() function to add one node to the int **head.
int **addNode(int **head, int ival)
{
int **node = malloc(2 * sizeof(int *));
// don't forget to alloc memory to store the int value
node[0] = malloc(sizeof(int));
*(node[0]) = ival;
// next is pointing to NULL
node[1] = NULL;
if (head == NULL) {
// first node to be added
head = node;
}
else {
int **temp;
temp = head;
// temp[1] is the next
while (temp[1]!=NULL) {
// cast needed to go to the next node
temp = (int **)temp[1];
}
// cast needed to store the next node
temp[1] = (int *)node;
}
return (head);
}
Step 2 - a function display() to explore the current linkedlist.
void display(int **head)
{
int **temp;
int i = 0;
temp = head;
printf("display:\n");
while (temp!=NULL) {
// temp[0] is pointing to the ivalue
printf("node[%d]=%d\n",i++,*(temp[0]));
temp = (int **)temp[1];
}
printf("\n");
}
Step 3 - the popNode() function to remove the first node.
int **popNode(int **head)
{
int **temp;
if (head!=NULL) {
temp = (int **)head[1];
// don't forget to free ivalue
free(head[0]);
// then free the next pointer
free(head[1]);
head = temp;
}
return (head);
}
Step 4 - then an example of main() function using the linkedlist.
int main()
{
int **head = NULL;
head = addNode(head,111);
head = addNode(head,222);
head = addNode(head,333);
display(head);
// display:
// node[0]=111
// node[1]=222
// node[2]=333
head = popNode(head);
display(head);
// display:
// node[0]=222
// node[1]=333
while ((head = popNode(head))!=NULL);
display(head);
// display:
return (0);
}
Allocate two arrays, both of which are stored as pointers. In C, they can be the pointers you get back from calloc(). The first holds your node data. We can call it nodes. The second is an array of pointers (or integral offsets). We can call it nexts. Whenever you update the list, update nodes so that each nexts[i] links to the next node after the one that contains nodes[i], or an invalid value such as NULL or -1 if it is the tail. For a double-linked list, you’d need befores or to use the XOR trick. You’ll need a head pointer and some kind of indicator of which elements in your pool are unallocated, which could be something simple like a first free index, or something more complicated like a bitfield.
You would still need to wrap all this in a structure to get more than one linked list in your program, but that does give you one linked list using no data structure other than pointers.
This challenge is crazy, but a structure of arrays isn’t, and you might see a graph or a list of vertices stored in a somewhat similar way. You can allocate or deallocate your node pool all at once instead of in small chunks, it could be more efficient to use 32-bit offsets instead of 64-bit next pointers, and contiguous storage gets you locality of reference.

Changing value of Linked List without flexiblility in parameters

I have an assignment. I was provided with a function declaration that I cannot modify.
The function declaration is void Insert (Item x, int p, List *L); where I am supposed to change the values of the linked list struct, L.
Now, the code that invokes that method in my main function is
struct List *L = malloc(sizeof(List));
Insert(x,p,L);
How would I change my code so I can pass the address of the struct List instead of making another copy of it?
Like I said, I cannot change the function declaration at all.
/*********************************************************************
* FUNCTION NAME: Insert
* PURPOSE: Inserts an Item in a List.
* ARGUMENTS: . The Item to be inserted (Item)
* . The position in the List
* where the Item should be inserted in (int)
* . The address of the List (List *L)
* REQUIRES (preconditions):
* . The position should be a nonnegative integer
* not greater than the size of the List.
* . The List should not be full.
* ENSURES: . Empty will return false (0).
* . Size will return the first integer greater
* than the size of the List before the call.
* . Peek in the same position will find
* the Item that was inserted.
*********************************************************************/
extern void Insert (Item X, int position, List *L);
What I tried that didn't work was
head->next = L; //changing the next item in list to L
L = head; //changing the address of L so it remains the head of the list
I think this will work:
void Insert (Item x, int p, List *L) {
struct List newnode, last = *L;
newnode = (struct List)malloc(sizeof(struct List));
newnode->item = x;
newnode->next = NULL;
if (last == NULL){
if (p == 0) { *L = newnode; }//first node
else { printf("List is empty and index %d does not exist", p); }
} else if (p == 0) {
newnode->next = *L;
*L = newnode;
}
else{
int counter = 0;
while (1) {
if (counter == p) {
newnode->next = last->next;
last->next = newnode;
break;
}
last = last->next;
counter++;
if (last->next == NULL && counter != p){ break; }
}
}
}
You might want to review the differences (or similarities) between addresses, pointers in C because the answer to your question is that you are already passing the address of your struct List.
I will try and explain a bit. malloc() returns a memory address, AKA a pointer, which is denoted by the * symbol in struct List *L. When I read this line in my head, I would say "L contains a pointer to a struct List object" or "L contains the memory address of a struct List object".
So in that case, when you write Insert(L, x) you are already passing a pointer to your struct List object. And no other copy is being made. So any actions you perform inside of your Insert() function will be acting on the original list.
The only exception to this rule is if you try to reassign L in your insert method, like this:
void Insert(struct List* L, int x) {
L = NULL; // or L = malloc(sizeof(struct List));
}
This will not do what you might expect, but the reason for that is more complicated and something you probably don't need to know for the time being.
There are irregularities with your function declarations.
Your code suggests that you have a function with the following signature :
void Insert (struct List *L, int x);
The header file that you have linked uses a function insert with this signature :
extern void Insert (Item X, int position, List *L);
Note the additional parameter Item X.
There isn't much to go on since you haven't showed us much of your code, but I would suggest taking a look at your missing parameter.
First of all:
How would I change my code so I can pass the address of the struct List instead of making another copy of it?
You are already doing it: void Insert (Item x, int p, List *L); takes pointer to List structure, not structure itself, so you are not copying it.
Secondly:
What I tried that didn't work was head->next = L; //changing the next item in list to L
L = head; //changing the address of L so it remains the head of the list
It won't work. Inside Insert function L is value of pointer to List. So if you change this value inside the function it won't be change outside, as value of L is passed by copy. Only changes to *L will be seen, as they will not change value of L itself, but value of what L is pointing to.
I can assure you, that no L = is needed inside Insert function to complete this task.
Moreover take good look at prerequisites - they should discribe situations, which you do not need to trouble yourself with (probably, I don't know person which created this task, but I would understand it this way) - meaning, if user doesn't comply to them, it's users own fault, anything bad can happen.

Doubly linked list does not create properly

I am trying to create a doubly linked list in C but it doesn't work and I don't know why. It prints only the last element that I introduce. I do not see any problem at the part of code that creates the list. Maybe you can see it?
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
struct node *prev;
}NodeT;
struct d_linked_list
{
NodeT *first;
NodeT *last;
};
int main()
{
int d;
struct d_linked_list *l;
NodeT *p,*q;
p=(NodeT*)malloc(sizeof(NodeT));
q=(NodeT*)malloc(sizeof(NodeT));
l->first=NULL;
l->last=NULL;
while (fscanf(stdin,"%d",&d)!=EOF)
{
p->data=d;
if (l->first==NULL)
{
l->first=p;
l->last=p;
p->next=NULL;
p->prev=NULL;
}
else
{
l->last->next=p;
p->prev=l->last;
l->last=p;
}
}
l->last->next=NULL;
for (q=l->first;q!=NULL;q=q->next)
printf("%d ",q->data);
return 0;
}
As so often, there are a number of problems, some of them already identified in other answers or in comments and some (I think) not identified before:
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
struct node *prev;
}NodeT;
struct d_linked_list
{
NodeT *first;
NodeT *last;
};
So far, so good.
int main()
{
int d;
struct d_linked_list *l;
You don't allocate space for l. It would probably be simpler (maybe better, therefore) to use:
struct d_linked_list head; // Or maybe list instead of head
and then refer to head in your code instead of l; you could also use l = &head; without further changes.
NodeT *p,*q;
p=(NodeT*)malloc(sizeof(NodeT));
q=(NodeT*)malloc(sizeof(NodeT));
You never use the space allocated for q and you eventually overwrite it, thus leaking. You should check that malloc() worked, doing something appropriate (stop with an error message?) if it has failed.
l->first=NULL;
l->last=NULL;
while (fscanf(stdin,"%d",&d)!=EOF)
You should check that you got one integer with while (fscanf(stdin, "%d", &d) == 1); the loop breaks on EOF or on a conversion failure.
{
p->data=d;
You allocated p before the loop, but each subsequent entry is overwriting the same space. You need to allocate a new node for each value you read. (This was not previously identified as an issue — though I see Filipe Gonçalves added it to his answer while I was typing mine.)
if (l->first==NULL)
{
l->first=p;
l->last=p;
p->next=NULL;
p->prev=NULL;
}
else
{
l->last->next=p;
p->prev=l->last;
l->last=p;
}
}
Superficially, the code above looks OK; I've not run it, so there could be issues I've not spotted.
I noted 'not thoroughly checked' and indeed there are problems, as Filipe pointed out. The if clause is OK, I think, but the else clause needs to set p->next = NULL;. In general, it is a good idea to create the node completely: p->data = d; p->next = NULL; p->prev = NULL: and then hook the node into the list.
l->last->next=NULL;
This line should be unnecessary. At the end of each cycle of the loop, the list should be correctly formed. One way to test this is to print out the contents of the list (using a function) on each cycle. You'd also use that function in place of the loop that follows. An interface design that I often use is:
void dump_list(FILE *fp, char const *tag, struct d_linked_list const *list)
which prints the identifying tag and the contents of the list on the given file stream. I keep such functions around for every significant data structure so that debugging is easier later.
for (q=l->first;q!=NULL;q=q->next)
This loop loses track of the space allocated to q.
printf("%d ",q->data);
You should output a newline at some point.
You should also go through the motions of releasing all the space allocated, simply to make sure you know how you could do that. When you're about to exit a program, it isn't crucial, but if you were using the list in a long-running program that needs a list once a minute, then goes off and does unrelated operations, then you'd be leaking all that memory and your long-running program would stop running after a while because it lacked the necessary memory (because it had leaked — wasted — the memory in the lists).
return 0;
}
Try moving p=(NodeT*)malloc(sizeof(NodeT)); into the top of the loop. Also, you don't need to malloc the value in q.
You never allocate space for l. Therefore, these lines are dereferencing an invalid pointer:
l->first=NULL;
l->last=NULL;
You must allocate space for l before using it:
l = malloc(sizeof(*l));
l->first=NULL;
l->last=NULL;
Also, you need to allocate a new element for each new value that you read. Thus, I would move the allocation for p into the loop:
q=(NodeT*)malloc(sizeof(NodeT));
l->first=NULL;
l->last=NULL;
while (fscanf(stdin,"%d",&d)!=EOF)
{
p=(NodeT*)malloc(sizeof(NodeT));
/* ... */
}
And you don't need to allocate space for q (you use it only for traversing the list). Finally, as pointed out in a comment, you should check if fscanf() returned 1, because only in that case you can be sure that d contains a valid value.
Putting this all together:
int main()
{
int d;
struct d_linked_list *l;
NodeT *p,*q;
if ((l = malloc(sizeof(*l))) == NULL) {
/* Handle malloc error */
}
l->first=NULL;
l->last=NULL;
while (fscanf(stdin,"%d",&d) == 1)
{
if ((p = malloc(sizeof(*p))) == NULL) {
/* Handle malloc error... */
}
p->data=d;
p->next = p->prev = NULL;
if (l->first==NULL)
{
l->first=p;
l->last=p;
}
else
{
l->last->next=p;
p->prev=l->last;
l->last=p;
}
}
for (q=l->first;q!=NULL;q=q->next)
printf("%d ",q->data);
return 0;
}
UPDATE: I changed the code to check for malloc()'s return value, and took that l->last->next = NULL; away - p->next and p->prev are now initialized to NULL inside the loop, there is no need to do it after the loop.

Reversing Doublely Linked Deque in C

I'm having trouble reversing my doublely linked deque list (with only a back sentinel) in C, I'm approaching it by switching the pointers and here is the code I have so far:
/* Reverse the deque
param: q pointer to the deque
pre: q is not null and q is not empty
post: the deque is reversed
*/
/* reverseCirListDeque */
void reverseCirListDeque(struct cirListDeque *q)
{
struct DLink *back = q->backSentinel;
struct DLink *second = q->backSentinel->prev;
struct DLink *third = q->backSentinel->next;
while (second != q->backSentinel->next){
back->next = second;
third = back->prev;
back->next->prev = back;
back = second;
second = third;
}
}
But it doesn't seem to work, I've been testing it with a deque that looks like this: 1, 2, 3
The output is: 3 and this process seems to mess up the actual value of the numbers. ie. 2 becomes 2.90085e-309... I think the pointer switching is messed up but I cannot find the problem. And even though it doesn't mean my code is correct; it compiles fine.
Linked structures like deques lend themselves readily to recursion, so I tend to favor a recursive style when dealing with linked structures. This also allows us to write it incrementally so that we can test each function easily. Looping as your function does has many downsides: you can easily introduce fencepost errors and it tends toward large functions that are confusing.
First, you've decided to do this by swapping the pointers, right? So write a function to swap pointers:
void swapCirListDequePointers(
struct cirListDeque** left,
struct cirListDeque** right)
{
struct cirListDeque* temp = *left;
*left = *right;
*right = temp;
}
Now, write a function that reverses the pointers in a single node:
void swapPointersInCirListDeque(struct cirListDeque* q)
{
swapCirListDequePointers(&(q->prev),&(q->next));
}
Now, put it together recursively:
void reverseCirListDeque(struct cirListDeque* q)
{
if(q == q->backSentinel)
return;
swapPointersInCirListDeque(q);
// Leave this call in tail position so that compiler can optimize it
reverseCirListDeque(q->prev); // Tricky; this used to be q->next
}
I'm not sure exactly how your struct is designed; my function assumes that your deque is circular and that you'll be calling this on the sentinel.
EDIT: If your deque isn't circular, you'll want to call swapPointersInCirListDeque(q) on the sentinel as well, so move swapPointersInCirListDeque(q) before the if statement.
If you plan to use the backSentinel after this, you should change that also, since it's now the front of the list. If you have a frontSentinel, you can just add swapCirListDequePointers(&(q->frontSentinel),&(q->backSentinel)); to swapPointersInCirListDeque. Otherwise, you'll have to pass in the first node along with q and set q->backSentinel to that.
If it's a doubly linked list, you shouldn't need to change any pointers at all. Just swap over the payloads:
pointer1 = first
pointer2 = last
while pointer1 != pointer2 and pointer2->next != pointer1:
temp = pointer1->payload
pointer1->payload = pointer2->payload
pointer2->payload = temp
pointer1 = pointer1->next
pointer2 = pointer2->prev
If by back sentinel you mean the last pointer (as in no first pointer is available), then you need to step backwards throw the deque to find it. It's hard to believe however that this would be the case since it would be a fairly inefficient deque (which is supposed to be a double ended queue).
You've been given a couple of suggestions already; here's another possibility:
// Assumes a node something like:
typedef struct node {
struct node *next, *prev;
int data;
} node;
and also assumes a couple of variables (globals for the moment) named head and tail that point to the head and tail of the deque, respectively.
void reverse() {
node *pos = head;
node *temp = pos->next;
head = tail;
tail = pos;
while (pos != NULL) {
node *t = pos->prev;
pos->prev = pos->next;
pos->next = t;
pos = temp;
if (temp)
temp = temp->next;
}
}
At least for the moment, this does not assume any sentinels -- just NULL pointers to signal the ends of the list.
If you're just storing ints in the deque, Paxdiablo's suggestion is a good one (except that creating a doubly-linked node to hold only an int is a massive waste). Assuming that in reality you were storing something large enough for doubly-linked nodes to make sense, you'd also prefer to avoid moving that data around any more than necessary, at least as a general rule.

C issue - Can't figure how to assign pointer to beginning of list

I have a simple assignment that the professor wants us to do.
Basically to pull in some numbers from a text file and load into a linked list.
I don't want to get to much into the details but I have a basic question.
He provided us with a function like so:
INTLIST* init_intlist( int n )
{
INTLIST *lst;
lst = (INTLIST *)malloc(sizeof(INTLIST));
lst->datum = n;
lst->next = NULL;
return lst;
}
This function is used to initialize the linked list with the first element. Then he asked us to define a function with this signature:
int insert_intlist( INTLIST *lst, int n )
So I assume he just wants us to add to the linked list so I tried this:
int insert_intlist( INTLIST *lst, int n )
{
INTLIST* lstTemp;
lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
lstTemp->datum = n;
lstTemp->next = lst;
lst = lstTemp;
free(lstTemp);
}
So what my thought process was is that it creates a temporary node, assigns the data value (Datum) and assigns the next pointer to point to where the current pointer is pointing at. Then I reassign the main pointer to this newly created temp node.
That way we have for instance 2 nodes:
[New Temp Node] -> [Prev Initialized Node]
When I step through the code it looks great...
Then back in main I have just a function to print the list:
while (lst!=NULL)
{
printf("The value is:%d", lst->datum);
lst=lst->next;
}
The problem is this only seems to print one digit (namely the first digit that I am reading in from the file, which I think is the last one in the list or at least I thought it was the last one in the list).
But it should keep going through as I have 10 digits in the file. I know the code is very dirty and I will clean it up...here is my entire main function if anyone needs more info:
#include <stdio.h>
#include <stdlib.h>
#include "intlist.h"
int main(int argc, char *argv[])
{
char c; /* Character read from the file. */
FILE* ptr; /* Pointer to the file. FILE is a
structure defined in <stdio.h> */
int index=0;
//INTLIST* aList[10]; //will use later
/* Open the file - no error checking done */
ptr = fopen("1.txt","r");
/* Read one character at a time, checking
for the End of File. EOF is defined
in <stdio.h> as -1 */
if(ptr==NULL) {
printf("Error: can't open file.\n");
/* fclose(file); DON'T PASS A NULL POINTER TO fclose !! */
return 1;
}
//aList[index] = malloc(sizeof(INTLIST)); WE NEED THIS LATER ON....
INTLIST *lst=NULL;
while ((c = fgetc(ptr)) != EOF)
{
if (c != ' ')
{
//make sure it isnt a space
int i = c - '0'; //get the value from the text file
if(c=='\n')
{
// aList[index]=lst;
// index++;
// aList[index] = malloc(sizeof(INTLIST));
while (lst!=NULL)
{
printf("The value is:%d", lst->datum);
lst=lst->next;
}
free(lst);
free(aList[index]);
return 0;
//new line in the file
//create another linked list
}
if (lst==NULL)
lst = init_intlist(i);
else
insert_intlist( lst, i);
}
}
fclose(ptr);
system("PAUSE");
return 0;
}
Here is intlist.h for anyone who may need it:
#ifndef __intlist_h__
#define __intlist_h__
/* each entry in the list contains an int */
typedef struct intlist {
int datum;
struct intlist *next;
} INTLIST;
INTLIST *init_intlist( int n ); /* initializes the intlist with initial datum n */
int insert_intlist( INTLIST *lst, int n ); /* Inserts an int (n) into an intlist from the beginning*/
void list_append(INTLIST *list, void *datum); /* Inserts entry to the end of the list */
INTLIST* list_front(INTLIST *list); /*return the element at the front of the list, and remove it
from the list*/
void list_map( INTLIST *list, void (*f)(void *) ); /*Applies a function to each element of the list */
void list_delete( INTLIST *list ); /* Deletes (and frees) all entries in the list */
#endif
A couple of issues here.
I'll start with a BAD bug:
int insert_intlist( INTLIST *lst, int n )
{
INTLIST* lstTemp;
lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
lstTemp->datum = n;
lstTemp->next = lst;
lst = lstTemp;
free(lstTemp); // <<<<< NO!
}
You are still using that memory, so you can't free it.
Secondly, the proto-type supplied to you for insertion has no way to return a new front of the list, so you can not change the front of the list. This implies that you must add new nodes to the back, rather than to the front as you have done.
Also, the supplied return type of int probably means that he expects out the number of nodes in the list, which is no problem as you're going to have to walk the list to find the back anyway.
Have another go at it, you're not doing badly at all.
Working with code like:
int insert_intlist( INTLIST *lst, int n )
{
INTLIST* lstTemp;
lstTemp = (INTLIST *)malloc(sizeof(INTLIST));
lstTemp->datum = n;
lstTemp->next = lst;
lst = lstTemp;
free(lstTemp);
}
This has a couple of problems. First of all, the free(lstTemp) seems to be freeing the node that you just inserted in the list, which you probably don't want to do.
Second, you're passing the pointer to the list into the function -- which means the function can't modify that pointer, so when you assign to the pointer, you're only changing your local copy of it.
You have two choices: you can either pass in a pointer to that pointer (so you can modify the original pointer) or you can get clever and figure out a way to avoid needing to (but I won't give away the secret right away...)
This line:
lst = lstTemp;
Only changes the value of lst inside the function. It won't propagate back to the copy of the pointer that the caller has.
You can either use a pointer-to-a-pointer, or if you can't change the function signature, insert somewhere other than the head of the list.
Though the typical way of handling this is to not point to the first element in the list - rather, you have some sort of list structure that holds a pointer to the first element, and some other information about the list (say, how many elements it has). Then you pass a pointer to that structure around.
In C, parameters are passed to functions "by value", meaning they are copied when you enter the function and any changes you make to them are not reflected back to the caller. That means that when you modify lst to point to your newly allocated memory it doesn't actually modify the caller's pointer to the list.
EDIT: As dmckee pointed out, you shouldn't free the memory in your insert function as you are still using it. That's definitely a bug, but it's not the one causing your problem.
In C, everything is passed by value. If you want a function to change something, you need to pass its address to the function. Since in int insert_intlist( INTLIST *lst, int n ), you want to change the list head, you need to pass a pointer to it, i.e., the first parameter should be INTLIST **lst (see below too, though). But the function prototype is given and cannot be changed.
What that means is that you can't add a number to the beginning of the list—the caller can't know that you did so. So, you have to traverse the list pointed to by lst, and then add the new node anywhere down the chain. The professor probably wants you to add the node at the end, but he might have asked for some other condition.
With that information, let's look at the comments for the prototypes:
/* Inserts an int (n) into an intlist from the beginning*/
int insert_intlist( INTLIST *lst, int n );
The comment or the prototype is wrong. If your professor has given you this file, insert_intlist() cannot be written to satisfy the comment, since it can't return to the caller the new head. The prototype should be either:
/* Inserts an int (n) into an intlist from the beginning
and returns the new head */
INTLIST *insert_intlist( INTLIST *lst, int n );
Or:
/* Inserts an int (n) into an intlist from the beginning */
int insert_intlist( INTLIST **lst, int n );
(Note the **.)
The header also has:
/*return the element at the front of the list, and remove it from the list*/
INTLIST* list_front(INTLIST *list);
This is correct. Note that you need to modify the list's head in list_front(), so you're returning the new head.
Finally, you don't want to free() anything in insert_intlist(). You want to keep the new node in the list, don't you? Once the caller is done with the list, he will have to call list_delete(), which will traverse the linked list, and free each node.
I Agree with Alok. I Have the same problem/ Professor. I am new to C programming and I have been looking all over the web for forms and C webpages for help. I have came across a source that supports Alok.
I used
INTLIST *list_add(INTLIST **p, int i){
INTLIST *n;
n = (INTLIST *) malloc(sizeof(INTLIST));
if (n == NULL)
return NULL;
n->next = *p; /* the previous element (*p) now becomes the "next" element */
*p = n; /* add new empty element to the front (head) of the list */
n->datum = i;
return p; }
From my main I can pass in
INTLIST *list
list_add(&list, 1);
list_add(&list, 2);
so when i print the list it prints 2 1
The professor suggested this:
INTLIST *mylist[N];
Where N is the number of rows of your
input file. Then mylist[i] is a
pointer to the ith linked list.
Okay Fine: create for testing purposes INTLIST *mylist[2];
I call the same functions:
list_add(&list[0], 1);
list_add(&list[0], 2);
This prints out 2 1 ... Great,
But when I do this:
list_add(&list[1], 3);
list_add(&list[1], 4);
I get a Segmentation fault..

Resources