【C】通訊錄(鏈表+數據庫存儲)

/*****************************************************
copyright (C), 2014-2015, Lighting Studio. Co.,     Ltd. 
File name:
Author:Jerey_Jobs    Version:0.1    Date: 
Description:
Funcion List: 
*****************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>


void get_name(char*);
void get_num(char*,int);
void get_address(char*);
char get_check(char*);

struct node
{
    char name[20];
    char hometel[9];
    char phone[12];
    char address[100];

    struct node * next;
};

typedef struct node Node;
typedef struct node * Link;



void welcome()
{
    printf(" =============================================================================\n");
    printf("|                                                                             |\n");
    printf("|                                  通訊錄                                     |\n");
    printf("|                                                                             |\n");
    printf(" =============================================================================\n");
    printf("|                                                                             |\n");
    printf("|              1 顯示通訊錄                   2 添加聯繫人信息                |\n");
    printf("|              3 刪除聯繫人信息               4 查找聯繫人信息                |\n");
    printf("|              5 修改聯繫人信息               6 退出                          |\n");
    printf("|                                                                             |\n");
    printf(" =============================================================================\n");
    printf("\n");
    printf("請輸入操作對應的數字:");
}

void create_node(Link *new_node)
{
    int count = 10;

    do
    {
        *new_node = (Link)malloc(sizeof(Node));
        count--;
    }while(!is_malloc_ok(*new_node) && count);
}

void create_link(Link *head)
{
    create_node(head);
    (*head)->next = NULL;
}

int is_malloc_ok(Link new_node)
{
    if(new_node == NULL)
    {
        printf("malloc error!\n");
        return 0;
    }
    return 1;
}

void insert_node_and_sort(Link head,Link new_node)
{
    Link p = head->next;
    Link q = head;

    if(p == NULL)
    {
        new_node->next = head->next;
        head->next = new_node;
    }
    else
    {                                                                                                                                                                                                                                                               
        while(p != NULL && strcmp(p->name,new_node->name) < 0)
        {
            q = p;
            p = p->next;
        }

        if(p == NULL)
        {
            new_node->next = p;
            q->next = new_node;
        }
        else
        {
            q->next = new_node;
            new_node->next = p;
        }
    }

}

void display(Link head)
{
    if(head == NULL)
    {
        printf("鏈表已經完全釋放!\n");
        return;
    }

    Link p = head->next;

    if(p == NULL)
    {
        printf("通訊錄爲空!\n");
    }
    else
    {
        printf("\t聯繫人姓名\t座機號\t\t手機號\t\t家庭地址\n");
        printf("-------------------------------------------------------------\n");
        while(p != NULL)
        {
            printf("\t%s\t\t%s\t%s\t%s\n",p->name,p->hometel,p->phone,p->address);
            p = p->next;
        }
    }
}

void clear_screen()
{
    char str;

    printf("\n已成功執行,請按回車鍵繼續操作\n");
    my_get(&str,1);
    system("clear");
    welcome();
}

void create_new_contact(Link head,Link *new_node)
{
    char str[2];
    
    do{

        create_node(new_node);
        printf("請輸入新聯繫人的\n姓      名 :");
        get_name((*new_node)->name);
       // scanf("%s",(*new_node)->name);
        printf("座  機  號 :");
        get_num((*new_node)->hometel,9);
       // scanf("%s",(*new_node)->hometel);
        printf("手  機  號 :");
        get_num((*new_node)->phone,12);
       // scanf("%s",(*new_node)->phone);
        printf("家 庭 地 址:");
       // scanf("%s",(*new_node)->address);
        get_address((*new_node)->address);

        insert_node_and_sort(head,*new_node);

        printf("\n保存成功!是否要繼續輸入?(Y/N):");
        get_check(str);

        printf("\n");

    }while(strcmp(str,"Y") == 0);
    
}


void delete_contact(Link head)
{
    char str[20];
    char str1[2];

    do
    {
        printf("請輸入你想刪除的聯繫人的姓名:");
        //scanf("%s",str);
        get_name(str);

        //delete_node(head,str);

///////////////////////////
        Link p = head->next;
        Link q=head;
    
    
        while(p != NULL && strcmp(p->name,str) != 0)
        {
            q = p;
            p = p->next;
        }

        if(p == NULL)
        {
            printf("\n抱歉,未找到你想刪除的聯繫人,請確認是否輸入正確\n");
        }
        else
        {
            q->next = p->next;
            free(p);
        }

///////////////////////////////

        printf("\n是否繼續刪除?(Y/N):");
        get_check(str1);
        printf("\n");
    }while(strcmp(str1,"Y") == 0);

}


void delete_node(Link head,char str[])
{
    Link p = head->next;
    Link q=head;
    
      
    while(p != NULL && strcmp(p->name,str) != 0)
    {
        q = p;
        p = p->next;
    }

    if(p == NULL)
    {
        printf("抱歉,未找到你想刪除的聯繫人,請確認是否輸入正確\n");
    }
    else
    {
        q->next = p->next;
        free(p);
        printf("刪除成功!");
    }
}

void find_contact(Link head)
{
    char str[20];
    char str1[2];
    Link p = head->next;

    do{

    printf("請輸入你想查找的聯繫人的姓名:");
    //scanf("%s",str);
    get_name(str);

    while(p != NULL && strcmp(str,p->name) != 0)
    {
        p = p->next;
    }

    if(p == NULL)
    {
        printf("抱歉,未找到你想查找的聯繫人,請確認輸入是否正確\n");
    }
    else
    {
        printf("\n該聯繫人信息:\n");
        printf("姓      名 :%s\n",p->name);
        printf("座  機  號 :%s\n",p->hometel);
        printf("手  機  號 :%s\n",p->phone);
        printf("家 庭 地 址:%s\n",p->address);
    }
          printf("\n是否繼續查詢?(Y/N):");
          get_check(str1);
          printf("\n");
      }while(strcmp(str1,"Y") == 0);

}

void alter_contact(Link head)
{
    char str[20];
    char str1[50];
    char str2[2];
    char str3[2];
    int num;
    Link p =head->next;
    
    do
    {
        printf("1 按姓名修改      2 按座機號修改\n請輸入選項: ");
        //scanf("%d",&num);
        num = get_mode(str3,2);

        switch(num)
        {
            case 1:
                printf("請輸入你想修改的聯繫人的姓名:");
                //scanf("%s",str);
                get_name(str);

                while(p != NULL && strcmp(str,p->name) != 0)
                {
                    p = p->next;
                }
            
                if(p == NULL)
                {
                    printf("抱歉,未找到你想修改的聯繫人,請確認輸入是否正確\n");
                }
                else
                {
                    printf("\n該聯繫人信息:\n");
                    printf("姓      名 :%s\n",p->name);
                    printf("座  機  號 :%s\n",p->hometel);
                    printf("手  機  號 :%s\n",p->phone);
                    printf("家 庭 地 址:%s\n",p->address);
                

                    printf("請修改:\n");
                    printf("請輸入聯繫人的\n姓      名 :");
                    get_name(p->name);
                    printf("座  機  號 :");
                    get_num(p->hometel,9);
                    printf("手  機  號 :");
                    get_num(p->phone,12);
                    printf("家 庭 地 址:");
                    get_address(p->address);
                }
                break;

            case 2:
                printf("請輸入你想修改的聯繫人的座機號:");
                get_num(str,9);

                while(p != NULL && strcmp(str,p->hometel) != 0)
                {
                    p = p->next;
                }
            
                if(p == NULL)
                {
                    printf("抱歉,未找到你想修改的聯繫人,請確認輸入是否正確\n");
                }
                else
                {
                    printf("\n該聯繫人信息:\n");
                    printf("姓      名 :%s\n",p->name);
                    printf("座  機  號 :%s\n",p->hometel);
                    printf("手  機  號 :%s\n",p->phone);
                    printf("家 庭 地 址:%s\n",p->address);
                

                    printf("請修改:\n");
                    printf("請輸入聯繫人的\n姓      名 :");
                    get_name(p->name);
                    printf("座  機  號 :");
                    get_num(p->hometel,9);
                    printf("手  機  號 :");
                    get_num(p->phone,12);
                    printf("家 庭 地 址:");
                    get_address(p->address);
                }
                break;

        }
            printf("\n是否繼續修改?(Y/N):");
            get_check(str2);
            printf("\n");
   
    }while(strcmp(str2,"Y") == 0);
}

int my_get(char str[],int length)   //length爲存放的最長長度
{
    int i;

    for(i = 0; i < length ; i++)
    {
        str[i] = getchar();
        if(str[i] == '\n')
        {
            str[i] = '\0';
            return i;
        }
    }

    while(getchar() != '\n');
    str[i - 1] = '\0';
    return -1;

}



int check_name(char *str)
{
    char *p = str;

    if(*p == '\0')          //不加的話,如果輸入姓名直接打回車鍵它是會認爲沒有錯的。
    {                       //因爲my_get會把回車改爲'\0',而姓名輸入又不像數字輸入一樣有長度限制(就是確定的長度)
        return 0;
    }

    while(*p != '\0')
    {
        if(!((*p >= 'a' && *p <= 'z') || (*p >= 'A' &&*p <= 'Z')))
        {
            return 0;
        }
        p++;
    }

    return 1;
    
}

int check_num(char *str)
{
    char *p = str;

    while(*p != '\0')
    {
        if(!(*p >= '0' && *p <= '9'))
        {
            return 0;
        }
        p++;
    }

    return 1;
}

int check_mode(char *str,int num)
{
    if(*str >= '1' && *str <= '0'+num)
    {
        return 1;
    }
    
    return 0;
}

int check_check(char *str)
{
    if(*str == 'Y' || *str == 'N')
    {
        return 1;
    }

    return 0;
}

void get_name(char *str)
{
    while(my_get(str,20) == -1 || check_name(str) == 0)
    {
        if(check_name(str) == 0)
        {
            printf("姓名中出現除大小寫以外字母,");
        }
        else
        {
            printf("姓名太長超出規定範圍,");
        }
        printf("格式不符合要求,請重新輸入:");
    }
}

void get_num(char *str, int length)
{
    while(my_get(str,length) != length - 1 || check_num(str) == 0)
    {
        if(check_num(str) == 0)
        {
            printf("出現非數字的字符,");
        }
        else
        {
            printf("需輸入%d位的號碼,", length - 1);
        }
        printf("格式不符合要求,請重新輸入:");
    }
}

void get_address(char *str)
{
    while(my_get(str,100) == -1)
    {
        printf("地址太長超出規定範圍,請重新輸入:");
    }
}

int get_mode(char *str,int num)
{
    while(my_get(str,2) == -1 || check_mode(str,num) == 0)
    {
        printf("請輸入1-%d之間的數字:",num);
    }

    return *str - '0';
}

char get_check(char *str)
{
    while(my_get(str,2) == -1 || check_check(str) == 0)
    {
        printf("請輸入Y或N:");
    }

    return *str;

}

int read_file(Link head,Link *new_node)
{
    sqlite3 *db;
    int ret, i, row, column, index;
    char *sql;
    char *errmsg;
    char **result;

    ret = sqlite3_open("AddressDatabase.db",&db);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_open error,%s\n",sqlite3_errmsg(db));
        return 0;
    }

    sql = "select * from AddressList";
    ret = sqlite3_get_table(db,sql,&result,&row,&column,&errmsg);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_get_table error,%s\n",errmsg);
        return -1;
    }

    index = column;
    for(i = 0; i < row; i++)
    {
        create_node(new_node);
        strcpy((*new_node)->name,result[index++]);
        strcpy((*new_node)->hometel,result[index++]);
        strcpy((*new_node)->phone,result[index++]);
        strcpy((*new_node)->address,result[index++]);

        insert_node_and_sort(head,*new_node);
    }

    sqlite3_close(db);

    return 1;
}

int write_file(Link head)
{
    Link p = head->next;

    sqlite3 *db;
    int ret, i;
    char *sql;
    char *errmsg;

    ret = sqlite3_open("AddressDatabase.db",&db);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_open error,%s\n",sqlite3_errmsg(db));
        return 0;
    }

    sql = "drop table AddressList;";
    ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_exec error,%s\n",errmsg);
        return 0;
    }

    sql = "create table AddressList(name text,hometel text,phone text,address text);";
    ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
    if(ret != SQLITE_OK)
    {
        printf("sqlite3_exec error,%s\n",errmsg);
        return 0;
    }

    sql = (char*)malloc(sizeof(char) * 141);        //如果不給它賦空間,之後用sprintf會出現段錯誤(我也不知道爲什麼
    while(p != NULL)
    {
        sprintf(sql,"insert into AddressList values('%s','%s','%s','%s');",p->name,p->hometel,p->phone,p->address);
        ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
        if(ret != SQLITE_OK)
        {
            printf("sqlite3_exec error,%s\n",errmsg);
            return 0;
        }
        p = p->next;
    }

    sqlite3_close(db);
    return 1;
}

int main()
{
    system("clear");
    welcome();

    Link head;
    Link new_node; 
    int num;
    char num_get[2];
    int flag = 1;

    create_link(&head);

    read_file(head,&new_node);

    while(flag)
    {
        num = get_mode(num_get,6);

        switch(num)
        {
            case 1:
                display(head);
                clear_screen();
                break;

            case 2:
                create_new_contact(head,&new_node);
                clear_screen();
                break;

            case 3:
                delete_contact(head);
                clear_screen();
                break;

            case 4:
                find_contact(head);
                clear_screen();
                break;

            case 5:
                alter_contact(head);
                clear_screen();
                break;

            case 6:
                flag = 0;
                break;
        }
    }

    write_file(head);

    return 0;
}

兩個問題:

1.sprintf如果存入的字符串是個指針會出段錯誤,除非存入一個字符數組或者指針給它先賦空間

2.執行此程序前要先自行建立一個數據庫並把列都建好,每次執行此程序都會把那個數據庫刪掉再重新建一遍把所有數據都寫入,有沒有更簡便的方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章