一次作业题目-----话单计费(C-链表)

/****************************************************************
*File Name  :  final?.c
*Data   :  04/11/28
*Author   :  Solid Snake(wzz24)
*Model   : 
*
*Description  :  Get data from primitive tel-paper, and
      then count everybody's fee
*................................................................
*Revision History
*No Data  Revised  FunctionName
*1 04/11/10 MultiArray[] 第一阶段用的是多维数组写的, 刚开始接触C,没有经验
*2 04/11/28 LinkTable 第二阶段用的是连表写的, 别人都这么写, 我也就改成了连表
*3 04/12/12 模块化  第三阶段把具体功能拆分我认为还可以了, 便于添加新功能
*4 //继续优化中 原来冗余的变量减少
*5 //优化  驱除空格的错误 犯了低级错误, 不知什么原因, copy的Tab后变成了连续的空格, 我倒!!!害我几
     乎一个礼拜时间, shit
*6 //优化  减少冗余变量 2个GlobalVariable, main()里3个AutoVariable,自我感觉良好,比较满意,
*7 05/01/01 优化  
*8 05/01/02 想改成用makefile的(但没成功, changing...)
****************************************************************/

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

#define NEW_UNIT 13


/*************用此结构体存储一个单元,一个单元就是用空行(共2个字符ASCII码是13和10)隔开的******/
struct Bill_t
{
 char cUserName[BUFSIZ];
 char cType[BUFSIZ];
 char cTime[BUFSIZ];
 char cIno[BUFSIZ];
 char cOuto[BUFSIZ];
 struct Bill_t *Next;
};
typedef struct Bill_t stNode;
typedef stNode *Link;
/*************用此结构体存储一个单元,一个单元就是用空行(共2个字符ASCII码是13和10)隔开的******/

/****************用此结构存储不重复的用户名*******************/
struct Name_t
{
  char cUserName[BUFSIZ];
  struct Name_t *Next;
};
typedef struct Name_t stNodeName;
typedef stNodeName *LinkName;
/****************用此结构存储不重复的用户名*******************/

/****************函数原型声明*************************/
LinkName GetUserName(Link);
Link CreateList(Link, FILE *);
void CountFee(LinkName, Link);
void getValue(char *, char * , char *);
Link FilterSame(Link);
/****************函数原型声明*************************/

/****************全局变量**********************/
char cBuf[BUFSIZ]; //每一行的内容都放在这里
int iUnit;  //判断是否为头节点
/****************全局变量**********************/

int main(void)
{
 /***********************变量定义开始*************************/
 Link Head;  //存储每个单元的头节点
 LinkName HeadName; //指向用户名连表的头节点
 FILE *Stream;
 
 /***********************变量初始化开始**********************/
 Stream = fopen("detail.txt","r");
 iUnit = 1; //初始化全局变量 iUnit
 
 /***********************生成连表*****************************/
 Head = CreateList(Head, Stream);

 /***********************用GetUserName()取得无重复用户名字列表**/
 HeadName = GetUserName(Head);

 /***********************话单分捡(还没测试)****************************/ 
 /********************Head = FilterSame(Head);***********************/
 
 /***********************计算用户费用****************************/
 CountFee(HeadName, Head);
}

 

 

/*******************************函数定义区************************************/

/************************创建连表***************************************/
Link CreateList(Link Head, FILE *Stream)
{
 Link New;
 Link Pointer; //连接连表的各个节点用
 Head = (Link)malloc(sizeof(stNode)); //Initialize Global Variable Head
 New  = (Link)malloc(sizeof(stNode)); //Initialize Global Variable New
 
 /***此处while循环目的是分别把每一个单元放到连表的节点BEGIN***/
 while (fgets(cBuf, BUFSIZ, Stream) != NULL)   //针对每一行进行判断
        { //sizeof(cBuf)返回4, 因为cBuf是指针(sizeof(*)等于4), 即使把形参改成char cBuf[], 还是4, 因为它还是一个指针, 所以不能用sizeof获取数组大小, 可以使用宏BUFSIZ
                //如果STATUS=STOP, 就加入连表(还没写)
                                                                                                              
                if (cBuf[0] == NEW_UNIT)        //如果每一行的第一个字符(ASCII码)是13,意味一个新的单元的开始
                {
                        iUnit++;        //发现一个单元才加1
                        if (2 == iUnit) //开始第二个单元时,把Head over,Pointer指向Head
                        {               //不是当iUnit==2时每次都执行,因为cBuf[0]==13每个单元(节点)只有一次机会
                                Head->Next = NULL;
                                Pointer = Head;
                        }
                        if (iUnit > 2)           //当iUnit>2时
                        {
                                New->Next = NULL;       //先设置旧节点为NULL
                                Pointer->Next = New;    //Pointer和新节点相连
                                Pointer = New;          //Pointer指向New
                                New = (Link)malloc(sizeof(stNode));             //新单元开始,创建新节点
                        }
                }
                else            //如果不是,说明在一个单元内
                {
   /*********获取用户名BEGIN**********/
                        getValue(" User-Name", Head->cUserName, New->cUserName);
                        /*********获取用户名OVER***********/
                                                                                                              
                        /*********获取类型BEGIN************/
                        getValue(" Acct-Status-Type", Head->cType, New->cType);
                        /*********获取类型OVER*************/
                                                                                                              
                        /*********获取时间BEGIN************/
                        getValue(" Acct-Session-Time", Head->cTime, New->cTime);
                        /*********获取时间OVER*************/
                                                                                                              
                        /*********获取流入量BEGIN**********/
                        getValue(" Acct-Input-Octets", Head->cIno, New->cIno);
                        /*********获取流入量OVER***********/
                                                                                                              
                        /*********获取流出量BEGIN**********/
                        getValue(" Acct-Output-Octets", Head->cOuto, New->cOuto);
                        /*********获取流出量OVER***********/
                }
        }
        /**********此处while循环目的是分别把每一个单元放到连表的节点中OVER***********/

 return Head;
}

/******************取得我要找的值, 并且赋值给相应的节点***********************************/
void getValue(char *cName, char *HeadValue, char *NewValue)
{   
 //cName是要找的字符串 eg:User-Name, 即名/值对中的名
 //cValue是我要找的字符串所对应的值, 即名/值对中的值

 /*
 cBufName是临时的, 用于判断某一行是否是我要找的
 eg: 我要找某一行开头有"UserName"的行, 那我就用cBufName存储与"UserName"相同长度的每一行的值,
 再把cBufName与"UserName"比较, 就可知道是否当前行是我的目标行
 */
 
 //HeadValue是Bill_t内元素的地址, 这样只需在main函数内把相应的Bill_t元素地址传给本函数, 就可以赋值了
 //NewValue同上, 但它是后面的节点, 而HeadValue是对应的头节点的

        int iName;   //for circle count, trace username
        int iValue;  //trace username-value
 char cBufName[BUFSIZ];
 char cValue[BUFSIZ];


        for (iName = 0; iName < strlen(cName); iName++)
                cBufName[iName] = cBuf[iName];  //cBuf is global variable
        cBufName[iName] = '/0';
        if (strcmp(cBufName, cName) == 0) //找到目标行
        {
                iName  = strlen(cBufName) + 3;
                iValue =  0;
                while (cBuf[iName] != '/0')
                        cValue[iValue++] = cBuf[iName++];
                cValue[iValue - 2] = '/0';      //remove '/n'

                if (1 == iUnit)         //iUnit is Global variable
                 strcpy(HeadValue, cValue);
                else
   strcpy(NewValue, cValue);
        }
}

/**********************建立不重复用户名连表***********************/
LinkName GetUserName(Link Head)

 /*****************对auto变量初始化**************/
 int iSign;
 int iUnitName = 0;
 Link Pointer = Head;
 LinkName HeadName;
 LinkName NewName;
 LinkName PointerName;
 LinkName PointerTest;
 /*************对auto变量初始化****************/
 HeadName = (LinkName)malloc(sizeof(stNodeName));
 NewName = (LinkName)malloc(sizeof(stNodeName));

 while (Pointer != NULL)
        {
                //跟每个节点进行比较时都要把iSign清0,否则当iSign被置1后,后面就无法继续
                //因为iSign一直是1,即使后面不是重名的节点也没有往连表上连
                iSign = 0;
                iUnitName++;
                if (1 == iUnitName)    //如果是头节点,给头节点赋值
                {
                        strcpy(HeadName->cUserName, Pointer->cUserName);
                        HeadName->Next = NULL;
                        PointerName=HeadName;
                }
                else       //不是头节点
                {
                        //再对新生成的连表遍历,看要往新生成的连表上连的Pointer节点的名字是否与新生成的连表重名
                        //Pointer->cUserName是我要往新生成的连表上连的节点的名字
                        PointerTest = HeadName;
                        while (PointerTest != NULL)
                        {
                                if (strcmp(Pointer->cUserName, PointerTest->cUserName) == 0)   //重复
                                {
                                        iSign = 1;      //证明有重复的
                                        break;
                                }
                                PointerTest=PointerTest->Next;
                        }
                        if (iSign != 1)
   {
                                strcpy(NewName->cUserName, Pointer->cUserName);    //没有重复的就赋值
                                NewName->Next = NULL;
                                PointerName->Next = NewName;
                                PointerName = PointerName->Next;
                                NewName = (LinkName)malloc(sizeof(stNodeName));
                        }
                        Pointer = Pointer->Next;
                }
        }
 return HeadName;
}

/***************************计费***********************/
void CountFee(LinkName HeadName, Link Head)
{
        int TotalTime;
        int TotalIno;
        int TotalOuto;
        Link Pointer;
        LinkName PointerName = HeadName;
                                                                                                              
        while (PointerName != NULL)
        {
                TotalTime = 0;
                TotalIno  = 0;
                TotalOuto = 0;
                                                                                                              
                Pointer = Head;
                while (Pointer != NULL)
                {
                        if (strcmp(PointerName->cUserName, Pointer->cUserName) == 0)
                        {
                                TotalTime += atoi(Pointer->cTime);
                                TotalIno  += atoi(Pointer->cIno);
                                TotalOuto += atoi(Pointer->cOuto);
 }
                        Pointer = Pointer->Next;
                }
                printf("%s Time is %d, Ino is %d, Outo is %d/n", PointerName->cUserName,TotalTime, TotalIno, TotalOuto);
                PointerName = PointerName->Next;
        }
}

/**********************话单分捡(去除重单)*******************************/
/*Link FilterSame(Link Head) (还没测试)
{
 Link Pointer;
 Link PointerSon;
 Link Back;    //跟踪Pointer, 当要删除中间节点时有作用
 Pointer = Head;
 int iFlag;    //标志是否有重单
 
 //嵌套循环判断是否重单
 while (Pointer != NULL)
 {
  iFlag = 0;   //每一次新的开始, 重置iFlag
  
  PointerSon = Pointer->Next; //为了与Pointer后面的节点比较, 所以新建PointerSon指向Pointer的
      //下一个节点
  while (PointerSon != NULL)
  {
   if (strcmp(Pointer->Uid, PointerSon->Uid) == 0 && strcmp(Pointer->ConTime, PointerSon->ConTime) == 0)
   { 
    iFlag = 1;  //如果符合重单规则, 那么置iFlag为1, 代表有重单
    break;   //立即跳出子循环
   }
   PointerSon = PointerSon->Next; 
  }
  
  if (iFlag) //有重单, 那么删除Pointer这个节点,(我是把前面的节点删除)
  {
   if (Pointer == Head)  //如果是删除头节点
   {
    Head = Pointer->Next;
    free(Pointer);  //释放空间
    Pointer = Head;  //Pointer指向新的头节点(即指向下一个节点)
   }
   else    //否则是删除中间节点(注意, 不可能是尾节点, 因为我可前面的节点删除)
   {    //------可能存在问题, 注意这里
    Back = Pointer->Next;
    free(Pointer);
    Pointer = Back;  //Pointer指向下一个节点
   }

  }
  else  //没有重单, 那么继续往下判断
   Back = Pointer;   //目的是设置Back在Pointer的后面
   Pointer = Pointer->Next; //目的是设置Back在Pointer的后面
 }

 return Head;
}
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值