C语言复习——指针 链表 与 文件操作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言复习——指针 链表 与 文件操作相关的知识,希望对你有一定的参考价值。

     刚刚进入大二,准备开始学习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 ;
}

 

以上是关于C语言复习——指针 链表 与 文件操作的主要内容,如果未能解决你的问题,请参考以下文章

C语言文件操作复习

C语言复习之字符指针(迭代内存申请等操作)

c语言中如何通过二级指针来操作二维数组

C语言复习之改变变量的指针地址

C语言 严蔚敏数据结构 线性表之链表实现

c语言链表和指针的运用