I have the following C code which returns the reverse of a linked list.
Though it reverses the linked list, I never get the head of the reversed linked list because the restofElements node is getting overwritten.
S *reverseRecursive(S *headref) {
S *firstElement = NULL;
S *restOfElements = NULL;
if (headref==NULL) {
return ;
}
firstElement = headref;
restOfElements = headref->next;
if (restOfElements == NULL)
return headref;
reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
headref = restOfElements;
return headref;
}
How can I get the head of the reversed linked list node returned to the calling program?
If you want to change the head pointer, you must pass it by reference (as a pointer). The prototype should be modified to receive the head as S **.
S *reverseRecursive(S **headref);
The head of the reversed list is equal to the head of the reversed List starting with restOfElements (because the original headref has to become tha last element of the reversed list). So storing the result of the recussive call should do (as Jim has already suggested in his comment):
...
headref = reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
/* headref = restOfElements; that's wrong */
return headref;
Thanks everyone. I have modified it little bit and it works now. Let me know your comments.
new_head is a global variable.
S *reverseRecursive(S *headref)
{
S *firstElement = NULL;
S *restOfElements = NULL;
if (headref==NULL)
{
return ;
}
firstElement = headref;
if (headref->next == NULL)
return headref;
else
restOfElements = headref->next;
reverseRecursive(restOfElements);
firstElement->next->next = firstElement;
firstElement->next = NULL;
if(new_head == NULL ) //just dont take it ervery time
new_head = restOfElements;
return new_head;
}
Probably closer.
S *reverseRecursive(S *headref)
{
S *firstElement = NULL;
S *restOfElements = NULL;
S *new_head = NULL;
if (headref==NULL)
{
return ;
}
firstElement = headref;
restOfElements = headref->next;
if (restOfElements == NULL)
return headref;
new_head = reverseRecursive(restOfElements);
restOfElements->next = new_head;
return restOfElements;
}
$ gcc -std=c99 -Wall -Wextra reverse.c
#include <stdlib.h>
#include <stdio.h>
typedef struct list {
struct list* next;
int data;
} S;
void print_list(S* list) {
if (list == NULL) { printf("NULL\n"); return; }
printf("%d ", list->data);
print_list(list->next);
}
S* reverse_aux(S* list, S* tail) {
// invalid arg
if (list == NULL) { return NULL; }
// base case
if (list->next == NULL) {
list->next = tail;
return list;
}
// general case
S* tmp = list->next;
list->next = tail;
return reverse_aux(tmp, list);
}
S* reverse(S* list) { return reverse_aux(list, NULL); }
int main(int argc, char* argv[]) {
// build a list with which to test
S a[10];
for (unsigned i = 0; i < sizeof(a)/sizeof(S); ++i) {
a[i].data = i;
a[i].next = &a[i+1];
}
a[sizeof(a)/sizeof(S) - 1].next = NULL;
S* list = &a[0];
print_list(list);
list = reverse(list);
print_list(list);
return 0;
}
Actually, since reverse is destructive (it mutates its argument), a better interface design would probably be
void reverse(S** plist);
reverse(&list);
So there's two ways to reverse a list in place recursively.
First, some setup. Let's make it easy to load linked lists
of strings and print them, so we can make sure this stuff works:
// linked_list.c
#include <stdio.h>
#include <stdlib.h>
// a linked lis of strings
typedef struct S {
struct S * next;
char * val;
} S;
// print out the list
void showS(char * const name, S * head) {
printf("%s: (", name);
while (head){
printf(" ");
printf("%s",head->val);
head = head->next;
printf( "%c", head ? ',' : ' ' );
}
printf(")\n");
}
// convert an array of strings into a linked list of strings
S * mkS(int n, char ** args) {
S * head = NULL;
if (n > 0 && (head = calloc(n, sizeof(S)))){
S * curr = head - 1;
while (n-- > 0) {
curr++;
curr->val = *args++;
curr->next = curr + 1;
}
curr->next = NULL;
}
return head;
}
One way of reversing the list involves passing back the new head of the
list once we find it. We don't need it locally (since we're just moving
the current element to the new end), but we'll need it so that the caller
has a pointer to the head of the list once we're done.
// reverse a list one way
S * revS1( S * const head ){
if (head && head->next) {
S * const new_head = revS1( head->next );
head->next->next = head;
head->next = NULL;
return new_head;
} else {
return head;
}
}
Another way takes a pointer to a pointer. The only difference is that
we don't need to return anything, since we're directly modifying a variable
the caller has. I prefer this calling method since it's much clearer
that we're modifying the list, not returning a copy. It's also harder
for the caller to accidentally loose the pointer to the new head this way.
// reverse a list another way
void revS2( S ** phead ){
S * const head = *phead;
if (head && head->next) {
*phead = head->next;
revS2( phead );
head->next->next = head;
head->next = NULL;
}
}
But what's better than either of these is to reverse the list non-recursively.
Neither of those functions is tail-recursive, so the compiler has
to allocate new stack frames for each element in the list. Try to reverse a long
enough list, and you'll blow your stack. Much better to just reverse the list
using a while loop.
// reverse a list non-recursively
void revS3( S ** phead ){
S * head = *phead;
S * reversed = NULL;
while (head) {
S * curr = head;
head = curr->next;
curr->next = reversed;
reversed = curr;
}
*phead = reversed;
}
Now we can test our results just by building lists out of the command line:
// just use the command line arguments as our list
int main(int argc, char** argv){
S* list1 = mkS(argc - 1, argv + 1);
S* list2 = mkS(argc - 1, argv + 1);
S* list3 = mkS(argc - 1, argv + 1);
showS( "given", list1 );
showS( "revS1", revS1(list1) );
revS2( &list2 );
showS( "revS2", list2 );
revS2( &list3 );
showS( "revS3", list3 );
return 0;
}
So let's compile:
% gcc -Wall linked_list.c -o linked_list
And do some test runs
% ./linked_list
given: ()
revS1: ()
revS2: ()
revS3: ()
% ./linked_list first second third
given: ( first, second, third )
revS1: ( third, second, first )
revS2: ( third, second, first )
revS3: ( third, second, first )
% ./linked_list only
given: ( only )
revS1: ( only )
revS2: ( only )
revS3: ( only )
Related
Is this a right way to do a linked list ? I am having a problem in a big school project and now i want to make sure that this is true.
void addnode(int a){
struct house* tmp = houses[i].next;
while (tmp != NULL) {
tmp = tmp->next;
}
tmp = (struct house*)malloc(sizeof(struct house));
tmp->id=a;
tmp->next=NULL;
}
i figured out that the error can be in other parts of the code. Now i will share the parts i suspect i hope you can help me.
houses[i] is an array of linked lists. if houses[i].id==-1 it is empty
struct house get_house_byid(int id) {
for (int i = 0; i < 1000; i++) {
if (houses[i].id != -1) {
if (houses[i].id == id) {
return houses[i];
}
if (houses[i].next != NULL) {
struct house* tmp = houses[i].next;
while (tmp != NULL) {
if (tmp->id == id) {
return *tmp;
}
tmp = tmp->next;
}
}
}
}
struct house housep;
housep.id = -1;
return housep;//if it cant find that id it returns housep
}
There may be other issues with your code that is not shown, but there are issues with addnode:
addnode does not set the head of the list (i.e. houses[i].next).
Thus, the newly added node is never connected to anything [and is a memory leak].
Ignoring the [obvious] typo/syntax error: void addnode{int a} instead of void addnode(int a).
The loop on tmp discards the pointer to the tail of the list. We need a separate variable (e.g. prev).
Note that i is global. That's fine, but the function would be cleaner if i was an argument to addnode instead.
Don't cast the return of malloc: Do I cast the result of malloc?
Here's is some refactored code. It is annotated:
void
addnode(int i,int a)
{
struct house *tmp;
struct house *prev;
// find the tail of the list
prev = NULL;
for (tmp = houses[i].next; tmp != NULL; tmp = tmp->next)
prev = tmp;
// allocate the new node
tmp = malloc(sizeof(*tmp));
tmp->id = a;
tmp->next = NULL;
// append to the tail of the [non-empty] list
if (prev != NULL)
prev->next = tmp;
// add to front of the empty list
else
houses[i].next = tmp;
}
typedef struct LinkedList LinkedList;
struct LinkedList {
LinkedList* next;
char* head;
char current;
};
LinkedList makeList()
{
char* headPointer = calloc(60, sizeof(char));
LinkedList temp = { 0xCCCCCCCC, headPointer, 0 };
return temp;
}
int addToList(LinkedList* lstPointer, char toAdd) {
if (lstPointer->head == NULL || lstPointer->head == 0xCCCCCCCC)
return -1;
if (lstPointer->current + 1 < 60) { /* enough space in the list to add */
*(lstPointer-> head + lstPointer -> current) = toAdd;
lstPointer->current = lstPointer->current + 1;
}
else /* not enough space, will create new node in the list */
{
if (lstPointer->next == 0xCCCCCCCC) {
LinkedList nextNode = makeList();
lstPointer->next = &nextNode;
}
return addToList(lstPointer->next, toAdd);
}
/*Added succsessfully*/
return 0;
}
int main(){
char chr;
LinkedList lst = makeList();
while ((chr = getchar()) != EOF) {
if (addToList(&lst, chr) == -1)
return -1;
}
return 0;
}
i am trying to use linked list but after i fill the first, i create a new one and able to add an item to it. on the second item the next list pointer get destroyed by getchar(). i have no idea why or how is it related.
In makelist you need to allocate a new list, but then instead of returning it, you copy it into a local variable, leaking the memory that you just allocated. Instead, return a pointer:
LinkedList *makeList() // Note *
{
LinkedList *temp = calloc(1, sizeof(LinkedList));
temp->head = calloc(60, sizeof(char));
temp->next = 0;
temp->current = toAdd;
return temp; // Note temp is a pointer
}
In addToList you don't need the nextNode variable:
lstPointer->next = makelist();
I am supposed to make a linked list that takes in strings and prints them out in the reverse order. Normally I'd ask the number of nodes that need to be created, and then ask for the data in a for loop until we're done.
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st *next;
}
But the problem is, the number of nodes isn't known until runtime. So I have to keep asking for data until the user is done. I'm not really sure where to start/how to do that and can't seem to find anything on the internet either. So a hint would be very helpful.
I have my insert function and the print function looks fairly simple too.
word_t *insert_2(word_t* head, string text) {
word_t * p = NULL;
word_t * temp = (word_t*) malloc(sizeof(word_t));
temp -> word = text;
temp -> next = NULL;
if(head == NULL) {
head = temp;
} else {
p = head;
} while(p -> next != NULL) {
p = p -> next;
}
p -> next = temp;
return head;
}
In reverse, replace next by prev:
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st * prev;
}
And the function:
word_t *insert_2(word_t* head, string text) {
word_t * nextHead = (word_t*) malloc(sizeof(word_t));
nextHead -> word = text;
nextHead -> prev = NULL;
// Check first element of LIFO
if( head == NULL ) {
return nextHead;
}
nextHead -> prev = head;
return nextHead;
}
I hope It compiles and work.
Note:
for(word_t * head = last ; head->prev != NULL ; head = head->prev )
{
// Do the job
;
}
I need to implement the function: struct listnode * mergesort(struct listnode *data)
My professor provided the main() function testing code. I only need to submit the mergesort function. He told us to do it in C or C++ but the test code main() he gave us is in C.
This is my code right now:
I can compile it but when I run it, it crashes. I checked debugger and it gave me segmentation fault. I am also not really sure if this function is correct since I can't get past the testing point in the main().
#include <stdio.h>
#include <stdlib.h>
struct listnode { struct listnode * next;
long value; } ;
struct listnode * mergesort(struct listnode *data)
{ int temp, finished = 0;
struct listnode *tail, *head, *ahead, *bhead, *atail, *btail;
if ( data == NULL )
return;
//Split
ahead = atail = head = data; // first item
btail = head->next; // second item
while(btail->next != NULL) // anything left
{
atail = atail->next;
btail = btail->next;
if( btail->next != NULL)
btail = btail->next;
}
bhead = atail->next; // disconnect the parts
atail->next = NULL;
//sort
mergesort(ahead);
mergesort(bhead);
//merge
if(ahead->value <= bhead->value) // set the head of resulting list
head = tail = ahead, ahead = ahead->next;
else
head = tail = bhead, bhead = bhead->next;
while(ahead && bhead)
if(ahead->value <= bhead->value) // append the next item
tail = tail->next = ahead, ahead = ahead->next;
else
tail = tail->next = bhead, bhead = bhead->next;
if(ahead != NULL)
tail->next = ahead;
else
tail->next = bhead;
return(head);
}
int main(void)
{
long i;
struct listnode *node, *tmpnode, *space;
space = (struct listnode *) malloc( 500000*sizeof(struct listnode));
for( i=0; i< 500000; i++ )
{ (space + i)->value = 2*((17*i)%500000);
(space + i)->next = space + (i+1);
}
(space+499999)->next = NULL;
node = space;
printf("\n prepared list, now starting sort\n");
node = mergesort(node);
printf("\n checking sorted list\n");
for( i=0; i < 500000; i++)
{ if( node == NULL )
{ printf("List ended early\n"); exit(0);
}
if( node->value != 2*i )
{ printf("Node contains wrong value\n"); exit(0);
}
node = node->next;
}
printf("Sort successful\n");
exit(0);
}
if ( data == NULL )
return;
You should return NULL.
btail = head->next; // second item
while(btail->next != NULL) // anything left
{
If btail is set to head->next. If head->next is NULL, you're trying to check in the loop NULL->next != NULL which isn't a thing.
if( btail->next != NULL)
btail = btail->next;
}
You need to check if btail is NULL before you check ->next. Just above you are setting btail = btail->next; so it could be set to NULL.
Also the loop above has the same issue, you need to check null before you do stuff with next.
There may be issues with the below code, but the above code needs way more error checking.
Example function to merge two already sorted lists using pointer to pointer. Since your'e only allowed a single function, you'll have to merge this logic into your mergesort() function. If this is homework, it may seem like you had too much help, but I'm not sure how else to explain the ideas shown in this example.
NODE * MergeLists(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
while(1){
if(pSrc1 == NULL){
*ppDst = pSrc2;
break;
}
if(pSrc2 == NULL){
*ppDst = pSrc1;
break;
}
if(pSrc2->data < pSrc1->data){ /* if src2 < src1 */
*ppDst = pSrc2;
pSrc2 = *(ppDst = &(pSrc2->next));
continue;
} else { /* src1 <= src2 */
*ppDst = pSrc1;
pSrc1 = *(ppDst = &(pSrc1->next));
continue;
}
}
return pDst;
}
I'm implementing a linked list and it needs to have a function that when given a head of a linked list and a cstring, it finds and deletes a node whose value is the cstring.
typedef struct node
{
char entry[21];
struct node* next;
} node;
/*returns true if node with phrase value found, otherwise false*/
bool findAndRemove(node* root, char phrase[21])
{
if(root != NULL)
{
node* previous = NULL;
while(root->next != NULL)
{
if(strcmp(root->entry, phrase) == 0)//found
{
if(previous == NULL)//node to delete is at head
{
node* tmp = root;
root = root->next;
free(tmp);
return true;
}
previous->next = root->next;
free(root);
return true;
}
previous = root;
root = root->next;
}
return false;
}
}
It works alright but when deleting the head some garbage gets printed out. What is happening and how can I fix this? Do I have any memory leaks? Out of curiosity is the term "root" or "head" more commonly used for the first node in a linked list?
The first thing to realise is that removing an element from a linked list involves changing exactly one pointer value: the pointer that points at us. This can be the external head pointer that points to the first list element, or one of the ->next pointers inside the list. In both cases that pointer needs to be changed; its new value should become the value of the ->next pointer of the node to be deleted.
In order to change some object (from within a function) we need a pointer to it. We need to change a pointer, so we will need a pointer to pointer.
bool findAndRemove1(node **ptp, char *phrase)
{
node *del;
for( ;*ptp; ptp = &(*ptp)->next) {
if( !strcmp((*ptp)->entry, phrase) ) { break; } //found
}
/* when we get here, ptp either
** 1) points to the pointer that points at the node we want to delete
** 2) or it points to the NULL pointer at the end of the list
** (in the case nothing was found)
*/
if ( !*ptp) return false; // not found
del = *ptp;
*ptp = (*ptp)->next;
free(del);
return true;
}
The number of if conditions can even be reduced to one by doing the dirty work in the loop,and returning from the loop but that would be a bit of a hack:
bool findAndRemove2(node **ptp, char *phrase)
{
for( ;*ptp; ptp = &(*ptp)->next) {
node *del;
if( strcmp((*ptp)->entry, phrase) ) continue; // not the one we want
/* when we get here, ptp MUST
** 1) point to the pointer that points at the node we want to delete
*/
del = *ptp;
*ptp = (*ptp)->next;
free(del);
return true;
}
return false; // not found
}
But what if the list is not unique, and we want to delete all the nodes that satisfy the condition? We just alter the loop logic a bit and add a counter:
unsigned searchAndDestroy(node **ptp, char *phrase)
{
unsigned cnt;
for( cnt=0 ;*ptp; ) {
node *del;
if( strcmp((*ptp)->entry, phrase) ) { // not the one we want
ptp = &(*ptp)->next;
continue;
}
/* when we get here, ptp MUST point to the pointer that points at the node we wish to delete
*/
del = *ptp;
*ptp = (*ptp)->next;
free(del);
cnt++;
}
return cnt; // the number of deleted nodes
}
Update: and a driver program to test it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct list {
struct list *next;
char entry[20];
} node;
void node_add( node **ptp, char *str)
{
node *new;
for ( ; *ptp; ptp = &(*ptp)->next) {
if (strcmp ((*ptp)->entry, str) < 0) continue;
}
new = malloc (sizeof *new);
strcpy(new->entry, str);
new->next = *ptp;
*ptp = new;
}
int main (void)
{
node *root = NULL;
unsigned cnt;
node_add (& root, "aaa" );
node_add (& root, "aaa" );
node_add (& root, "bbb" );
node_add (& root, "ccc" );
node_add (& root, "aaa" );
cnt = seachAndDestroy( &root, "bbb" );
printf("Cnt(bbb) := %u\n", cnt );
cnt = seachAndDestroy( &root, "ccc" );
printf("Cnt(ccc) := %u\n", cnt );
cnt = seachAndDestroy( &root, "aaa" );
printf("Cnt(aaa) := %u\n", cnt );
printf("Root now = %p\n", (void*) root );
return 0;
}
And the output:
plasser#pisbak:~/usenet$ ./a.out
Cnt(bbb) := 1
Cnt(ccc) := 1
Cnt(aaa) := 3
Root now = (nil)
You are changing the root inside the function, thus you need to pass a double pointer:
bool findAndRemove(node** root, char phrase[21])
{
node* iterate = *root;
if(root != NULL && *root != NULL)
{
node* previous = NULL;
while(iterate->next != NULL)
{
if(strcmp(iterate->entry, phrase) == 0)//found
{
if(previous == NULL)//node to delete is at head
{
node* tmp = iterate;
*root = iterate->next;
free(tmp);
return true;
}
previous->next = iterate->next;
free(iterate);
return true;
}
previous = iterate;
iterate = iterate->next;
}
return false;
}
}
You construct a list by pointing to the first node.
Then you delete the first node, but do not update the pointer to the list to point to the second one
Just make your function check if you are deleting the first node, and always return a pointer to the first pointer of the final list. Alternatively, instead of node *root parameter, pass node **root so you can modifiy the reference in your function (although I don't like this way of working).