一.创建主MakeFile
1.先在主目录分别创建四个文件夹,分别是:src . include . obj . bin ,然后在主目录创建makefile文件。
OBJS:=main.o pig.o
MyApp:=MyPig
CC:=gcc
CFLAGS:=-c -g -Wall
export OBJS MyApp CC CFLAGS //将变量传给各目录下的子makefile
ALL:
make -C ./src/ // 先执行src下的makefile
make -C ./obj/ //再执行obj下的makefile
.PHONY:clean
clean:
$(RM) ./obj/*.o
$(RM) ./bin/*
二.创建子MakeFile
2.进入到src 以及 obj 文件夹下分别再创建makefile文件,makefile如下图:
src:
ALL:$(OBJS)
mv $^ ../obj/
main.o:main.c
$(CC) $(CFLAGS) $< -o $@
pig.o:pig.c
$(CC) $(CFLAGS) $< -o $@
makefile目的是为了把*.c文件转换为.c文件,并且把.o文件移动到obj文件夹中。
obj:
ALL:$(MyApp)
mv $^ ../bin/
$(MyApp):$(OBJS)
$(CC) $^ -o $@
makefile目的是为了把所有的.o文件合并转换为可执行文件,并且再把可执行文件移动到bin目录下。
三.编写头文件(.h文件)
#ifndef _PIG_H
#define _PIG_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define SIZE 100
//猪的数据类型的定义
typedef struct pig
{
char color[20];
int age;
char state[20];
int weight;
int NUM;
}data_type;
//hash表的节点的定义:一个数据段一个指针段
typedef struct hashnode
{
data_type data;
struct hashnode *pNext;
}HashNode;
//hash表的定义
typedef struct hash
{
HashNode *HashArr[SIZE];
int count;
int LastNum;
}Hash;
//定义一个枚举来列出错误的类型
enum value
{
NO_EXIST = -7,
EMPTY_ERROR,
NUM_ERROR,
MALLOC_ERROR,
CREAT_ERROR,
NULL_ERROR,
ERROR,
OK
};
int HashCreat(Hash **ppHash);
int AddBuyPigMessageToHash(Hash *pHash, data_type NewPigData);
int SellPigFromHash(Hash *pHash ,int NUM , data_type *pSellData);
int AlterPigMessage(Hash *pHash, data_type PigData);
int SearchPigMessage(Hash *pHash, int NUM, data_type *pData);
int DestroyHash(Hash **ppHash);
int ShowAllPigMessage(Hash *pHash);
#endif
四.编写主函数
#include "../include/pig.h"
int main(int argc, const char *argv[])
{
//创建哈西表
Hash *pHash = NULL;
if(HashCreat(&pHash) < 0)
{
return ERROR;
}
printf("创建哈西表成功\n");
//导入文件中的内容至哈西表中
int fr = open("pig.txt",O_RDONLY);
if(fr < 0)
{
perror("open_read error");
}
else
{
printf("打开存储猪信息的文件成功\n");
//读取 定义一个可以存储每只猪信息的变量
data_type AllData;
while(1)
{
int MyRead = read(fr, &AllData, sizeof(AllData));
if(MyRead < 0)
{
perror("读取猪信息失败");
close(fr);
DestroyHash(&pHash);
return ERROR;
}
else if(0 == MyRead)
{
printf("导入猪的信息完毕\n");
break;
}
else
{
//存储读取的信息
if(AddBuyPigMessageToHash(pHash,AllData) < 0)
{
DestroyHash(&pHash);
close(fr);
return ERROR;
}
printf("已经导入一只猪的信息\n");
pHash->LastNum = AllData.NUM;
}
}
}
//定义变量保存新买入母猪的数据
data_type Data;
//定义保存猪编号的变量
int NUM;
char op[20];
//定义保存卖出母猪信息的变量
data_type SellData;
while(1)
{
printf("请输入需要进行的操作:buy,sell,alter,search...\n");
scanf("%s",op);
if(0 == strcmp("quit",op))
{
printf("退出\n");
break;
}
if(0 == strcmp("buy",op))
{
// 买入
printf("请输入新猪的颜色:\n");
scanf("%s",Data.color);
//自动生成编号
Data.NUM = pHash->LastNum + 1;
printf("请输入新猪的年龄:\n");
scanf("%d",&Data.age);
printf("请输入新猪的受孕状态:\n");
scanf("%s",Data.state);
printf("请输入新猪的重量:\n");
scanf("%d",&Data.weight);
//调用买入
if(AddBuyPigMessageToHash(pHash,Data) < 0)
{
DestroyHash(&pHash);
return ERROR;
}
printf("%d编号小猪猪买入完毕\n",Data.NUM);
//更新最后一头猪的编号
pHash->LastNum = Data.NUM;
}
else if(0 == strcmp(op,"search"))
{
//查找所有的猪或者指定猪的信息
printf("请输入需要查找的猪的编号:\n");
scanf("%d",&NUM);
//0->查看所有猪的信息 非0->查看指定编号猪的信息
if(SearchPigMessage(pHash, NUM, NULL) < 0)
{
DestroyHash(&pHash);
return ERROR;
}
printf("查找成功\n");
}
else if(0 == strcmp(op, "sell"))
{
//卖猪喽
printf("正在和买家讨价还价....\n");
printf("请输入要卖的猪的编号:\n");
scanf("%d",&NUM);
//调用卖猪函数
if(SellPigFromHash(pHash, NUM, &SellData) < 0)
{
DestroyHash(&pHash);
return ERROR;
}
printf("%d编号的猪猪售卖完毕",NUM);
printf("被卖掉的猪的信息如下:\n");
printf("-------------\n");
printf("颜色:%s\n",SellData.color);
printf("编号:%d\n",SellData.NUM);
printf("年龄:%d\n",SellData.age);
printf("状态:%s\n",SellData.state);
printf("重量:%d\n",SellData.weight);
printf("-------------\n");
}
else if(0 == strcmp(op,"alter"))
{
//修改猪的信息
printf("请输入要修改信息的猪的编号:\n");
scanf("%d",&NUM);
printf("%d编号的猪的信息修改中....\n",NUM);
data_type PigData;
if(SearchPigMessage(pHash, NUM, &PigData) < 0)
{
DestroyHash(&pHash);
return ERROR;
}
printf("需要修改的猪的信息已找到\n");
printf("请重新输入猪的年龄:\n");
scanf("%d",&PigData.age);
printf("请确认这只猪是否怀孕\n");
scanf("%s",PigData.state);
printf("这小子是不是又胖了,请重新输入体重:\n");
scanf("%d",&PigData.weight);
//调用修改函数
if(AlterPigMessage(pHash,PigData) < 0)
{
DestroyHash(&pHash);
return ERROR;
}
printf("修改后的猪的信息如下:\n");
SearchPigMessage(pHash, NUM, NULL);
}
}
//自动保存猪的信息
int fw = open("pig.txt", O_WRONLY | O_CREAT | O_TRUNC ,0664);
if(fw < 0)
{
perror("open_write error");
close(fr);
DestroyHash(&pHash);
return ERROR;
}
printf("打开保存信息文件成功,即将保存所有猪的信息\n");
int i;
for(i = 0; i < pHash->LastNum; i++)
{
HashNode *pTemp = pHash->HashArr[i];
while(NULL != pTemp)
{
//写入文件
int MyWrite = write(fw, &pTemp->data, sizeof(pTemp->data));
if(MyWrite < 0)
{
perror("write error");
close(fr);
close(fw);
DestroyHash(&pHash);
return ERROR;
}
else if(0 == MyWrite)
{
printf("没有猪的信息\n");
close(fr);
close(fw);
DestroyHash(&pHash);
return ERROR;
}
else
{
printf("写入一个猪的信息成功\n");
}
//更新pTemp的指向
pTemp = pTemp->pNext;
}
}
//销毁哈西表
if(DestroyHash(&pHash) < 0)
{
printf("销毁哈西表失bai\n");
return ERROR;
}
printf("销毁哈西表成功\n");
close(fr);
close(fw);
return 0;
}
五.编写子函数
#include "../include/pig.h"
//创建哈西表子函数
//参数:哈西表的首地址
//成功返回ok
int HashCreat(Hash **ppHash)
{
if(NULL == ppHash)
{
return NULL_ERROR;
}
*ppHash = (Hash *)malloc(sizeof(Hash));
if(NULL == *ppHash)
{
return MALLOC_ERROR;
}
memset(*ppHash, '\0', sizeof(Hash));
return OK;
}
//买入新猪子函数
//参数1:哈西表的地址
//参数2:即将买入新猪的数据
//成功返回ok
int AddBuyPigMessageToHash(Hash *pHash, data_type NewPigData)
{
if(NULL == pHash)
{
return CREAT_ERROR;
}
//根据哈西函数获得NUM和存储地址之间的关系
//根据算出来的地址存储制定的新猪数据
//将NewPigData的节点地址保存在HashArr[Index]
//哈西函数->H(NUM) = NUM-1
int Index = NewPigData.NUM-1;
HashNode *pNew = (HashNode *)malloc(sizeof(HashNode));
if(NULL == pNew)
{
return MALLOC_ERROR;
}
memset(pNew, 0 ,sizeof(HashNode));
//赋值
pNew->data = NewPigData;
//头插
pNew->pNext = pHash->HashArr[Index];
//将pNew重新赋值给hasharr[Index]
pHash->HashArr[Index] = pNew;
//更新猪的数量
pHash->count++;
return OK;
}
//查找猪猪子函数
//参数1:哈西表的地址
//参数2:查找的猪的编号
//参数3:找到指定的猪的信息
//成功返回ok
int SearchPigMessage(Hash *pHash, int NUM, data_type *pData)
{
if(NULL == pHash)
{
return CREAT_ERROR;
}
if(NUM < 0 || NUM >SIZE)
{
return NUM_ERROR;
}
//根据传入的编号进行不同的操作
if(0 == NUM)
{
//查看所有猪的信息
ShowAllPigMessage(pHash);
}
else
{
int Index = NUM-1;
HashNode *pShow = pHash->HashArr[Index];
//遍历
while(NULL != pShow)
{
if(NUM == pShow->data.NUM)
{
//判断第三个参数是否为NULL决定进行的操作
if(NULL == pData)
{
//只想查看某只猪的信息
printf("-------------\n");
printf("颜色:%s\n",pShow->data.color);
printf("编号:%d\n",pShow->data.NUM);
printf("年龄:%d\n",pShow->data.age);
printf("状态:%s\n",pShow->data.state);
printf("重量:%d\n",pShow->data.weight);
printf("-------------\n");
}
else
{
*pData = pShow->data;
}
break;
}
//更新pShow的指向
pShow = pShow->pNext;
}
//判断引起循环终止的条件
if(NULL == pShow)
{
printf("需要查找的%d编号的小猪猪还没买",NUM);
return NO_EXIST;
}
}
return OK;
}
//显示所有的猪猪信息的子函数
//参数:哈西表的地址
//成功返回ok
int ShowAllPigMessage(Hash *pHash)
{
if(NULL ==pHash)
{
return CREAT_ERROR;
}
//遍历哈西表
int i;
HashNode *pTemp = NULL;
printf("目前猪圈的猪猪个数为:%d个,具体的猪猪信息如下:\n",pHash->count);
for(i = 0; i < pHash->LastNum; i++)
{
pTemp = pHash->HashArr[i];
while(NULL != pTemp)
{
printf("-------------\n");
printf("颜色:%s\n",pTemp->data.color);
printf("编号:%d\n",pTemp->data.NUM);
printf("年龄:%d\n",pTemp->data.age);
printf("状态:%s\n",pTemp->data.state);
printf("重量:%d\n",pTemp->data.weight);
printf("-------------\n");
//更新指针指向
pTemp = pTemp->pNext;
}
}
return OK;
}
//卖猪函数
//参数1:哈系表的地址
//参数2:即将被卖掉的猪的编号
//参数3:即将卖掉的猪的信息
//成功返回ok
int SellPigFromHash(Hash *pHash, int NUM, data_type *pSellData)
{
if(NULL == pHash)
{
return CREAT_ERROR;
}
if(NUM <= 0 || NUM > SIZE)
{
printf("猪的编号不对\n");
return NUM_ERROR;
}
if(NULL == pSellData)
{
return NULL_ERROR;
}
//通过编号找猪
//先保存被卖的猪的信息
//释放被卖的猪的节点空间
//置空
int Index = NUM-1;
HashNode *pTemp = pHash->HashArr[Index];
if(NULL == pTemp)
{
printf("该位置没有猪的信息\n");
return EMPTY_ERROR;
}
else
{
if(NUM == pTemp->data.NUM)
{
//保存被卖的猪的信息
*pSellData = pTemp->data;
//保存pTemp->pNext到pHash->HashArr[Index]
pHash->HashArr[Index] = pTemp->pNext;
free(pTemp);
pTemp = NULL;
//猪的个数减少
pHash->count--;
}
else
{
//pTemp指向节点里的num不是我们要找的猪
HashNode *pPre = pTemp;
HashNode *pSell = pPre->pNext;
while(NULL != pSell)
{
//pTemp后面有节点
if(NUM == pSell->data.NUM)
{
*pSellData = pSell->data;
//保存后续地址
pPre->pNext = pSell->pNext;
free(pSell);
pSell = NULL;
pHash->count--;
}
else
{
//还是没有找到
pPre = pSell;
pSell = pSell->pNext;
}
}
}
}
return OK;
}
//修改猪的信息(赚钱)函数
//参数1:哈系表的地址
//参数2:修改猪的信息
//成功返回ok
int AlterPigMessage(Hash *pHash, data_type PigData)
{
if(NULL == pHash)
{
return CREAT_ERROR;
}
int Index = PigData.NUM-1;
HashNode *pTemp = pHash->HashArr[Index];
while(NULL != pTemp)
{
if(PigData.NUM == pTemp->data.NUM)
{
pTemp->data = PigData;
break;
}
pTemp = pTemp->pNext;
}
if(NULL == pTemp)
{
printf("没有这个编号的猪\n");
}
return OK;
}
//销毁函数
//参数1:哈西表的首地址
//成功返回ok
int DestroyHash(Hash **ppHash)
{
if(NULL == ppHash)
{
return NULL_ERROR;
}
if(NULL == *ppHash)
{
return CREAT_ERROR;
}
//先释放每一个指针数组元素中有可能存储的单链表
//再释放哈西表
int i;
HashNode *pNode = NULL;
for(i = 0; i < (*ppHash)->LastNum; i++)
{
pNode = (*ppHash)->HashArr[i];
//头删法删除单链表
while(NULL != pNode)
{
(*ppHash)->HashArr[i] = pNode->pNext;
free(pNode);
pNode = (*ppHash)->HashArr[i];
}
}
//删除哈西表
free(*ppHash);
*ppHash = NULL;
return OK;
}
六.运行结果