First of, the argument passing of theList is wrong. In case that the list is still empty, you were expecting to pass NULL for theList. But how do you then return the new element that is being allocated in that call?
The solution is to pass
int addContact(struct contact **theList)
{
...
curr = *theList;
Now to the end of your function. What you want to test is whether curr is NULL, hence the list is still empty. In that case you want to place the pointer to the first element into the list anchor:
if (curr == 0)
{
*theList = newContact;
newContact->next = NULL;
newContact->prev = NULL:
}
else
...
By the way, I doubt that your code will compile. Is newContact really a member of you contact structure?
[AMENDED]
And your calling code should look like this:
struct contact* ptrHead = 0;
...
addContact (&ptrHead);
...
writeListToFile ("test.csv", ptrHead);
What I was wondering about is: Why are keeping a doubly linked list, but have only a single head pointer? The advantage of a doulbe linked is that you can traverse it in both directions. An additional pointer to the last element in the list would make that easy and also support your append operation; it would save you from looping over the entire list to find the last element. But first let's find the little bug that keeps it from working.