Can somebody please explain what this code with pointers does:
while(terminate== 0)
{
s->value=s->next->value;
if ((s->next->next)==NULL)
{
free(s->next);
s->next=NULL;
terminate= 1;
}
s=s->next;
}
where s is passed as a parameter as : set_el* s and having this structure below:
typedef struct set_el
{
int value;
struct set_el* next;
} set_el;
In case of NULL input it will cause a segmentation fault since s->value is illegal.
On a list of size 1 it will similarly fail because s->next->value is illegal.
On a list with a loop (for instance a>b>a...) it will loop endlessly because s->next->next will never be NULL
Finally on a linked list of size 2 or above it will traverse the list coping the value of the next node to the current node and delete the last node.
Effectively it will 'remove' the first node in the list in a very roundabout way. (We free up the last node memory but we copy the values up the list. The new list is 1 node shorter and without the value in the first node).
Related
I'm new to C and have a question.
How would I check if a linked list is empty?
I have a struct _node
typedef struct _node{
int data;
struct _node *next;
}node;
If I have initialized node *list, but didn't do anything to it (i.e didn't assign list->data a value), how would I check if it's empty?
I tried if (node == NULL){break} but didn't work.
Thanks for the help!
Intro:
There are usually two ways to use linked lists: with a root element and without.
Without a root, your list pointer is NULL when the list is empty:
node *list;
...
if (list == NULL) { /* empty list */ }
With root, there is always one element. But it can be used in two ways:
Either simply to provide a pointer to the first element.
node *root;
...
if (root->next == NULL) { /* empty list */ }
Or to have the last element link back to the root to form a cycle. This concept has the advantage that the "next" element is never NULL and you thus don't need to check for it. In this case, the list is empty if the root points back to itself.
node *root;
...
if (root->next == root) { /* empty list */ }
Answer:
Now, according to your description, you have allocated a node. This either means you want the "root" approach (second or third example). But if you want to go with the first variant, you must not allocate the node, since it doesn't hold data.
For the "root" approach, you indeed have one (and only one) node that doesn't hold data. But for simple linked lists, all nodes must contain data.
I'd keep it simple.
Check the head pointer - if it is NULL, there's no entry in the list.
int isEmpty( node * list )
{
if( !list )
return 1;
return 0;
}
Sometimes when you create a variable, C will zero out all the data for you. Other times, the variable will contain garbage. You need to learn the rules that govern this, but as a beginner, you should simply be certain always to initialize your variables explicitly.
For a linked list, when you append a node to a list, you should always be certain to set a NULL into the next pointer, so that the list will be properly terminated.
Your linked list should have a "head" pointer. If the head is set to NULL then you have a zero-length linked list; if the head has any value other than NULL you must have at least one node in the linked list, so the list must have length of at least 1.
So, as long as you have been careful about initializing your head pointer to NULL you can trivially tell whether the list is empty by checking to see if the head pointer is NULL.
But your question was really about the data member variable. There will always be some sort of value in there. As I said, sometimes C will set it to zero for you, but other times it will be unpredictable garbage (a value that could be any integer value). You need to initialize that to a sensible default when you allocate a new node. For example, the valid values of data might all be greater than zero, so you might set data to zero to indicate that it is currently empty.
You can write a simple loop that traverses your linked list and checks each data member, and return true if it finds any data that is not zero (or whatever special value flags that it is unused). It should return false if it finds only default data or if the list is zero length.
Its better to have a header node when building your linked list. Then you can add nodes to build the list. Let that list variable be your header node. Then to check if your linked list is empty, use this:
typedef struct _node{
int data;
struct _node *next;
}*node;
and then instantiate
node list;
and to check the linked list is empty use
if((list->next)==null)
{
break;
}
I have to print a list of a set in c using linked lists (hence pointers). However,when I delete the first element of the list and try to print the list, it just displays a lot of addresses under each other. Any suggestions of what the problem might be? Thanks!
Delete function:
int delete(set_element* src, int elem){
if (src==NULL) {
fputs("The list is empty.\n", stderr);
}
set_element* currElement;
set_element* prevElement=NULL;
for (currElement=src; currElement!=NULL; prevElement=currElement, currElement=currElement->next) {
if(currElement->value==elem) {
if(prevElement==NULL){
printf("Head is deleted\n");
if(currElement->next!=NULL){
*src = *currElement->next;
} else {
destroy(currElement);
}
} else {
prevElement->next = currElement->next;
}
// free(currElement);
break;
}
}
return 1;
}
void print(set_element* start)
{
set_element *pt = start;
while(pt != NULL)
{
printf("%d, ",pt->value);
pt = pt->next;
}
}
If the list pointer is the same as a pointer to the first element then the list pointer is no longer valid when you free the first element.
There are two solutions to this problem:
Let all your list methods take a pointer to the list so they can update it when neccesary. The problem with this approach is that if you have a copy of the pointer in another variable then that pointer gets invalidated too.
Don't let your list pointer point to the first element. Let it point to a pointer to the first element.
Sample Code:'
typedef struct node_struct {
node_struct *next;
void *data;
} Node;
typedef struct {
Node *first;
} List;
This normally happens when you delete a pointer (actually a piece of the memory) which doesn't belong to you. Double-check your function to make sure you're not freeing the same pointer you already freed, or freeing a pointer you didn't create with "malloc".
Warning: This answer contains inferred code.
A typical linked list in C looks a little something like this:
typedef struct _list List;
typedef struct _list_node ListNode;
struct _list {
ListNode *head;
}
struct _list_node {
void *payload;
ListNode *next;
}
In order to correctly delete the first element from the list, the following sequence needs to take place:
List *aList; // contains a list
if (aList->head)
ListNode *newHead = aList->head->next;
delete_payload(aList->head->payload); // Depending on what the payload actually is
free(aList->head);
aList->head = newHead;
The order of operations here is significant! Attempting to move the head without first freeing the old value will lead to a memory leak; and freeing the old head without first obtaining the correct value for the new head creates undefined behaviour.
Addendum: Occasionally, the _list portion of the above code will be omitted altogether, leaving lists and list nodes as the same thing; but from the symptoms you are describing, I'm guessing this is probably not the case here.
In such a situation, however, the steps remain, essentially, the same, but without the aList-> bit.
Edit:
Now that I see your code, I can give you a more complete answer.
One of the key problems in your code is that it's all over the place. There is, however, one line in here that's particularly bad:
*src = *currElement->next;
This does not work, and is what is causing your crash.
In your case, the solution is either to wrap the linked list in some manner of container, like the struct _list construct above; or to rework your existing code to accept a pointer to a pointer to a set element, so that you can pass pointers to set elements (which is what you want to do) back.
In terms of performance, the two solutions are likely as close so as makes no odds, but using a wrapping list structure helps communicate intent. It also helps prevent other pointers to the list from becoming garbled as a result of head deletions, so there's that.
I need to make a program that has (at most) 50 linked lists. Basically, my program generates some messages and based on a indicator that comes in the front of my string, I need to put the message in the right linked list.
I don't know if it is clear enough but I will try to show part of my code (the important part). The function I made to add a new element (on the top) of the linked list is the following:
void InsertLL (News p, char M[]) {
char * text = malloc(strlen(M)+1);
strcpy(text, M);
News s,t;
t = malloc(sizeof(struct List));
t-> Text = text;
s = p;
p = t;
p-> next = s;
}
My struct List (the type of the elements of my lists) contains a char pointer (called text) and a pointer to the next element of the list.
Simulating my program, suppose that I received a message that needs to be put in the linked list where the begin is pointed by the pointer p[0]. So I create a new element (forget the case that the list is empty, I already made this one) and add in the top of my list using the function I've shown.
Now, suppose that I received another message that needs to be put in the next pointer p[1]. If I print p[0] -> Text, I get the text of p[1]->Text.
I mean, if I add a new element in the list pointed by p[i], all the previous texts p[i] -> Texts gets the new text of this new element. I have no idea what am I doing wrong.
I don't know if it is enough to help me, if more information is needed, just tell me.
Problem with your code is you are not maintaining the list of nodes. you are overwriting the same node again and again.
Algo:
If no node then create one.
If nodes are present then navigate to end node.(You can use tail
pointer for quicker access).
Append the node at the end.
Creating Node:
Declare a node type pointer.
Allocate memory to it.
Update the content of the node.
Set the next pointer of the node to null.
Add this node to end of the list.
ex. inserting node 3 in the list of node 1 and node 2.
This is the general approach that you can use
typedef struct node{
int val; //you can use your text here
struct node* next;
}NODE;
struct node* head=0;
int addNode(int v){
if(head==0){ //checking for empty node.
struct node* n=malloc(sizeof(NODE));
n->val=v;
head=n;
}
else{
struct node* temp=head;
while(temp->next != 0) //Navigating till end
{
temp=temp->next;
}
struct node* n=malloc(sizeof(NODE)); //allocating memory
n->val=v; //you need to use strcpy for string here.
temp->next=n; //adjusting pointers
n->next=0;
}
}
You can check this demo created by me for Double linked List http://ideone.com/s6TtUX
This loop will crash and give the error of EXC_BAD_ACCESS in XCode 4.6.2
Here is the loop code
for (beforeToDel = studentToChange->pFirstClass;
(int)strcmp(beforeToDel->pNext->classId, className) == 0;
beforeToDel = beforeToDel->pNext)
{}
and the different variables have these values:
Thank you so much for any help you can give!
beforeToDel->pNext->pNext is NULL. Your loop will crash on the second iteration trying to indirect through that pointer to compare to className. You need to check it before calling strcmp.
Aside: Why the typecast to int?
There is no need to cast the return value of strcmp to an int. It's already one.
What happens if beforeToDel is NULL, or if beforeToDel->pNext is NULL? If they point to nothing, then they can't have a classId or pNext member, right?
It is an error to use strcmp if you haven't included <string.h>, so make sure you have that included. I presume you're looking for the link to a node to be removed, hence the rather awkward identifier "beforeToDel". What happens if the head of the list is the node you want to remove? Why don't you start with a pointer to studentToChange->pFirstClass and iterate on the links, rather than the nodes? This will solve your head problem, and make your code more clear at the same time.
I'm going to declare my linked list like this:
struct list {
struct list *next;
char class_name[];
};
Declare a pointed to whichever type pNext is. Call it link, because this object will store a pointer to the link that the code will update. Initialise it to the head of the list. This way, when the first iteration results in a match, you'll be changing the head of your list with ease. In my function, I'll be returning the new head. You don't need to do that in your code. Just make sure link points to the head of the list (eg. link = &studentToChange->pFirstClass;).
At the end of each iteration, update link to point to (*link)->next (or pNext, in your case).
Operate on *link, rather than link (eg. strcmp(*link->classId, class_name) == 0). When the node to delete is found, assign over the top of it by using *link = *link->next; or equivalent.
struct list *list_remove_class_name(struct list *head, char *class_name) {
struct list **link = &head;
/* Did you mean != 0 here? */
while (*link != NULL && strcmp(*link->class_name, class_name) == 0) {
*link = *link->next;
}
struct list *node = *link;
if (node != NULL) {
*link = node->next;
}
free(node);
return head;
}
Purpose of code:
TO maintain a unique element link list...UFID is the keyword for unique
Structure declaration:
struct sharedFiles
{
char UFID[50];
int valid; //valid 1 if someone have this file in write mode
int shared; //no of user's reading this file
struct sharedFiles *next; //pointer to next node
}*sfstart,*sfend; //sfstart points to the first node of linked list and efend to the last node of linked list so that it will be easy to just insert at the end without traversing the linked list
Error Description:
The below code gives segmentation fault when I invoking it 2nd time.
I tried to debug with GDB and it says unable to access the location at line
if(strcmp(sftemp->UFID,ufid)==0)
In the above line it is unable to access sftemp->UFID
/*Function code*/
int addShareList(char *ufid,int mode) //mode=0 (read) and mode=1 (Write request)
{
struct sharedFiles *sftemp,*newnode;
sftemp=sfstart;
if(sfstart==NULL) //if list is empty add first node
{
sfstart=(struct sharedFiles *) malloc(sizeof(struct sharedFiles));
strcpy(sfstart->UFID,ufid);
sfstart->valid=mode;
sfstart->shared=1;
sfstart->next=NULL;
sfend=sfstart; //this node will also be last node of Linked list
return 0;
}
else //if list is not empty
{
while(sftemp->next != NULL) //traverse till last node
{
if(strcmp(sftemp->UFID,ufid)==0)
{
//here if same node found some manupulation to the struct variables
}
sftemp=sftemp->next;
} //while
if(sftemp->next==NULL) //procvess last node
{
if(strcmp(sftemp->UFID,ufid)!=0) //if last node not same add node at the end of Linked list
{
newnode=(struct sharedFiles *) malloc(sizeof(struct sharedFiles));
strcpy(newnode->UFID,ufid);
newnode->valid=mode;
newnode->shared=1;
newnode->next=NULL;
sftemp->next=newnode;
sfend=newnode;
return 0;
}
else //if last node is same
{
//some manipulations to struct variables
}
} //if
}
return -1;
}//addShareList
The above code works fine for inserting first element.When I invoke the same function for inserting second node in the linked list it unable to access the first node while comarision
in the line if(strcmp(sftemp->UFID,ufid)==0). Hope now the purpose of code is clear.
Thanks in advance..
In the while you check if sftemp!=NULL so we can be sure that in the second iteration, after line sftemp=sftemp->next; the pointer contain allocated memory.
But, since I don't know how the list it structured, I can't be sure that the content contains another node of sharedFiles type, it could contain an end-list node which not contains UFID attribute.
So, check in your list how to control if the list is finished.
Another solution can be to change your check this way:
while(sftemp->next!=NULL)
...
if(sftemp->next==NULL) {
//add the node in the right way, consider the end-list node
}
EDIT:
Furthermore, change in the first if the line sftemp->next = NULL; to sfnext->next = NULL;.
And be sure to initialize stnext = NULL.
EDIT 2:
Now that you post struct declaration I still cannot see when you initialize sfstart. Try to do this:
Structure declaration:
struct sharedFiles
{
char UFID[50];
int valid; //valid 1 if someone have this file in write mode
int shared; //no of user's reading this file
struct sharedFiles *next; //pointer to next node
}*sfstart = NULL,*sfend;
Normally the answer for this is that the pointer is NULL, which in your case means malloc has failed because you're out of memory - you really should be checking the return value.
The most likely cause for your problem is that you have corrupted the heap, so that sftemp no longer points to a valid memory address. Check what it's value is that might give you some more clues.