当前位置:网站首页>Simple C language address book

Simple C language address book

2022-06-11 14:42:00 qq_ forty-two million one hundred and twenty thousand eight hun

C Language address book

The main function

  • Add a person
  • Print shows all people
  • Delete a person
  • Find a person
  • Save the file
  • Load the file

Architecture design

I think for me, a rookie who doesn't have an overall design, this design method really brightens my eyes .

The main design is to divide the program into three supporting layers 、 Interface layer and business logic layer , Each layer will only use the functions provided by the layer below it , For example, business layer functions will call interface layer functions , The functions of the interface layer call the functions of the support layer , It will not let the business layer directly call the functions of the support layer .

 Insert picture description here

Source code

/* * 2022 year 6 month 7 Japan 10:29:41 *  Address book management system  *  Three layers : Support layer 、 The interface layer 、 Business logic layer  *  Two way linked list as data structure  * * */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// Using macro definition to make program code more intuitive 
#define NAME_LENGTH 16
#define PHONE_LENGTH 32
#define BUFFER_LENGTH 128
// The minimum value for reading a line of data from a file is 5, namely name:
#define MIN_TOKEN_LENGTH 5

// For future improvements , The function change of output information can be modified as a whole as long as it is modified here 
#define INFO printf

// Use macro definition to realize the operation of support layer , Note that the macro definition is a direct replacement 
// take item Insert list List the head 
//LIST_INSERT(ps, *ppeople) When here list yes *pperson, The type is (struct person *) Direct replacement 
// To list Adding parentheses is equivalent to (*pperson)
#define LIST_INSERT(item, list) do{
       \ item->prev = NULL; \ item->next = list; \ if((list) != NULL) (list)->prev = item; \ (list) = item; \ }while(0)

#define LIST_REMOVE(item ,list) do{
       \ if(item->prev != NULL) item->prev->next = item->next; \ if(item->next != NULL) item->next->prev = item->prev; \ if(item == list) list = item->next; \ item->prev = item->next = NULL; \ }while(0) //  Only once 

struct person
{
    
    char name[NAME_LENGTH];
    char phone[PHONE_LENGTH];

    struct person *next;
    struct person *prev; // The design is a two-way linked list , Easy to delete nodes 

};

// Address book class , It is equivalent to a management class 
struct contacts
{
    
    struct person *people; //  Point to the address list 
    int count;

};

enum {
    
    OPER_INSERT = 1,
    OPER_PRINT,
    OPER_DELETE,
    OPER_SEARCH,
    OPER_SAVE,
    OPER_LOAD
};

//define interface , The interface layer will use the functions of the support layer 
int person_insert(struct person **ppeople, struct person *ps)
{
    
    if(ps == NULL)  return -1;

    LIST_INSERT(ps, *ppeople);
    return 0;
}

int person_delete(struct person **ppeople, struct person *ps)
{
    
    if(ps == NULL)  return -1;

    LIST_REMOVE(ps, *ppeople);
    return 0;
}

struct person * person_search(struct person *people, const char *name)
{
    
    struct person *item = NULL;
    for(item = people; item != NULL; item = item->next)
    {
    
        //strcmp Equal to 0
        if(!strcmp(name, item->name))
            break;
    }
    return item;
}

int person_traverse(struct person *people)
{
    
    struct person *item = NULL;
    for(item = people; item != NULL;item = item->next)
    {
    
        INFO("name: %s,phone: %s\n", item->name, item->phone);
    }
    return 0; //  Successfully returns 0
}

// Put the address book ( Linked list )people Save information to file filename in 
int save_file(struct person *people, const char *filename)
{
    
    FILE *fp = fopen(filename, "w");
    if(fp == NULL)  return -1;
    struct person *item = NULL;
    for(item = people; item != NULL; item = item->next)
    {
    
        fprintf(fp, "name: %s, phone: %s\n", item->name, item->phone);
        fflush(fp); //  Refresh content to disk , The previous content is to write to the buffer ( Memory ) in 
    }
    
    fclose(fp);
}

//@length: by buffer Actual length ( A contact's record )
int parser_token(char *buffer, int length, char *name, char *phone)
{
    
    if(buffer == NULL)  return -1;
    if(length < MIN_TOKEN_LENGTH)   return -2;

    int i = 0, j = 0, status = 0;
    // The obtained data content is in the form of name: wangbojing,telephone: 15889650380
    // Resolve the name 
    // Adopt the method of state machine 
    for(i = 0; buffer[i] != ',';++i)
    {
    
        // The state will change after encountering a space , After that, it's the name we want 
        if(buffer[i] == ' ')
        {
    
            status = 1;
        }
        else if(status == 1)
        {
    
            name[j++] = buffer[i];
        }
    } 

    status = 0;
    j = 0;
    for(;i < length; ++i)
    {
    
        if(buffer[i] == ' ')
        {
    
            status = 1;
        }
        else if(status == 1)
        {
    
            phone[j++] = buffer[i];
        }
    }
    INFO("file token : %s ---- %s\n", name, phone);
    return 0;
}

// take filename The data read from the file is written to ( Load into ) To the address book people in 
//count:contacts Members of the object , Change the number of contacts 
int load_file(struct person **ppeople, int *count,const char *filename)
{
    
    FILE *fp = fopen(filename, "r");  
    if(fp == NULL)
        return -1;

    //fp The internal pointer loops without being at the end of the file 
    while(!feof(fp))
    {
    
        char buffer[BUFFER_LENGTH] = {
    0};
        // from fp Read length in the file referred to BUFFER_LENGTH Data to buffer in , Stop at line breaks or endings 
        fgets(buffer, BUFFER_LENGTH, fp);
        int length = strlen(buffer);
        INFO("length : %d\n", length);

        //name: wangbojing,telephone: 15889650380
        char name[NAME_LENGTH] = {
    0};
        char phone[PHONE_LENGTH] = {
    0};

        // Failed to parse the content , Jump out of this cycle 
        if(0 != parser_token(buffer, length, name, phone))
        {
    
            continue;
        }

        // Insert address book ( Linked list )
        struct person *p = (struct person*)malloc(sizeof(struct person));
        if(p == NULL) return -2;

        //memcpy()  Will be copied  name  The front of the memory content  NAME_LENGTH  Byte to  p->name  On the memory address .
        memcpy(p->name, name, NAME_LENGTH);
        memcpy(p->phone, phone, PHONE_LENGTH);
        
        person_insert(ppeople, p);
        (*count)++;

    }
    fclose(fp);
    return 0;
}



//define interface end

// Implementation of business logic 
int insert_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;

    struct person *p = (struct person*)malloc(sizeof(struct person));
    memset(p, 0x00, sizeof(struct person));
    if(p == NULL)
        return -2;

    //name
    INFO("Please input name: \n");
    scanf("%s", p->name);
    
    //phone
    INFO("Please input phone: \n");
    scanf("%s", p->phone);
    
    //add people
    // If cts->people by NULL, What we want to change is cts->people Value , So you have to send the address 
    // so person_insert The first parameter here must be a second level pointer 
    if(0 != person_insert(&cts->people, p))
    {
    
        free(p);
        return -3;
    }
    cts->count++; // Number of contacts updated 
    
    INFO("insert success!\n");
    return 0;
}

int print_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;
    //cts->people

    person_traverse(cts->people);
    return 0;
}

int delete_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;
    //name
    INFO("Please input name: \n");
    char name[NAME_LENGTH] = {
    0};
    scanf("%s",name);

    //person
    // Find and then delete 
    struct person *ps = person_search(cts->people, name);
    if(ps == NULL)
    {
    
        INFO("Person don't exist!\n");
        return -2;
    }
    //delete
    // If you delete the last element or the first element ( First element )
    // Change people Value , So this parameter needs to be passed to the address 
    // So the parameter type is a two-level pointer struct person **
    person_delete(&cts->people, ps);
    free(ps);
    INFO("Delete success!\n");
    return 0;
}

int search_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;
    //name
    INFO("Please input name: \n");
    char name[NAME_LENGTH] = {
    0};
    scanf("%s",name);

    //person
    struct person *ps = person_search(cts->people, name);
    if(ps == NULL)
    {
    
        INFO("Person don't exist!\n");
        return -2;
    }
    
    INFO("name:%s, phone: %s\n",ps->name, ps->phone);
    return 0;
}

int save_entry(struct contacts * cts)
{
    
    if(cts == NULL) return -1;

    INFO("Please input save filename:\n");
    char filename[NAME_LENGTH] = {
    0};
    scanf("%s", filename);

    save_file(cts->people, filename);
}


int load_entry(struct contacts * cts)
{
    
    if(cts == NULL) return -1;

    INFO("Please input load filename:\n");
    char filename[NAME_LENGTH] = {
    0};
    scanf("%s", filename);

    load_file(&cts->people, &cts->count, filename);
}

void menu_info()
{
    
    INFO("\n******************************************************\n");
    INFO("*****1.Add Person\t\t2.Print Person *******\n");
    INFO("*****3.Del Person\t\t4.Search Person ******\n");
    INFO("*****5.Save Person\t\t6.Load Person ********\n");
    INFO("*****Other Key for Exiting Program *******************\n");
    INFO("\n******************************************************\n");
}   

int main()
{
    
    struct contacts *cts = (struct contacts*)malloc(sizeof(struct contacts));
    if(cts == NULL) return -1;
    // Initialize structure 
    memset(cts, 0x00, sizeof(struct contacts));
    while(1)
    {
    
        menu_info();
        int select = 0;
        scanf("%d", &select);

        switch(select)
        {
    
            // Call the functions of the business logic layer 
            case OPER_INSERT:
                insert_entry(cts);
                break;

            case OPER_PRINT:
                print_entry(cts);
                break;

            case OPER_DELETE:
                delete_entry(cts);
                break;
            
            case OPER_SEARCH:
                search_entry(cts);
                break;
            
            case OPER_SAVE:
                save_entry(cts);
                break;

            case OPER_LOAD:
                load_entry(cts);
                break;
            default:
                goto exit;
        }       
    }
exit:
    free(cts);
    return 0;
}

Code analysis

Linked list implementation and data structure definition

This program uses a two-way linked list to store the address book :

struct person
{
    
    char name[NAME_LENGTH];
    char phone[PHONE_LENGTH];

    struct person *next;
    struct person *prev; // The design is a two-way linked list , Easy to delete nodes 

};

Address book management class , Easy to operate

struct contacts
{
    
    struct person *people; //  Point to the address list 
    int count;

};

Implement the header insertion and deletion of the linked list in the interface layer , Note that the macro definition is a direct text substitution , Pay attention to brackets , Prevent problems caused by priorities .

#define LIST_INSERT(item, list) do{
       \ item->prev = NULL; \ item->next = list; \ if((list) != NULL) (list)->prev = item; \ (list) = item; \ }while(0)

#define LIST_REMOVE(item ,list) do{
       \ if(item->prev != NULL) item->prev->next = item->next; \ if(item->next != NULL) item->next->prev = item->prev; \ if(item == list) list = item->next; \ item->prev = item->next = NULL; \ }while(0) //  Only once 

Implementation of the functions of the data structure operation interface layer

//define interface , The interface layer will use the functions of the support layer 
// The reason why ppeople The second level pointer is used because , When the incoming if is NULL, That is, when the node is inserted for the first time 
// We need to change the value of its first level pointer .
int person_insert(struct person **ppeople, struct person *ps)
{
    
    if(ps == NULL)  return -1;

    LIST_INSERT(ps, *ppeople);
    return 0;
}

// If you delete last element , Then the pointer to the linked list ( Class A ) To be changed to NULL, So pass the secondary pointer 
int person_delete(struct person **ppeople, struct person *ps)
{
    
    if(ps == NULL)  return -1;

    LIST_REMOVE(ps, *ppeople);
    return 0;
}

struct person * person_search(struct person *people, const char *name)
{
    
    struct person *item = NULL;
    for(item = people; item != NULL; item = item->next)
    {
    
        //strcmp Equal to 0
        if(!strcmp(name, item->name))
            break;
    }
    return item;
}

int person_traverse(struct person *people)
{
    
    struct person *item = NULL;
    for(item = people; item != NULL;item = item->next)
    {
    
        // here INFO Is a macro definition 
        INFO("name: %s,phone: %s\n", item->name, item->phone);
    }
    return 0; //  Successfully returns 0
}

Implementation of business logic functions

Define different operations as anonymous enumerations instead of directly using numbers

enum {
    
    OPER_INSERT = 1,
    OPER_PRINT,
    OPER_DELETE,
    OPER_SEARCH,
    OPER_SAVE,
    OPER_LOAD
};

main Function provides users with the display and selection of functions :

void menu_info()
{
    
    INFO("\n******************************************************\n");
    INFO("*****1.Add Person\t\t2.Print Person *******\n");
    INFO("*****3.Del Person\t\t4.Search Person ******\n");
    INFO("*****5.Save Person\t\t6.Load Person ********\n");
    INFO("*****Other Key for Exiting Program *******************\n");
    INFO("\n******************************************************\n");
}   

int main()
{
    
    struct contacts *cts = (struct contacts*)malloc(sizeof(struct contacts));
    if(cts == NULL) return -1;
    // Initialize structure 
    memset(cts, 0x00, sizeof(struct contacts));
    while(1)
    {
    
        menu_info();
        int select = 0;
        scanf("%d", &select);

        switch(select)
        {
    
            // Call the functions of the business logic layer 
            case OPER_INSERT:
                insert_entry(cts);
                break;

            case OPER_PRINT:
                print_entry(cts);
                break;

            case OPER_DELETE:
                delete_entry(cts);
                break;
            
            case OPER_SEARCH:
                search_entry(cts);
                break;
            
            case OPER_SAVE:
                save_entry(cts);
                break;

            case OPER_LOAD:
                load_entry(cts);
                break;
            default:
                goto exit;
        }       
    }
exit:
    free(cts);
    return 0;
}

Function implementation of business logic layer

// Implementation of business logic 
int insert_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;

    struct person *p = (struct person*)malloc(sizeof(struct person));
    memset(p, 0x00, sizeof(struct person));
    if(p == NULL)
        return -2;

    //name
    INFO("Please input name: \n");
    scanf("%s", p->name);
    
    //phone
    INFO("Please input phone: \n");
    scanf("%s", p->phone);
    
    //add people
    // If cts->people by NULL, What we want to change is cts->people Value , So you have to send the address 
    // so person_insert The first parameter here must be a second level pointer 
    if(0 != person_insert(&cts->people, p))
    {
    
        free(p);
        return -3;
    }
    cts->count++; // Number of contacts updated 
    
    INFO("insert success!\n");
    return 0;
}

int print_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;
    //cts->people

    person_traverse(cts->people);
    return 0;
}

int delete_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;
    //name
    INFO("Please input name: \n");
    char name[NAME_LENGTH] = {
    0};
    scanf("%s",name);

    //person
    // Find and then delete 
    struct person *ps = person_search(cts->people, name);
    if(ps == NULL)
    {
    
        INFO("Person don't exist!\n");
        return -2;
    }
    //delete
    // If you delete the last element or the first element ( First element )
    // Change people Value , So this parameter needs to be passed to the address 
    // So the parameter type is a two-level pointer struct person **
    person_delete(&cts->people, ps);
    free(ps);
    INFO("Delete success!\n");
    return 0;
}

int search_entry(struct contacts *cts)
{
    
    if(cts == NULL) return -1;
    //name
    INFO("Please input name: \n");
    char name[NAME_LENGTH] = {
    0};
    scanf("%s",name);

    //person
    struct person *ps = person_search(cts->people, name);
    if(ps == NULL)
    {
    
        INFO("Person don't exist!\n");
        return -2;
    }
    
    INFO("name:%s, phone: %s\n",ps->name, ps->phone);
    return 0;
}

Interface layer implementation of file saving and loading

Saving is to store the data on the linked list to a disk file , Loading is to read the contact data from the disk file and insert it into the linked list

File saving interface layer implementation

// Put the address book ( Linked list )people Save information to file filename in 
int save_file(struct person *people, const char *filename)
{
    
    FILE *fp = fopen(filename, "w");
    if(fp == NULL)  return -1;
    struct person *item = NULL;
    for(item = people; item != NULL; item = item->next)
    {
    
        fprintf(fp, "name: %s, phone: %s\n", item->name, item->phone);
        fflush(fp); //  Refresh content to disk , The previous content was just written to the buffer ( Memory ) in 
    }
    
    fclose(fp);
}

File loading interface layer implementation

here , We need to parse the name and phone number from the file , What we have on disk is shaped like :

name: wangbojing,telephone: 15889650380

According to this format ,

  1. We can parse the name and phone number into two parts through commas, namely name: wangbojing and telephone: 15889650380

  2. Then according to the finite state machine , The initial state is 0, When a space is encountered, the status changes to 1, The non space characters encountered later are names

    The same is true of telephone number resolution .

//@length: by buffer Actual length ( A contact's record )
int parser_token(char *buffer, int length, char *name, char *phone)
{
    
    if(buffer == NULL)  return -1;
    if(length < MIN_TOKEN_LENGTH)   return -2;

    int i = 0, j = 0, status = 0;
    // Resolve the name 
    // Adopt the method of state machine 
    for(i = 0; buffer[i] != ',';++i)
    {
    
        // The state will change after encountering a space , After that, it's the name we want 
        if(buffer[i] == ' ')
        {
    
            status = 1;
        }
        else if(status == 1)
        {
    
            name[j++] = buffer[i];
        }
    } 

    status = 0;
    j = 0;
    for(;i < length; ++i)
    {
    
        if(buffer[i] == ' ')
        {
    
            status = 1;
        }
        else if(status == 1)
        {
    
            phone[j++] = buffer[i];
        }
    }
    INFO("file token : %s ---- %s\n", name, phone);
    return 0;
}

Interface layer implementation of loading file :

// take filename The data read from the file is written to ( Load into ) To the address book people in 
//count:contacts Members of the object , Change the number of contacts 
int load_file(struct person **ppeople, int *count,const char *filename)
{
    
    FILE *fp = fopen(filename, "r");  
    if(fp == NULL)
        return -1;

    //fp The internal pointer loops without being at the end of the file 
    while(!feof(fp))
    {
    
        char buffer[BUFFER_LENGTH] = {
    0};
        // from fp Read length in the file referred to BUFFER_LENGTH Data to buffer in , Stop at line breaks or endings 
        fgets(buffer, BUFFER_LENGTH, fp);
        int length = strlen(buffer);
        INFO("length : %d\n", length);

        //name: wangbojing,telephone: 15889650380
        char name[NAME_LENGTH] = {
    0};
        char phone[PHONE_LENGTH] = {
    0};

        // Failed to parse the content , Jump out of this cycle 
        if(0 != parser_token(buffer, length, name, phone))
        {
    
            continue;
        }

        // Insert address book ( Linked list )
        struct person *p = (struct person*)malloc(sizeof(struct person));
        if(p == NULL) return -2;

        //memcpy()  Will be copied  name  The front of the memory content  NAME_LENGTH  Byte to  p->name  On the memory address .
        memcpy(p->name, name, NAME_LENGTH);
        memcpy(p->phone, phone, PHONE_LENGTH);
        
        person_insert(ppeople, p);
        (*count)++;

    }
    fclose(fp);
    return 0;
}

The business logic layer implementation of file saving and loading

int save_entry(struct contacts * cts)
{
    
    if(cts == NULL) return -1;

    INFO("Please input save filename:\n");
    char filename[NAME_LENGTH] = {
    0};
    scanf("%s", filename);

    save_file(cts->people, filename);
}


int load_entry(struct contacts * cts)
{
    
    if(cts == NULL) return -1;

    INFO("Please input load filename:\n");
    char filename[NAME_LENGTH] = {
    0};
    scanf("%s", filename);

    load_file(&cts->people, &cts->count, filename);
}

Experience

This program function makes the design very clear through the three-tier design method , At the same time, macro definition is used to enhance readability , For me, it has deepened some experience of program development , Broaden your horizons .

原网站

版权声明
本文为[qq_ forty-two million one hundred and twenty thousand eight hun]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206111426450419.html