A contact database using a dynamic-single linked list in ANSI C

majestic0110 1 Tallied Votes 10K Views Share

Hi all, here is a small program I have worked on over these last two days, I have submitted it in the hopes of some constructive criticism and suggestions (please be kind, this is one of my earlier C projects lol). This is a small console application that simulates a contact management database. The data that a user inputs is saved to an external dat file (contactdatabase.dat) which is created the first time a user saves and exits. This project also employs the use of Malloc(), which is used to allocate memory on the fly (at runtime) for dynamic data structures, in this case a single linked list. Upon entering a new contact, a unique ID account number is allocated to that contact. Note that at present, if this contact is removed, that ID account is NOT freed up for use by an additional (new) contact. I hope you all find this interesting and useful, I think the comments explain pretty well what is going on in the program, so those who are new to C will appreciate this most:
P.S. Sorry if the formatting does not look that tidy, I have tried to EDIT it so now It looks better.

/*Contact Management Database using a dynamic - single linked list
Author : P J Wells
Compiled on Dev-C++, Bloodshed Software.
Date : 03/04/08
*/

/*----------------------------------------------------------------------------*/
/* Define libraries to be included */
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
/*----------------------------------------------------------------------------*/
/* Define Functions*/
void clearInput(void);
void addNewcontact(void);
void listAll(void);
void deletecontact(void);
void modifycontact(void);
int findcontact(void);
int prompt(void);
int findnum (int);

/*----------------------------------------------------------------------------*/
/* Define Structures*/

typedef struct contact {   
    int number;        /*unique account number*/
    char name[20];     /*contains name*/  
    char phone[15];    /*contains phone number*/
    char email[20];           /*contains email address*/
    struct contact *next; /*next is used to navigate through structures.*/ 
    int count;     /*count is used to input comments into array*/    
    } Contact;
Contact *firstc,*currentc,*newc; /*pointers*/
/* firstc is used to point to first record in list
currentc points to current record in list
newc contains address of new structure/node 
*/
int cnum = 0; /*gives unique account numbers*/


/*----------------------------------------------------------------------------*/
/* Main Function */

int main()
{
    FILE *datafile;
    char *filename = "contactdatabase.dat";/*declare file name*/
    char ch;
    firstc = NULL;

    datafile = fopen(filename,"r");/* open file for reading*/
    
    if(datafile)	 
    {
	    firstc = (struct contact *)malloc(sizeof(struct contact));
    /*use of malloc to set aside memory relative to size of structure contact*/
	    currentc = firstc;       /*make first record current*/
	    while(1) /*endless while loop. a NULL pointer in final node ends loop*/
     	    {
		    newc = (struct contact *)malloc(sizeof(struct contact));
		    fread(currentc,sizeof(struct contact),1,datafile);
		    if(currentc->next == NULL)   /* NULL indicates end of node list*/
			    break;
		    currentc->next = newc;       /* pointer referencing next node*/
            currentc->count=0;           /* initiates count for comments*/
		    currentc = newc;             /* make current record new*/
	    }
	    fclose(datafile);                /* close file - good practice to cloe files after use*/
	    cnum = currentc->number;         
        
    }
        
    do
    {
	fflush(stdin);
        puts("\nWelcome To The Contact Database");/* print menu messages*/
        puts("-- -----------------------------");
        puts("1 - Add a new contact");     
	puts("2 - Delete contact");          
	puts("3 - List all contacts");       
	puts("4 - Modify contact");          
	puts("5 - Find a contact by name");  
	puts("-- -----------------------------");
        puts("Q - Save and quit\n");         
        printf("\tYour choice:");            
        ch = getchar();
	    ch = toupper(ch);/*changes user input case to upper case*/
        switch(ch)     /*stores in ch variable.*/
        {
            case '1':
                puts("Add a new contact\n");
	        fflush(stdin);
                addNewcontact();//call addNewcontact function 
                break;
	    case '2':
		puts("Delete a contact\n");
		deletecontact();
		break;
	    case '3':
		puts("List all contacts\n");
		listAll();
		break;
	    case '4':
		puts("Modify a contact\n");
		modifycontact();
		break;
	    case '5':
		puts("Find a contact by name\n");
		findcontact();
		break;
            case 'Q':
                puts("Save and quit\n");
                default:
                break;
        }
    }
    while(ch != 'Q');

/*
 * Save the records to disk
 */
    currentc = firstc;
    
    if(currentc == NULL)
	    return(0);		/*no data to write*/
				  
    datafile = fopen(filename,"w");   /*open file to write*/
    
    if(datafile == NULL)
    {
	    printf("Error writing to %s\n",filename);
	    return(1);
    }
    				/* Write each record to disk*/ 
    while(currentc != NULL)
    {
	    fwrite(currentc,sizeof(struct contact),1,datafile);
	    currentc = currentc->next;
    }
    fclose(datafile);             /*closes data file*/
    return(0);
}
/*----------------------------------------------------------------------------*/
void addNewcontact(void) /* add new contact function*/
{
    newc = (struct contact *)malloc(sizeof(struct contact)); 
    /*allocates memory for new structure.*/

/*
 * Checks to see whether this is the first record in file
 * If so, then all pointers are initialized to this record,
 */

    if(firstc==NULL)
        firstc = currentc = newc;

/* 
 * if not, end of structure list is obtained
 */

    else
    {
        currentc = firstc;      /* make the first record the current one*/ 
                                

        while(currentc->next != NULL)currentc = currentc->next;
                                /* and loop through all records*/ 
        currentc->next = newc;  /* pointer to next node */
        currentc = newc;        /* make current record the new one*/ 
    }

/* update the structure */

    cnum++;
    printf("%27s: %5i\n","contact number",cnum);
    currentc->number = cnum;    /*cnum is used to give unique account numbers*/
    
    printf("%27s: ","Enter contact name");
    gets(currentc->name);

    printf("%27s: ","Enter contact Phone number");
    gets(currentc->phone);

    printf("%27s: ","Enter contact email");
    gets(currentc->email);
    printf("contact added!");
    currentc->count=0;

/* 
 * gives the new record a NULL pointer
 * to show it's the last record:
 */

    currentc->next = NULL;
}
/*----------------------------------------------------------------------------*/
void listAll(void) /* list all contacts function*/
{
    if(firstc==NULL)
        puts("There are no contacts to display!"); /*prints message*/
        
    else
    {
	    printf("%6s %-20s %-15s %-15s\n","Acct#","Name","Phone","Email");
        puts("------ -------------------- ------------- -------------------");           
                            /*prints table titles*/
        currentc=firstc;
        
        do
        {
        
                printf("%6d: %-20s %-15s %-20s\n",\
                currentc->number,\
                currentc->name,\
                currentc->phone,\
                currentc->email); 
                /*prints values of number, name, phone and email*/
        }
        
        while((currentc=currentc->next) != NULL);
    }
}
/*----------------------------------------------------------------------------*/
void deletecontact(void)     /*delete contact function */          
{
    int record;
    struct contact *previousa;

    if(firstc==NULL)
    {
        puts("There are no contacts to delete!");
	return;
    }
    
    listAll();		/* show all records*/  
    printf("Enter contact account number to delete: ");
    scanf("%d",&record);

    currentc = firstc;
    
    while(currentc != NULL)
    {
        if(currentc->number == record)
	{
	    if(currentc == firstc)	/*if record to be deleted is the first record*/
		firstc=currentc->next; /*reset firstc to point at next record as first*/
	    else
		previousa->next = currentc->next;/*previous pointer used if record*/ 
                                         /*to delete is not the first*/
        free(currentc); /*frees memory <deletes>*/
	    printf("contact %d deleted!\n",record);
	    return;
	}
	
	else
	{
        previousa = currentc;
	    currentc = currentc->next;
	}
    }
    printf("contact %d not found!\n",record);
 }
/*----------------------------------------------------------------------------*/
void modifycontact(void)   /*modify contact function*/
{
    int record, result;

    if(firstc==NULL)
    {
        puts("There are no contacts to modify!");
	return;
    }
    
    listAll();		/* show all records */
    printf("Enter contact account number to modify or change: ");
    scanf("%d",&record);  /*scan user input to record*/

    result = findnum(record);
    
    if( result >0 ){
	    printf("Contact %d:\n",currentc->number);
	    printf("Name: %s\n",currentc->name);
	    if(prompt())
		    gets(currentc->name);
	    printf("Phone: %s\n",currentc->phone);
	    if(prompt())
		    gets(currentc->phone);
	    printf("Email: %s\n",currentc->email);
	    if(prompt())
		    gets(currentc->email);
	    return;
	}
    printf("contact %d was not found!\n",record);
}
/*----------------------------------------------------------------------------*/
int findnum (int recordnum)
{
    int record;
    record = recordnum;
    currentc = firstc;
    while(currentc != NULL)
    {
                   
        if(currentc->number == record)
	     {
           return 1;
         }
         
	else
	{
	    currentc = currentc->next;
	}
    }
    return -1;   
}
/*----------------------------------------------------------------------------*/
int findcontact(void) /* find contact function*/
{
     char buff[20];
     
     if(firstc==NULL)
	{
        puts("There are no contacts to find!");
	    return 1;
    }
    
    printf("Enter contact name: ");
    fflush(stdin);/*clears any text from the input stream*/
    gets(buff);
    
    currentc = firstc;
    while(currentc != NULL)
    {
        if( strcmp(currentc->name, buff) == 0 )
	    {
			printf("%6s %-20s %-15s %-15s\n","Acct#","Name","Phone","Email");
			/*prints table titles*/
            printf("%6d: %-20s %-15s %-20s\n",\
            currentc->number,\
            currentc->name,\
            currentc->phone,\
            currentc->email); 
            /*prints values of number, name, phone and email*/
			
			return 0;
	    }
		else
		{
			currentc = currentc->next;
		}
    }
    printf("contact %s was not found!\n",buff);
          return 1;
}   
/*----------------------------------------------------------------------------*/
int prompt(void)
{
	char ch;

    fflush(stdin);
	printf("Update? (Y to update any other key to not)");
	ch = getchar();
	ch = toupper(ch);
	fflush(stdin);
	if(ch == 'Y')
	{
		printf("Enter new value: ");
		return(1);
	}
	else
		return(0);
}
/*----------------------------------------------------------------------------*/

/* END OF PROGRAM */
chandaksach@gma 0 Newbie Poster

Hi
I had worked with the above code .. In this code program is working fine but only its not reading name which is being given by user .. plz check ur code again ..
And do send correct code ..

majestic0110 187 Nearly a Posting Virtuoso

Name is working fine here just tested it again. Specifically what issue are you having?

Nikul Devis 0 Newbie Poster

Hi
It would have been a bit more nice in the find contact part if the file contains contactname "Jason" and to find "Jas" and "Jason" would appear since the first letters corresponds to "Jason". Just like in searching in mobile phones. Just a suggestion though.

zipa72 0 Newbie Poster

As you said, this is one of your first projects - a small one, but it is a project. I would like to share with you some pointers that will make your life easier when you move to larger projects, or even when this (the small one) starts growing.

  • Be consistent with the variable and function names. Try to find some guidelines on naming conventions and adopt one that works for you. For example, functions addNewcontact, listAll, deletecontact are inconsistent in using capital letters. I have to commend your effort to keep variable and function names descriptive.

  • Whenever you see a large piece of code, let's say more than a screen or two, step back and think about it: Is this a time to split it into functional units? Can this code be reused? It might be the time to refactor your code and extract the functionality to a function. You did a good job in your switch block (moving the individual functionality to functions), so use that instinct for the rest of your code. For example, at the beginning of the main(), you have a loop that reads contacts from a file. Would it be useful in the future to have a "reset" functionality that will reload everything from the file again? Instead of having a large while block, you could call a function (readDataFile, for example), keeping the functionality for reading from a file in a separate, more manageable place.
    Following that example, you could virtually minimise your main() function to several variable declarations and four function calls: openDataFile(), readDataFile(), processCommands(), writeDataFile(). Anyway, by extracting the writeDataFile to a function, you would be able to write to the file every time you make a change, making your application more robust, and all of that by using the same method!

I hope this is the kind of response you expected and that it will help you with your progress.

Gribouillis 1,391 Programming Explorer Team Colleague

Majestic0100 is probably working on another project now as this thread was started 8 years ago!

Baneeishaque 15 Newbie Poster

an updated version : BuetoothDevices_C

rproffitt commented: Why here? Over a decade later. Buried here, no one may find this. Try a new tutorial? +15
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.