How to access linked list node from other function? - c

Hey im trying to make a linked list. I created linked list from other function called CreateLibrary. but then how can I access the head of the node of the linked list from other function?
int *HeadGlobal;
struct node {
char judul[50], author[30];
struct node *link;
};
int CreateLibrary(struct node *head) {
struct node *head = malloc(sizeof(struct node));
HeadGlobal = head;
}
int ViewData() {
char judul[50], author[50];
struct node *head = malloc(sizeof(struct node));
head = &HeadGlobal;
printf("%s dan %s", head->judul, head->author);
}
I tried to make HeadGlobal Pointer and save the head pointer into this global pointer, therefore accessing it from other function,called ViewData(). but I think its not the correct solution. how to solve this?

The name CreateLibrary implies that you should be able to create any number of libraries. You do not need any global variables to achieve that. You are also confusing the type needed to maintain a library. Your linked list should maintain a linked list of struct nodes - not ints.
Here's an example of how that may look:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct node node; // makes it possible to use `node` instead of `struct node`
struct node {
char judul[50], author[30];
node *link;
};
typedef struct {
node* head;
node* tail;
size_t count;
} library; // library is the type maintaining info about one library instance
// here's the function to create one instance of a library:
library *CreateLibrary() {
library *newlibrary = malloc(sizeof *newlibrary);
if(newlibrary == NULL) return newlibrary;
// initialize this new empty library:
newlibrary->head = NULL;
newlibrary->tail = NULL;
newlibrary->count = 0;
return newlibrary;
}
// a function to clean up:
void DestroyLibrary(library *lib) {
for(node *curr = lib->head, *next; curr != NULL; curr = next) {
next = curr->link;
free(curr);
}
free(lib);
}
// a helper function to create a new node:
node *CreateNode(const char *judul, const char *author) {
node *new_node = malloc(sizeof *new_node);
if(new_node == NULL) return new_node; // oups - this should rarely happen
new_node->link = NULL;
// copy the supplied information into the new node:
strncpy(new_node->judul, judul, sizeof new_node->judul);
new_node->judul[sizeof new_node->judul - 1] = '\0'; // just a precaution
strncpy(new_node->author, author, sizeof new_node->author);
new_node->author[sizeof new_node->author - 1] = '\0'; // just a precaution
return new_node;
}
// a helper function to add a node to the library:
bool AddToLibrary(library *lib, node *new_node) {
if(new_node == NULL) return false; // we won't add node pointers pointing at NULL
if(lib->head == NULL) { // this is the first node added to library
lib->head = new_node;
} else { // there is already at least one node in the library
lib->tail->link = new_node;
}
lib->tail = new_node; // and the new node is the new tail
lib->count++; // increase the number of nodes in the library
return true; // we successfully added the node
}
// print the information about one specific node:
void ViewNode(const node *node) {
printf("%s dan %s\n", node->judul, node->author);
}
// print the information for all nodes in one specific library:
void ViewLibrary(const library *lib) {
for(node *curr = lib->head; curr != NULL; curr = curr->link) {
ViewNode(curr);
}
}
Example usage:
int main() {
library *lib = CreateLibrary();
if(lib == NULL) return 1; // failure :-(
AddToLibrary(lib, CreateNode("foo", "Hello"));
AddToLibrary(lib, CreateNode("bar", "World"));
ViewLibrary(lib);
DestroyLibrary(lib);
}
Demo

Related

How to modularize a Linked List?

I have the following Linked List:
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head = NULL;
struct Node *second = NULL;
struct Node *third = NULL;
head = (struct Node*) malloc(sizeof(struct Node));
second = (struct Node*) malloc(sizeof(struct Node));
third = (struct Node*) malloc(sizeof(struct Node));
head -> data = 1;
head -> next = second;
second -> data = 2;
second -> next = third;
third -> data = 3;
third -> next = NULL;
printfList(head);
return 0;
}
How can I modularize this example to get something more professional? node type and separated from the others and function separately?
I think by "modularize" here you mean more kinda professional, clean looking code, I came up with following :
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data; // Linked List type of data.
struct Node *next; // Pointer to the next Node.
};
struct Node * makeNode(int data){
struct Node *temp = (struct Node*)malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
return temp;
}
void printfList(struct Node *head)
{
while(head != NULL)
{
printf(" %d\n", head -> data);
head = head -> next;
}
}
int main()
{
struct Node *head, *prev;
int i, n;
printf("How many values you want to insert ?");
scanf("%d", &n);
printf("\nNow enter values :\n");
for(i = 0; i < n; i++){
int val;
scanf("%d", &val);
if(i == 0){
head = makeNode(val);
prev = head;
}
else{
struct Node *temp = makeNode(val);
prev->next = temp;
prev = temp;
}
}
printfList(head);
return 0;
}
Hope it helps.
I'm not sure what you're looking to do, but I think you should start by reviewing the question: should a "node" be a property of an object (a struct data type) or should a "node" be an accessor to a data type...?
Both work and I've used both.
When I need to link existing objects together, than a node will contain a reference data type... but unlike your list, the data is always accessed using a pointer (not containing the actual data type, but only using a reference).
This allows one (object) to many (lists) relationships.
However, many times the data type itself will need to be "chained" (in a single list - one to one relationship), in which case the "node" is a property of the data type and can be re-used in many different types.
A list to link existing types
Here's an example code where I used a linked list to link existing objects using a void pointer.
I'm not sure this implementation adds anything to your initial concept, but it does show the "modularization" for a "one (objet) to many (lists)" approach.
/* *****************************************************************************
Simple List
***************************************************************************** */
typedef struct fio_ls_s {
struct fio_ls_s *prev;
struct fio_ls_s *next;
void *obj;
} fio_ls_s;
#define FIO_LS_INIT(name) \
{ .next = &(name), .prev = &(name) }
/** Adds an object to the list's head. */
static inline __attribute__((unused)) void fio_ls_push(fio_ls_s *pos,
void *obj) {
/* prepare item */
fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
if (!item)
perror("ERROR: fiobj list couldn't allocate memory"), exit(errno);
*item = (fio_ls_s){.prev = pos, .next = pos->next, .obj = obj};
/* inject item */
pos->next->prev = item;
pos->next = item;
}
/** Adds an object to the list's tail. */
static inline __attribute__((unused)) void fio_ls_unshift(fio_ls_s *pos,
void *obj) {
pos = pos->prev;
fio_ls_push(pos, obj);
}
/** Removes an object from the list's head. */
static inline __attribute__((unused)) void *fio_ls_pop(fio_ls_s *list) {
if (list->next == list)
return NULL;
fio_ls_s *item = list->next;
void *ret = item->obj;
list->next = item->next;
list->next->prev = list;
free(item);
return ret;
}
/** Removes an object from the list's tail. */
static inline __attribute__((unused)) void *fio_ls_shift(fio_ls_s *list) {
if (list->prev == list)
return NULL;
fio_ls_s *item = list->prev;
void *ret = item->obj;
list->prev = item->prev;
list->prev->next = list;
free(item);
return ret;
}
/** Removes an object from the containing node. */
static inline __attribute__((unused)) void *fio_ls_remove(fio_ls_s *node) {
void *ret = node->obj;
node->next->prev = node->prev->next;
node->prev->next = node->next->prev;
free(node);
return ret;
}
A list that is integrated in the data-type
Often I have objects that I know I will link together and that by nature will only belong to a single list ("one to one").
In these cases, placing the node struct data within the data-type allows better locality and improved performance through a single allocation for both the data and the node information.
A good enough example for such a situation can be examined is this SO answer.

Linked List removeNode C Programming

I was having some confusion between ListNode and LinkedList. Basically my question was divided into 2 parts. For first part, I was supposed to do with ListNode. The function prototype as such:
int removeNode(ListNode **ptrHead, int index);
All function were working fine for the ListNode part. Then as for the second part, I was supposed to change the function above to this:
int removeNode(LinkedList *11, int index);
My code for part 1 which is working fine look like this:
int removeNode(ListNode **ptrHead, int index) {
ListNode *pre, *cur;
if (index == -1)
return 1;
else if (findNode(*ptrHead, index) != NULL) {
pre = findNode(*ptrHead, index - 1);
cur = pre->next;
pre->next = cur->next;
return 0;
}
else
return 1;
}
ListNode *findNode(ListNode *head, int index) {
ListNode *cur = head;
if (head == NULL || index < 0)
return NULL;
while (index > 0) {
cur = cur->next;
if (cur == NULL) return NULL;
index--;
}
return cur;
}
And here is my entire code for the part 2 which is not working:
#include "stdafx.h"
#include <stdlib.h>
typedef struct _listnode {
int num;
struct _listnode *next;
}ListNode;
typedef struct _linkedlist {
ListNode *head;
int size;
}LinkedList;
void printNode2(ListNode *head);
int removeNode2(LinkedList *ll, int index);
int main()
{
int value, index;
ListNode *head = NULL, *newNode = NULL;
LinkedList *ptr_ll = NULL;
printf("Enter value, -1 to quit: ");
scanf("%d", &value);
while (value != -1) {
if (head == NULL) {
head = malloc(sizeof(ListNode));
newNode = head;
}
else {
newNode->next = malloc(sizeof(ListNode));
newNode = newNode->next;
}
newNode->num = value;
newNode->next = NULL;
scanf("%d", &value);
}
printNode2(head);
printf("\nEnter index to remove: ");
scanf("%d", &index);
removeNode2(ptr_ll, index);
printNode2(head);
return 0;
}
void printNode2(ListNode *head) {
printf("Current list: ");
while (head != NULL) {
printf("%d ", head->num);
head = head->next;
}
}
int removeNode2(LinkedList *ll, int index) {
ListNode *head = ll->head;
if (head == index)
{
if (head->next == NULL)
{
printf("There is only one node. The list can't be made empty ");
return 1;
}
/* Copy the data of next node to head */
head->num = head->next->num;
// store address of next node
index = head->next;
// Remove the link of next node
head->next = head->next->next;
return 0;
}
// When not first node, follow the normal deletion process
// find the previous node
ListNode *prev = head;
while (prev->next != NULL && prev->next != index)
prev = prev->next;
// Check if node really exists in Linked List
if (prev->next == NULL)
{
printf("\n Given node is not present in Linked List");
return 1;
}
// Remove node from Linked List
prev->next = prev->next->next;
return 0;
}
When I try to run the part 2, the cmd just not responding and after a while, it just closed by itself and I have no idea which part went wrong. I was thinking am I in the correct track or the entire LinkedList part just wrong?
When I tried to run in debug mode, this error message popped up:
Exception thrown at 0x01201FD1 in tut.exe: 0xC0000005: Access violation reading location 0x00000000.
If there is a handler for this exception, the program may be safely continued.
Thanks in advance.
You say that you got the linked list to work wihen the list is defined via the head pointer only. In this set-up, you have to pass a pointer to the head pointer when the list may be updated, and just the head pointer when you only inspect the list without modifying, for example:
int removeNode(ListNode **ptrHead, int index);
ListNode *findNode(ListNode *head, int index);
Here, the head pointer is the handle for the list that is visible to the client code.
The approach with the list struct defines a new interface for the linked list. While the head node is enough, it might be desirable to keep track of the tail as well for easy appending or of the number of nodes. This data can be bundles in the linked list struct.
What that means is that the handling of the nodes is left to the list and the client code uses only the linked list struct, for example:
typedef struct ListNode ListNode;
typedef struct LinkedList LinkedList;
struct ListNode {
int num;
ListNode *next;
};
struct LinkedList {
ListNode *head;
ListNode *tail;
int size;
};
void ll_print(const LinkedList *ll);
void ll_prepend(LinkedList *ll, int num);
void ll_append(LinkedList *ll, int num);
void ll_remove_head(LinkedList *ll);
int main()
{
LinkedList ll = {NULL};
ll_append(&ll, 2);
ll_append(&ll, 5);
ll_append(&ll, 8);
ll_print(&ll);
ll_prepend(&ll, 1);
ll_prepend(&ll, 0);
ll_print(&ll);
ll_remove_head(&ll);
ll_print(&ll);
while (ll.head) ll_remove_head(&ll);
return 0;
}
There's also one difference: In the head-node set-up, the head node might be null. Here, the list cannot be null, it must exist. (Its head and tail members can be null, though.) Here the list is allocated on the stack, its address &ll must be passed to the functions.
In the linked list set-up, the distinction between modifying and read-only access is done via the const keyword:
void ll_print(const LinkedList *ll);
void ll_prepend(LinkedList *ll, int num);
In your example, you take a mixed approach with two independent structures, a head node and a list. That can't work, one single list is described by one struct, pick one.
The advantage to the linked list structure approach is that all required data like head, tail and size are always passed together to a function. You can also hide the implementation from the user by not disclosing the struct members, so that theb user can only work on pointers to that struct.
Finally, here's an example implementation of the above interface for you to play with:
void ll_print(const LinkedList *ll)
{
ListNode *node = ll->head;
while (node != NULL) {
printf("%d ", node->num);
node = node->next;
}
putchar('\n');
}
void ll_prepend(LinkedList *ll, int num)
{
ListNode *nnew = malloc(sizeof *nnew);
nnew->next = ll->head;
nnew->num = num;
ll->head = nnew;
if (ll->tail == NULL) ll->tail = ll->head;
ll->size++;
}
void ll_append(LinkedList *ll, int num)
{
ListNode *nnew = malloc(sizeof *nnew);
nnew->next = NULL;
nnew->num = num;
if (ll->tail == NULL) {
ll->tail = ll->head = nnew;
} else {
ll->tail->next = nnew;
ll->tail = nnew;
}
ll->size++;
}
void ll_remove_head(LinkedList *ll)
{
if (ll->head) {
ListNode *ndel = ll->head;
ll->head = ll->head->next;
ll->size--;
free(ndel);
}
}

How to split a linked-list into two lists

I'm writing a code to split a circular linked-list to two linked lists with equal number of codes, following is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct node *ptr;
struct node {
int element;
ptr prev;
ptr next;
};
typedef ptr list;
typedef ptr position;
int main() {
list L=malloc(sizeof(struct node));
list first=malloc(sizeof(struct node));
list second=malloc(sizeof(struct node));
splitlist(L,first,second);
return 0;
}
void splitlist(list L, list first,list second) {
position p,temp;
p=malloc(sizeof(struct node));
temp=malloc(sizeof(struct node));
p=L;
int count=0;
while ((p)->next != L) {
count++;
}
int c=count;
while (c!=(count/2)-1) {
p=(p)->next;
temp=(p)->next;
}
first=L;
(p)->next=NULL;
second=temp;
c=count;
while (c!=(count/2)-1) {
temp=(temp)->next;
}
(temp)->next=NULL;
}
When compiling my code it gives no errors but I'm not sure if it's working properly.
In order to get more readable and maintainable code, the first step to improve the code could be to create functions which help manipulating lists. Candidate functions are:
ListInitialize()
ListPushFront()
ListPushBack()
ListPopFront()
ListPopBack()
ListGetFirstNode()
ListGetNextNode()
ListGetFront()
ListGetBack()
ListEmpty()
...
With a proper set of arguments and return values of course.
Then you can write your splitlist function using those basic list operation functions and your code will be easier to read and to reason about.
Also, in order to handle an empty list, you should have an extra list type which is not just a pointer to a node.
typedef struct Node_tag { int value; struct Node_tag *next; struct Node_tag *prev } Node, *NodePtr;
typedef struct IntList_tag { NodePtr front; NodePtr back; } IntList;
// Creates an empty list.
void ListInitialize( IntList *pList ) { pList->front = NULL; pList->back = NULL; }
void ListPushFront( IntList *pList, int value )
{ NodePtr newNode = malloc(sizeof(Node));
if(NULL != newNode )
{ newNode->next = pList->front;
newNode->prev = NULL; newNode->value = value;
pList->front = newNode;
if( pList->back == NULL ) pList->back = newNode; // first element...
}
}
// ...
Eventually, using those functions, you can write splitlist() function in a concise and noise-free way:
void splitlist( IntList * source, IntList *target1, IntList *target2 )
{
IntList * currentTarget = target1;
for( NodePtr currentNode = ListGetFirstNode(source); currentNode != NULL; currentNode = ListGetNextNode(currentNode) )
{
ListPushBack(currentTarget, currentNode->value );
if(currentTarget == target1 ) currentTarget = target2;
else currentTarget = target1;
}
}
It might appear that it is much work to create all those other list functions if all you want is splitlist. But in real world applications you will most likely want all those other functions as well (or you have them already). Only in homework situations, this looks a bit funny.
Example code. Using typedef for node to be compatible with Microsoft C compilers (C89). Note sometimes the pointer to a circular list is a pointer to the last node of the circular list, (which contains a pointer to the first node of the circular list), allowing for faster appends. This example assumes list pointers are pointers to first nodes, but could be modified to assume list pointers are to last nodes.
#include <stdlib.h>
typedef struct _node{
struct _node *next;
int data;
}node;
node * splitlist(node * psrc, node ** ppdst1, node ** ppdst2)
{
node *ps = psrc;
node ** ppd1 = ppdst1;
node ** ppd2 = ppdst2;
*ppd1 = *ppd2 = NULL;
if(ps == NULL)
return NULL;
while(1){
*ppd1 = ps;
ps = *(ppd1 = &(ps->next));
if(ps == psrc)
break;
*ppd2 = ps;
ps = *(ppd2 = &(ps->next));
if(ps == psrc)
break;
}
*ppd1 = *ppdst1;
*ppd2 = *ppdst2;
return NULL;
}
main()
{
node a[8] = {{&a[1],0},{&a[2],1},{&a[3],2},{&a[4],3},
{&a[5],4},{&a[6],5},{&a[7],6},{&a[0],7}};
node *pa = &a[0];
node *pb = NULL;
node *pc = NULL;
pa = splitlist(pa, &pb, &pc);
return 0;
}

What does each line do in this Linked List program?

Here is a linked list I am working on, and trying to figure out exactly what each line does. The way I seem to be learning how to program is painstakingly difficult, and I am getting extremely discouraged. Regardless, I understand how the link list works, but I am not understanding what the code is saying and what it exactly is doing to create the structs. For example: I can't understand why would you be assigning a pointer to node (13 and 14), especially when my understand of pointers is that they are used to store memory locations.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct numnode
{
int val;
struct numnode * next;
};
typedef struct numnode node;
main()
{
int i;
node * head;
node * newnode;
head = NULL;
for (i = 1; i <= 10; i++)
{
newnode = (node *) malloc(sizeof(node));
newnode->val = i;
newnode->next = NULL;
if (head == NULL)
{
head = newnode;
}
else
{
newnode->next = head;
head = newnode;
}
}
}
Here are some annotations (and minor edits to reduce the amount of code).
/* Linked list node definition */
struct node {
int val;
struct node * next;
};
int main() {
int i;
struct node *head, *new_node;
head = NULL;
for (i = 1; i <= 10; i++) {
// Allocate a new node and initialize its components (val and next)
new_node = (struct node *) malloc(sizeof(node));
new_node->val = i;
new_node->next = NULL;
// The if block is actually not necessary...
if (head == NULL) {
// If the linked list is empty, set the head pointer to the initial node
head = new_node;
} else {
// Now that you have your new node, connect it. Start:
// head->[current linked list]
// [new_node.next]->NULL
new_node->next = head;
// head->[current linked list]->...
// [new_node.next]->[current linked list]->...
head = newnode;
// head->[new_node.next]->[current linked list]->...
}
}
}
The key thing is that malloc returns a pointer to memory. Each new node is allocated dynamically and thus is a location in memory (not a basic type).
If you fix the statement pointed out by PakkuDon you will find that the code inserts at the head. It will end up with a list whose values descend from 9 down to 1.
pointer is just the thing to tell you where is the value,like a phone number,you can call anyone no matter who there is,as you konw the number.pointer can point to anything(under your access) as you want,no matter it is a int or a struct.
Here is the summary of this code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
struct numnode
{
int val;
struct numnode * next;
};
typedef struct numnode node;
main()
{
int i;
node * head;
node * newnode;
head = NULL;
for (i = 1; i <= 10; i++)
{
newnode = (node *) malloc(sizeof(node));
newnode->val = i;
newnode->next = NULL;
if (head == NULL) // It'll be NULL first time, as head = NULL.
{
// True # i = 1
head = newnode;
}
else // Afterwards, as head=newnode
{
// New node will be created every time. Till i <= 10.
newnode->next = head;
head = newnode;
}
}
}
It is a simple code though.
PS: It is head == NULL

Reuseable linked list implementation

Hi I'm trying to implement a generic linked list. I've got something working using the following code but I can't see an obvious and neat way to remove the dependance on the global pointers (curr and root,) and thus allow multiple linked lists to be defined. If I were using c++ I would probably just wrap the whole thing in a class, but as it is I can only see one solution which is manually handling and passing root and curr to the functions that need them. I'm sure there is a better way than this so how would you go about this.
Thanks
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
struct Node{
int value;
struct Node *next;
};
struct Node * curr = NULL;
struct Node * root = NULL;
struct Node * createList(int val){
struct Node *n = malloc(sizeof(struct Node));
if(n==NULL){
printf("Node creation failed\n");
return NULL;
}
n->value = val;
n->next = NULL;
root=curr=n;
return n;
}
struct Node * extendList(int val, bool end){
if(curr == NULL){
return createList(val);
}
struct Node * newNode = malloc(sizeof(struct Node));
if(newNode==NULL){
printf("Node creation failed\n");
return NULL;
}
newNode->value = val;
newNode->next = NULL;
if(end){
curr->next = newNode;
curr = newNode;
}
else{
newNode->next = root;
root=newNode;
}
return curr;
}
void printList(void){
struct Node *ptr = root;
while(ptr!=NULL){
printf("%d\n",ptr->value);
ptr = ptr->next;
}
return;
}
struct Node * pos_in_list(unsigned int pos, struct Node **prev){
struct Node * ptr = root;
struct Node * tmp = NULL;
unsigned int i = 0;
while(ptr!=NULL){
if(i == pos){
break;
}
tmp = ptr;
ptr=ptr->next;
i++;
}
*prev = tmp;
return ptr;
}
void deletefromlist(int pos){
struct Node * del = NULL;
struct Node * prev = NULL;
del = pos_in_list(pos,&prev);
if(del == NULL)
{
printf("Out of range\n");
}
else
{
if(prev != NULL)
prev->next = del->next;
if(del == curr)
{
curr = prev;
}
else if(del == root)
{
root = del->next;
}
}
free(del);
del = NULL;
}
void deleteList(){
struct Node * del = root;
while(curr!=NULL){
curr = del->next;
free(del);
del=curr;
}
root = NULL;
curr = NULL;
}
int main(void)
{
int i;
for(i=0;i<10;i++){
extendList(i,true);
}
for(i=10;i>0;i--){
extendList(i,false);
}
printList();
deletefromlist(5);
printList();
deleteList();
return 0;
}
Create a Structure of Node * root and Node * curr
struct LinkedList{
struct Node * curr;
struct Node * next;
};
You can create another struct to hold the curr and root. This struct will function like a "linked-list object" frontend, while your node structs will be the backend. As an added benefit, you can store other attributes about the linked-list, like the number of elements in the list.
struct LinkedList {
int numElements;
struct Node * curr;
struct Node * root;
};
You can modify your functions to work with this struct, and once you are done, the benefit is that the end-user can create many linked-lists, and all they have to do is call the functions and pass in their pointers to the LinkedList struct.
The way this is usually done is by giving each function an argument for the linked list pointer. Like this:
struct Node * extendList(struct Node * head, int val, bool end){
if(head == NULL){
return createList(val);
}
struct Node * newNode = malloc(sizeof(struct Node));
if(newNode==NULL){
printf("Node creation failed\n");
return NULL;
}
newNode->value = val;
newNode->next = NULL;
struct Node * tail = head;
while (tail->next) tail = tail->next;
tail->next = newNode;
tail = newNode;
return newNode; // return the new node
}
Which removes any need for a global pointer and allows for an arbitrary number of lists. In fact, I would strongly advise you to avoid the use of global variables in this context.
I had submitted a review for a linked list implementation you can check out. You may want to check the criticisms to, the ones that may apply to your own implementation.
I have implemented a generic list in C.
It is intended to be used as a static library. List operations (on generic data) are exposed from a list service. As you have asked,
neat way to remove the dependance on the global pointers (head)
Defining multiple linked lists.
This list service accomplish both these features in following way,
Upon creating a new Linked list this service returns a unique identifier representing it instead of traditional Linked list head pointer. This way client code can't directly corrupt linked list. this list service allows creation of multiple linked lists. Each having unique id. It is upto client to free lists when they are done and service can re-use that slot later when creating a new one. Maintaining global head pointer for each list is mandatory in any approach, but here is it hidden inside list service.
Following is my implementation :
https://github.com/rajan-goswami/glist/wiki
Take a look at the Berkeley-derived generic implementations for some other ideas on how to do it.
Documentation queue(3)
Source OpenBSD, Linux libc

Resources