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();
Related
I've read half a dozen answers with regards to this here and am relatively loathe to ask such a question, but I'm attempting to create a linked list using a struct in C, and was having some issues in passing pointers to the linked list. I think it's mostly sorted, but honestly am having acute issues trying to get the linked list working.
#include <stdio.h>
#include <stdlib.h>
typedef struct cell
{
int value;
struct cell *next;
} cell;
int inputplace = 0;
cell * createlist()
{
cell curElement = (cell *) malloc(sizeof(cell));
cell *head = &curElement;
cell *curEl = &curElement;
curEl->value = 900;
FILE *fp;
char *mode = "r";
fp = fopen("input",mode);
if(fp==NULL)
{
fprintf(stderr, "Unable to open input file 'input'");
exit(1);
}
int val;
int tempplace = 0;
while(tempplace < inputplace)
{
if(fscanf(fp, "%d", &val) != EOF)
{
tempplace++;
printf("%d", &val);
}
else
break;
}
while(fscanf(fp, "%d", &val)!=EOF)
{
inputplace++;
printf("%d\n", curEl);
if(val < 0)
{
curEl->value = -1;
curEl->next = -1;
break;
}
printf("%d\n", val);
curEl->value = val;
curEl->next = malloc(sizeof(struct cell));
curEl= curEl->next;
}
return head;
}
cell* reverse(cell* p)
{
cell * prev = -1;
cell * current = p;
cell * next;
while(current->value != -1)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
cell* append(cell* p, cell* q)
{
cell * current = p;
cell * r = p;
while(1)
{
if(current->value == -1)
{
current->value = q->value;
current->next = q->next;
}
}
return r;
}
int last(cell *p)
{
cell q = *p;
int last = -1;
while(1)
{
if(q.value == -1)
{
return last;
}
else
{
last = q.value;
q = *q.next;
}
}
}
cell * delete(int n, cell *p)
{
cell * head = p;
cell * prev = -1;
cell * current = p;
if(current-> value == n)
{
return current->next;
}
else
{
while(current->value != -1)
{
if(current->value==n)
{
prev->next = current->next;
break;
}
prev = current;
current = current->next;
}
}
return head;
}
int member(int n, cell *p)
{
cell q = *p;
while(1)
{
if(q.value == n)
{
return 1;
}
if(q.value == -1)
{
return 0;
}
q = *q.next;
}
}
int display(cell *p)
{
printf(" %c", '[');
cell q = *p;
while(1)
{
if(q.value == -1)
{
printf("%c ",']');
return 1;
}
if(q.next != p->next)
printf("%c ",',');
printf("%d", q.value);
q = *q.next;
}
printf("\n\n");
}
int main()
{
cell *head = createlist();
cell *headk = createlist();
cell *head3 = delete(5, head);
printf("%d, %d\n", head->value, head->next->value);
printf("Last head: %d\n", last(head));
display(headk);
display(head);
display(head3);
cell *head4 = delete(6, head);
display(head4);
cell *head5 = delete(7, head);
display(head5);
printf("Member2 6, head: %d\n", member(6,head));
printf("Member2 3, head: %d\n", member(3, head));
cell *head2 = reverse(head);
//print(head2);
printf("%d, %d\n", head2->value, head2->next->value);
}
So the input file contains numerical data with a negative one terminating the list:
Example input I'm using:
5
6
7
-1
1
2
3
-1
The issue I'm having is the second list is apparently overriding the first or some such, and my pointer-fu is weak, what do I need to do to successfully allocate the new structs?
Charles B.
You return a pointer to a local variable, and local variables goes out of scope once the function returns and that leaves you with a stray pointer. Using that stray pointer will lead to undefined behavior.
The problem starts with the declaration of curElement, and the compiler should really have screamed at you for that:
cell curElement = (cell *) malloc(sizeof(cell));
Here you declare curElement to be an actual structure, and not a pointer to the structure.
There's also the problem that you don't really have an end to the list. You allocate the next pointer of the last node you add, regardless if there's going to be a next node or not, and you don't initialize that node so the memory you allocate will be uninitialized, and trying to access it will lead to yet another undefined behavior.
I suggest something like the following abbreviated code:
cell *head = NULL;
cell *tail = NULL;
...
while (fscanf(fp, "%d", &val) == 1)
{
...
cell *current = malloc(sizeof(*current));
current->val = val;
current->next = NULL; // Very important!
// Check if this is the first node in the list
if (head == NULL)
head = tail = current;
else
{
// List is not empty, append node to end of list
tail->next = current;
tail = current;
}
}
Beside the change in how the list is handled and added to, there are also two other changes: The first is that the return value from the fscanf function is compared against 1, because fscanf (and family) will return the number of successfully parsed items, and this allows you to find format errors in the input file.
The second change is to not cast the return of malloc. In C you should never cast from or to void *, cast like that can hide subtle bugs.
Folks,
I don't know whether I am asking silly question. But tried to figure out my problem, but fail to that.
my structure is
typedef struct {
uint16 nwkaddr;
uint8 extaddr[8];
}device_t;
typedef struct node{
device_t list;
struct node *link;
}address_list;
The Data coming from UART is
1010,23CD1234,CD32454F,12F439AF,! . This I need to parse and store the mac list.
while(data[j] != '!')
{
if(data[i] == ',')
{
i = i+1;
memset(addr, 0, 9);
memcpy(addr, &data[i], 8);
// addr[8] = '\0';
if(addr != 0)
{
insert_MacList(addr);
}
}
i = i+8;
j = i+1;
}
the Created list is
void insert_MacList(uint8 *mac)
{
address_list *curr, *temp;
//curr = (address_list*)malloc(sizeof(address_list));
curr = osal_mem_alloc(sizeof(address_list));
strcpy((char*)curr->list.extaddr, (char const*)mac);
temp = head;
if(head == NULL)
{
head = curr;
head->link = NULL;
}
else
{
while(temp->link !=NULL)
{
temp = temp->link;
}
curr->link = NULL;
temp->link = curr;
}
}
I am trying to print all address,But I am fail to get 23CD1234. But after that I am getting correctly.
void check_inlist(void)
{
address_list *temp;
temp = head;
while(temp != NULL)
{
/*print data and send to UART*/
temp = temp->link;
}
}
Why head is changing to second element, is 23 value creating some problem?. So can some help me
You are using strcpy to copy data that isn't null terminated!
You can change it like this:
strncpy((char*)curr->list.extaddr, (char const*)mac, sizeof curr->list.extaddr); // strncpy won't write past the end of the array
You have
typedef struct {
uint16 nwkaddr;
uint8 extaddr[8];
}device_t;
But in insert_MacList() you call
strcpy((char*)curr->list.extaddr, (char const*)mac);
what copies 9 bytes (8 values + terminating '\0'). That might cause the problem.
please dont press the rep minus button so easily im new here- be nice please
i have slist.h implementing by slist.c
here is the slist.h
#ifndef DBLLIST_H
#define DBLLIST_H
//! The definition of a double linked list node
typedef struct dbllist_node
{
void *data; // Pointer to data of this node
struct dbllist_node *next; // Pointer to next node on list
struct dbllist_node *prev; // Pointer to previous node on list
}dbllist_node_t;
//! The definition of a double linked list
struct dbllist
{
dbllist_node_t *head; // Pointer to head of list
dbllist_node_t *tail; // Pointer to tail of list
unsigned int size; // The number of elements in the list
};
//! double linked list type
typedef struct dbllist dbllist_t;
// you have to use these macros, do not use the inner variables of the list!!
//! Macro to get the head node of a list l
#define dbllist_head(l) l->head
//! Macro to get the tail node of a list l
#define dbllist_tail(l) l->tail
//! Macro to get the size of a list l
#define dbllist_size(l) l->size
//! Macro to get the next node of l
#define dbllist_next(n) n->next
//! Macro to get the prev node of l
#define dbllist_prev(n) n->prev
//! Macro to get the data of node l
#define dbllist_data(n) n->data
//! Specifies whether dbllist_destroy should deallocate or not stored elements
typedef enum { DBLLIST_LEAVE_DATA = 0, DBLLIST_FREE_DATA } dbllist_destroy_t;
/** Initialize a double linked list
\param list - the list to initialize */
void dbllist_init(dbllist_t *);
/** Destroy and de-allocate the memory hold by a list
\param list - a pointer to an existing list
\param dealloc flag that indicates whether stored data should also be de-allocated */
void dbllist_destroy(dbllist_t *,dbllist_destroy_t);
/** Append data to list (add as last node of the list)
\param list - a pointer to a list
\param data - the data to place in the list
\return 0 on success, or -1 on failure */
int dbllist_append(dbllist_t *,void *);
/** Prepend data to list (add as first node of the list)
\param list - a pointer to list
\param data - the data to place in the list
\return 0 on success, or -1 on failure
*/
int dbllist_prepend(dbllist_t *,void *);
/** \brief Remove the specific node from the list.
\param to a pointer to the list
\param pointer to the node that should be removed.
\param dealloc flag that indicates whether to de-allocated the data in the node
\return 0 on success, or -1 on failure
*/
int dbllist_remove(dbllist_t *, dbllist_node_t* ,dbllist_destroy_t);
#endif
and now the slist.c i wrote
my problem is when ever i call the destroy function im facing segmentation fault at the last node.. i can provide main that i wrote too.
#include "slist.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void dbllist_init(dbllist_t *list)
{ if(list != NULL)
{
dbllist_head(list) = NULL;
dbllist_tail(list) = NULL;
dbllist_size(list) = 0;
}
}
int dbllist_append(dbllist_t *list,void *data)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
dbllist_data(temp) = data;
if(list!=NULL)
{
if(dbllist_head(list) == NULL)
{
//dbllist_next(temp) = NULL;
dbllist_prev(temp) = NULL;
dbllist_head(list) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
else
{
dbllist_next(temp) = NULL;
dbllist_prev(temp) = dbllist_tail(list);
dbllist_next(dbllist_tail(list)) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
}
return -1;
}
int dbllist_prepend(dbllist_t *list,void *data)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
dbllist_data(temp) = data;
if(list!=NULL)
{
if(dbllist_head(list) == NULL)
{
//dbllist_next(temp) = NULL;
dbllist_prev(temp) = NULL;
dbllist_head(list) = temp;
dbllist_tail(list) = temp;
dbllist_size(list)++;
return 0;
}
else
{
dbllist_next(temp) = dbllist_head(list) ;
dbllist_prev(temp) = NULL;
dbllist_prev(dbllist_head(list)) = temp;
dbllist_head(list) = temp;
dbllist_size(list)++;
return 0;
}
}
return -1;
}
/**
int dbllist_remove(dbllist_t *list, dbllist_node_t* pointer,dbllist_destroy_t dealloc)
{
dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
if(temp == NULL)
return -1;
temp = dbllist_head(list);
if(list != NULL && pointer !=NULL)
{
if(pointer == dbllist_head(list))
{
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
dbllist_head(list) = NULL;
dbllist_size(list) = 0;
dbllist_tail(list) = NULL;
free(dbllist_head(list));
free(temp);
return 0;
}
if(pointer == dbllist_tail(list))
{
dbllist_tail(list) = dbllist_prev(dbllist_tail(list)) ;
dbllist_next(dbllist_tail(list)) = NULL;
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
free(temp);
free(pointer);
dbllist_size(list)--;
return 0 ;
}
int tempSize = 1;
for(temp = dbllist_next(temp) ; tempSize< dbllist_size(list); temp = dbllist_next(temp),tempSize++)
if(temp == pointer)
{
dbllist_next(dbllist_prev(temp)) = dbllist_next(temp);
dbllist_prev(dbllist_next(temp)) = dbllist_prev(temp);
if(dealloc != DBLLIST_LEAVE_DATA)
free(dbllist_data(pointer));
free(temp);
free(pointer);
dbllist_size(list)--;
return 0;
}
}
return -1;
}
*/
int dbllist_remove(dbllist_t *list, dbllist_node_t* pointer,dbllist_destroy_t dealloc)
{
if(list == NULL || pointer == NULL )
return -1;
//printf("%d \n",(int)dbllist_data(current));
if( pointer == dbllist_head(list))
{
dbllist_head(list) = dbllist_next(dbllist_head(list));
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(dbllist_prev(dbllist_head(list))));
free(dbllist_prev(dbllist_head(list)));
dbllist_prev(dbllist_head(list)) = NULL;
dbllist_size(list)--;
return 0;
}
if(pointer == dbllist_tail(list))
{
dbllist_tail(list) = dbllist_prev(dbllist_tail(list));
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(dbllist_next(dbllist_tail(list))));
free(dbllist_next(dbllist_tail(list)));
dbllist_next(dbllist_tail(list)) = NULL;
dbllist_size(list)--;
return 0;
}
//int i = 1;
dbllist_node_t *current = dbllist_next(dbllist_head(list));
while(current)
{
if(current == pointer)
{
dbllist_next(dbllist_prev(current)) = dbllist_next(current) ;
dbllist_prev(dbllist_next(current)) = dbllist_prev(current) ;
dbllist_size(list)--;
if(dealloc == DBLLIST_FREE_DATA)
free(dbllist_data(current));
free(current);
current = NULL;
return 0;
}
current = dbllist_next(current);
}
free(current);
return -1;
}
void dbllist_destroy(dbllist_t *list ,dbllist_destroy_t dealloc)
{
//dbllist_node_t *current = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
//dbllist_node_t *temp = (dbllist_node_t *)malloc(sizeof(dbllist_node_t));
while (dbllist_head(list) != NULL)
{
//dbllist_node_t *current;
dbllist_node_t *temp ;
temp = dbllist_tail(list);
while(temp)
{
dbllist_remove(list,temp , dealloc);
printf("in\n");
temp = dbllist_tail(list);
printf("out \n");
}
//temp = dbllist_head(list);
//dbllist_remove(list,temp , dealloc);
//free(temp);
}
//free(current);
//free(temp);
}
can someone understand the error and explain to me how to fix it
im trying over a feew hours now without success
In this code:
if( pointer == dbllist_head(list))
{
// After next line: list->head points to next node (could be null)
dbllist_head(list) = dbllist_next(dbllist_head(list));
if(dealloc == DBLLIST_FREE_DATA)
// -- If head is now NULL, what happens below? --
free(dbllist_data(dbllist_prev(dbllist_head(list))));
free(dbllist_prev(dbllist_head(list)));
dbllist_prev(dbllist_head(list)) = NULL;
dbllist_size(list)--;
return 0;
}
the right answer is:
if(!dbllist_next(dbllist_head(list)))
{
if(dealloc == DBLLIST_FREE_DATA )
free(dbllist_data(dbllist_head(list)));
free(dbllist_head(list));
dbllist_head(list) = NULL;
dbllist_size(list)--;
return 0;
}
add this before the head part in remove function
because of a null pointer exception i did when in the head of the list.
thanks
In your Remove function dbllist_remove the section that is for the head case(pun intended ;)) tries to free memory that is NULL and not allocated.
The arguments free(dbllist_data(dbllist_prev(dbllist_head(list)))) AND dbllist_data(dbllist_prev(dbllist_head(list))) will not work as you have already removed the next element as well as its pointers. It was freed earlier in your destroy function. So, you cannot rely on the previous pointer actually pointing to anything.
So, I would modify your while loop in the destroy function to wait until head->next is null and then simply delete it outside of the loop and not use the standard remove function. Or modify your head case to take into account when head->next is null.
I have been working on this little project for quite some time and I can't figure out why I'm not getting the results that are expected. I am a beginner to C programming so my understanding with pointers and memory allocation/deallocation is novice. Anyways, I have constructed this segment of code by originally building a hash function, then adding a count to it. However, when I test it, sometimes the count works, sometimes it doesn't. I'm not sure whether it's the fault of the hash function, or the fault of the way I set up my count. The text file is read one line at a time and is a string consisting of a hexadecimal.
struct node {
char *data;
struct node *next;
int count; /* Implement count here for word frequencies */
};
#define H_SIZE 1024
struct node *hashtable[H_SIZE]; /* Declaration of hash table */
void h_lookup(void)
{
int i = 0;
struct node *tmp;
for(i = 0; i < H_SIZE; i++) {
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) {
printf("Index: %d\nData: %s\nCount: %d\n\n", i,
tmp->data, tmp->count);
}
}
}
}
/* self explanatory */
void h_add(char *data)
{
unsigned int i = h_assign(data);
struct node *tmp;
char *strdup(const char *s);
/* Checks to see if data exists, consider inserting COUNT here */
for(tmp = hashtable[i]; tmp != NULL; tmp = tmp->next) {
if(tmp->data != 0) { /* root node */
int count = tmp->count;
if(!strcmp(data, tmp->data))
count= count+1;
tmp->count = count;
return;
}
}
for(tmp = hashtable[i]; tmp->next != NULL; tmp = tmp->next);
if(tmp->next == NULL) {
tmp->next = h_alloc();
tmp = tmp->next;
tmp->data = strdup(data);
tmp->next = NULL;
tmp->count = 1;
} else
exit(EXIT_FAILURE);
}
/* Hash function, takes value (string) and converts into an index into the array of linked lists) */
unsigned int h_assign(char *string)
{
unsigned int num = 0;
while(*string++ != '\0')
num += *string;
return num % H_SIZE;
}
/* h_initialize(void) initializes the array of linked lists. Allocates one node for each list by calling h_alloc which creates a new node and sets node.next to null */
void h_initialize(void)
{ int i;
for(i = 0; i <H_SIZE; i++) {
hashtable[i] = h_alloc();
}
}
/* h_alloc(void) is a method which creates a new node and sets it's pointer to null */
struct node *h_alloc(void)
{
struct node *tmp = calloc(1, sizeof(struct node));
if (tmp != NULL){
tmp->next = NULL;
return tmp;
}
else{
exit(EXIT_FAILURE);
}
}
/* Clean up hashtable and free up memory */
void h_free(void)
{
struct node *tmp;
struct node *fwd;
int x;
for(x = 0; x < H_SIZE; x++) {
tmp = hashtable[x];
while(tmp != NULL) {
fwd = tmp->next;
free(tmp->data);
free(tmp);
tmp = fwd;
}
}
}
I assume that the count is not being incremented when it does not work. It is possible that strdup is not able to allocate memory for the new string and is returning NULL. You should check the return value to and exit gracefully if it fails.
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 )