您的位置:首页 > 编程语言 > C语言/C++

C语言指针、链表与文件操作详解

2017-05-02 22:48 351 查看
用两个函数 Load_LinkList() 和 Save_LinkList() 让链表与文件操作结合,除了打印函数,其他都是在内存中操作链表,这样写更有条理,在创建链表时没有采用书上的用一个中间变量引导,并插入到结点前面,而是直接在链表尾的next申请内存,便于理解,操作也方便。
  /*首先是文件包含,这里就不使用 ifndef 那样常规写一个头文件*/
  #include
  #include
  #include
  #include
  #include
  /*接下来就是结构体*/
  /*每一种商品对应一个结点,用链表连接起来,统一写入文件,或者从文件中读取*/
  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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: