I remember back when I was self teaching myself C I found building a doubly linked list was difficult and finding examples to learn from on the net was also difficult so here I am with some code to get people started.

So here is the file tate_list.c
Code:
/*
 * tate_list.c
 *
 *  Created on: Jan 7, 2010
 *      Author: Tate Exon
 *
 *  A simple somewhat generic doubly linked list.
 */

#include <stdlib.h>
#include <stdio.h>
#include "tate_list.h"
#include "tate_bool.h"

/**
 * Node type, ptr and struct
 * contains a void * which can be anything and then ptrs to the
 * next element and the prev element.
 * Basically the entire node is private to this class and can only
 * be manipulated here.
 */
typedef struct node NodeType;
typedef struct node* Node;
struct node{
	void* data;
	Node next;
	Node prev;
};

void freeNode(Node node){
	if(node == NULL){
		return;
	}
	free(node);
}

/**
 * Private list type and structure
 * contains the head and tail of the list and the size
 */
typedef struct tate_list listType;
struct tate_list{
	Node head;
	Node tail;
	int size;
};

/**
 * Creates a ptr to a new empty list and returns it.
 */
tateList newList(){
	tateList list;
	list = (tateList)malloc(sizeof(listType));
	list->head=NULL;
	list->tail=NULL;
	list->size = 0;
	return list;
}

/**
 * Adds an element to the list given.
 */
bool listAdd(tateList list, void* data){
	Node nod;
	nod = (Node)malloc(sizeof(NodeType));
	if(nod == NULL){
		return false;
	}
	nod->data = data;
	if(list->head == NULL){
		list->head = nod;
		list->tail = nod;
		nod->prev = NULL;
		nod->next = NULL;
	}else{
		list->tail->next=nod;
		nod->prev = list->tail;
		nod->next = NULL;
		list->tail=nod;
	}
	list->size+=1;
	return true;//success
}

/**
 * Retrieves a ptr to the item at the element number given.
 * 0 is the first element.
 * Returns NULL if the element number given is out of range.
 */
Node list_get(tateList list, int element){
	if(element>=list->size || element<0){
		fprintf(stderr,"List element out of range: %d",element);
		return NULL;
	}
	Node search = list->head;
	int i;
	for(i=0; i<element; i++){
		search = search->next;
	}
	return search;
}

/**
 * Retrieves the item and the element number given.
 * Refer to list_get for other info.
 */
void* listGet(tateList list, int element){
	Node nod = list_get(list,element);
	return nod->data;
}

/**
 * Removes a node from the list at the element number given.
 * Returns 0 if the element number is out of range.
 * Returns 1 if node removal is successful.
 */
bool listRemove(tateList list, int element){
	if(element>=list->size || element<0){
		return false; //error
	}else if(element == list->size-1 && element == 0){
		Node nod = list->head;
		freeNode(nod);
		list->size-=1;
		list->head=NULL;
		list->tail=NULL;
		return true;
	}else if(element == 0){
		Node nod = list->head;
		list->head=nod->next;
		nod->next->prev=NULL;
		freeNode(nod);
		list->size-=1;
		return true;//success
	}else if(element == (list->size)-1){
		Node nod = list->tail;
		nod->prev->next = NULL;
		list->tail = list->tail->prev;
		freeNode(nod);
		list->size-=1;
		return true;//success
	}else{
		Node nod = list->head;
		int i;
		for(i=0; i<element; i++){
			nod = nod->next;
		}
		nod->next->prev = nod->prev;
		nod->prev->next = nod->next;
		freeNode(nod);
		list->size-=1;
		return true;//success
	}
}

/**
 * Returns the size of the list.
 */
int listSize(tateList list){
	return list->size;
}

/**
 * Frees the list from memory by first removing all the nodes
 * and then free the list ptr.
 */
void listFree(tateList list){
	int i;
	int init_size = listSize(list);
	for(i=0; i<init_size; i++){
		listRemove(list,0);
	}
	freeNode(list->head);
	freeNode(list->tail);
	free(list);
}
Here is the header file tate_list.h
Code:
/*
 * tate_list.h
 *
 *  Created on: Jan 7, 2010
 *      Author: Tate Exon
 */

#ifndef TATE_LIST_H_
#define TATE_LIST_H_

#include "tate_bool.h"

//--List struct pointers--//
typedef struct tate_list* tateList;

//--List methods--//
tateList newList();
bool listAdd(tateList list, void* data);
void* listGet(tateList list, int element);
int listSize(tateList list);
bool listRemove(tateList list, int element);
void listFree(tateList list);

#endif /* TATE_LIST_H_ */
And here is the header file tate_bool.h that contains my bool implementation to give c a c++ feel and is used in both of my list files.
Code:
//tate_bool.h
// Create a type boolean similar to that in c++

#ifndef TATE_BOOL_H_
#define TATE_BOOL_H_

typedef enum bool{
	true = 1,
	false = 0
}bool;

#endif /* TATE_BOOL_H_ */
Now I wouldn't take this code and copy paste it for use since it is not the best way to implement a linked list, just use it to get an idea of how you can implement it. Enjoy!