歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言指針、鏈表與文件操作學習

C語言指針、鏈表與文件操作學習

日期:2017/3/1 9:12:17   编辑:Linux編程

准備開始學習C++,對大一所學的C語言一次練習,正好也是趕上老師布置的任務,用C語言寫一個 銷售管理系統 ,就盡可能的把所學的都用上,也就是結構,指針,文件操作,還有數據結構,本次加入了鏈表。

用兩個函數 Load_LinkList() 和 Save_LinkList() 讓鏈表與文件操作結合,除了打印函數,其他都是在內存中操作鏈表,這樣寫更有條理,在創建鏈表時沒有采用書上的用一個中間變量引導,並插入到結點前面,而是直接在鏈表尾的next申請內存,便於理解,操作也方便。

/*首先是文件包含,這裡就不使用 ifndef 那樣常規寫一個頭文件*/

#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
/*接下來就是結構體*/

/*每一種商品對應一個結點,用鏈表連接起來,統一寫入文件,或者從文件中讀取*/
typedef struct commodity
{
    int data;               //頭結點data統計個數,其余為商品編號
    char name[20];          //名稱
    double price;           //價格
    int count;              //數量
    double sum;             //總計,頭結點sum為所有商品總計
    struct commodity *next;

} *LinkList, LNode;
/*定義全局變量,方便使用*/

/*鏈表頭指針*/
LinkList H = NULL;

/*文件指針*/
FILE *fp = NULL;
/*函數聲明*/



/***************顯示函數****************/
//歡迎界面
void welcome();

//顯示菜單
void menu();
//打印表格頭 void printf_header();
//顯示單個結點信息 void printf_linklist_info(LinkList pTemp); //延時函數 void delay(); /***********鏈表文件操作函數*****************/ //從文件中讀取到鏈表中 void Load_LinkList(LinkList H); //將鏈表保存到文件中 void Save_LinkList(LinkList H); /***************鏈表函數**********************/ //建立頭結點 void Creat_LinkList(); //添加結點到鏈表尾部 LinkList Add_LinkList(LinkList H); //輸入結點數據 void Scanf_LinkList(LinkList pTemp); //找到符合要求的結點的前驅 LinkList Find_LinkList_Pos(LinkList H,int index); //找到符合要求的結點的地址 LinkList Find_LinkList_Val(LinkList H, char *name); //刪除指定結點 void Del_LinkList(LinkList H, char *name); //修改結點內容 void Modify_LinkList(LinkList H, int index, int data); //順序輸出 void Printf_LinkList(LinkList H); //釋放內存 void Free_LinkList(LinkList H);
/*main函數,沒什麼說的,除了getch函數用的時候會方便一些*/

int main()
{
    LinkList pTemp = NULL;
    char name[20] = {0};
    system("color A");
    //welcome();

    Creat_LinkList();
    Load_LinkList(H);

    while(1)
    {
        system("cls");
        menu();
        switch(getch())
        {
            case '1':
                pTemp = Add_LinkList(H);
                Scanf_LinkList(pTemp);
                getch();
                break;
            case '2':
                printf_header();
                Printf_LinkList(H);
                getch();
                break;
            case '3':
                printf("\n輸入名稱查找:");
                scanf("%s", name);
                pTemp = Find_LinkList_Val(H, name);
                printf_linklist_info(pTemp);
                getch();
                break;
            case '4':
                printf("\n請先輸入名稱查找:");
                scanf("%s", name);
                pTemp = Find_LinkList_Val(H, name);
                Scanf_LinkList(pTemp);
                getch();
                break;
            case '5':
                printf("\n請先輸入名稱查找:");
                scanf("%s", name);
                Del_LinkList(H, name);
                getch();
                break;
            case '6':
                Save_LinkList(H);
                printf("\n成功保存%d條信息!\n", H->data);
                getch();
                break;
            case '0':
                printf("\n歡迎下次使用!\n");
                exit(0);
            default :
                printf("錯誤輸入!");
                getch();
        }
    }
    return 0;
}

////////////////////下面是顯示函數實現內容

/*歡迎界面,其實不要也可以*/
void welcome()
{
    int i;
    for(i=1 ; i<=100 ; i++)
    {
        printf("*******************歡迎使用本系統*************************");
        printf("\n\n\n\n\n\n\n");
        printf("                                                 加載中");
        printf("...\n");
        printf("                                                      %3d%%\n",i);
        printf("**********************************************************");
        system("cls");
    }
    return ;
}
/*菜單函數*/
void menu()
{
    system("cls");
    printf("                        歡迎進入本系統                     \n");
    printf("\n");
    printf("-------------------------------------------------------------------\n");
    printf("|                 1 添加商品                                      |\n");
    printf("|                 2 顯示商品                                      |\n");
    printf("|                 3 查找商品                                      |\n");
    printf("|                 4 修改商品                                      |\n");
    printf("|                 5 刪除商品                                      |\n");
    printf("|                 6 保存修改                                      |\n");
    printf("|                 0 退出系統                                      |\n");
    printf("-------------------------------------------------------------------\n");
    printf("                                               提示:退出前請先保存!");
    printf("\nchoose(0-8):");
}
/*以表格的形式打印所有商品信息*/
void printf_header()
{
    system("cls");
    printf("-------------------------您的所有庫存-------------------------------------\n");
    printf("|   編號   |      名稱     |    價格       |       數量     |    總計    |\n");
    printf("|----------|---------------|---------------|----------------|------------|\n");
}
/*顯示單個結點信息*/
void printf_linklist_info(LinkList pTemp)
{
    if(pTemp == NULL)
    {
        return ;
    }
    printf_header();
    pTemp->sum = pTemp->price * pTemp->count;
    printf("|%10d|%15s| %lf  |%20d|  %lf   |\n",pTemp->data, pTemp->name, pTemp->price, pTemp->count, pTemp->sum);
    printf("|----------|---------------|---------------|----------------|------------|\n");
    return ;
}
/*延時函數,寫完了發現我一直用的是getch等待按鍵*/
void delay()
{
    long int i,j;
    for(i=500000 ; i>0 ; i--)
    {
        for(j=0 ; j<=2000 ; j++);
    }
}
/*創建頭結點*/
void Creat_LinkList()
{
    H = (LinkList)malloc(sizeof(LNode));
    if(H)
    {
        H->next = NULL;
        H->data = 0;
    }
    return ;
}
/*添加結點,這裡是直接用最後一個節點的next申請內存*/
LinkList Add_LinkList(LinkList H)
{
    LinkList q = H;
    while(q->next != NULL)
        q = q->next;
    q->next = (LinkList)malloc(sizeof(LNode));
    q->next->sum = 0;

    q->next->next = NULL;
    H->data++;
    return q->next;
}
/*用於添加結點時輸入結點信息,或者修改時輸入*/
void Scanf_LinkList(LinkList pTemp)
{
    if(pTemp == NULL)
    {
        return ;
    }
    printf("\n輸入編號:");
    scanf("%d", &pTemp->data);
    printf("輸入名稱:");
    scanf("%s", pTemp->name);
    printf("輸入價格:");
    scanf("%lf", &pTemp->price);
    printf("輸入數量:");
    scanf("%d", &pTemp->count);
    pTemp->sum = pTemp->price * pTemp->count;
}
/*從文件中讀取並加載到鏈表中,和Save函數一樣,是最關鍵的兩個函數*/
void Load_LinkList(LinkList H)
{
    LinkList p = NULL, pTemp = NULL;
    pTemp = (LinkList)malloc(sizeof(LNode));
    pTemp->next = NULL;
    fp = fopen("D:/a.txt", "rb");

    while(1)
    {
        /*這裡用一個中間結點,臨時儲存,fread讀一次才能決定是否添加結點,直接用p添加結點會錯誤,本身就是空文件時會多出一個結點,存的垃圾值,而fread必須有一塊內存才能讀*/
        if((fread(pTemp, sizeof(LNode), 1, fp)) != 0)
        {
            p = Add_LinkList(H);

            p->data = pTemp->data;
            strcpy(p->name, pTemp->name);
            p->price = pTemp->price;
            p->count = pTemp->count;

            H->data++;
        }
        else
            break;
    }
    free(pTemp);
    fclose(fp);
    return ;
}    
/*將鏈表保存到文件中*/
void Save_LinkList(LinkList H)
{
    LinkList p = H->next;
    if(p == NULL)
    {
        /*這裡是清空一下,假如鏈表中保存的有數據,調用刪除完之後,不能用fwrite,只是這種情況下用wb清空文件*/
        fp = fopen("D:/a.txt", "wb");
        H->data = 0;
        fclose(fp);
        getch();
        return ;
    }
    fp = fopen("D:/a.txt", "wb");
    while(p != NULL)
    {
        fwrite(p, sizeof(LNode), 1, fp);
        p = p->next;
    }

    fclose(fp);
    return ;
}

///////////////接下來的函數就是只在內存裡面操作鏈表

/*通過位置查找,返回結點  前驅結點  地址,計劃是有這個查找的,後來寫菜單也不想用了,就放這裡沒動過*/

LinkList Find_LinkList_Pos(LinkList H,int index)
{
    LinkList p = H;
    index--;
    while(index--)
    {
        p = p->next;
    }
    return p;
}
/*通過字符串匹配查找,返回結點地址*/
LinkList Find_LinkList_Val(LinkList H, char *name)
{
    LinkList p = H;
    while(strcmp(p->name, name) != 0  &&  p->next != NULL)
    {
        p = p->next;
    }
    if(p->next == NULL)
    {
        printf("沒有此商品!");
        return NULL;
        getch();
    }
    return p;
}
/*刪除一個結點,pre是前驅結點,p是要找的結點*/
void Del_LinkList(LinkList H, char *name)
{
    int flag = 0;
    LinkList p = H->next, pre = H;
    while(p != NULL)
    {
        if(strcmp(p->name, name) == 0)
        {
            flag = 1;
            break;
        }
        pre = p;
        p = p->next;
    }
    if(flag == 0)
    {
        printf("沒有此商品!\n");
        return ;
    }

    p = pre->next;
    pre->next = p->next;
    free(p);
    return ;
}
/*修改結點信息,也是也可以實現的,和Find_LinkList_Pos()一樣,沒有用過*/
void Modify_LinkList(LinkList H, int index, int data)
{
    LinkList p = Find_LinkList_Pos(H, index+1);
    if(p)
        p->data = data;
    return ;
}
/*順序輸出,表格沒有對太齊,應該用 %xd 這樣的,後來也不想改了*/
void Printf_LinkList(LinkList H)
{
    LinkList p = NULL;
    p = H->next;
    if(p == NULL)
    {
        printf("當前沒有任何商品!");
        getch();
        return ;
    }
    while(p != NULL)
    {
        p->sum = p->price * p->count;
        printf("|%10d|%15s|   %lf   |   %15d  |  %lf   |\n",p->data, p->name, p->price, p->count, p->sum);
        printf("-------------------------------------------------------------------------------\n");
        p = p->next;
    }
    printf("                                                                           %lf\n", H->sum);
    return ;
}
/*內存總是要釋放的*/
void Free_LinkList(LinkList H)
{
    LinkList pre = NULL, p = H->next;
    while(pre != NULL)
    {
        pre = p->next;
        free(p);
        p = p->next;
    }
    H->next = NULL;
    return ;
}

Copyright © Linux教程網 All Rights Reserved