一、需求
(1)管理员方账号登录;
(2)车位管理显示:车位状态;
(3)收费管理:小轿车 5元/小时,面包车6元/小时,大货车或客车7元/小时,由停车时选择录入;
(4)汽车停泊信息管理:车牌号、停泊位置、停泊开始时间,车位已满给出提示;
(5)车辆停泊时间自动计算费用管理:取车后自动计算车辆停泊所需费用;
(6)查询车辆信息管理:车辆是否入库,车辆出库,删除车辆信息;
(7)车主方选择车位、入库、出库时间。
二、系统功能
(1)登录模块:用于管理员登录账号
(2)信息保存模块:用于保存已有的泊车信息
(3)入库模块:用于停车时录入汽车停泊信息,如车牌号、车辆类型、车主电话、停泊位置、停泊开始时间等,若车位已满给出提示
(4)删除模块:用于出库时删除车辆信息
(5)展示模块:用于为车主提供车位信息,选择车位
(6)查找模块:用于通过车牌号查找车辆信息
(7)计费模块:用于取车时根据车辆停泊时间自动计算费用,小轿车 5元/小时,面包车6元/小时,大货车或客车7元/小时,由停车时选择录入
(8)出库模块:用于车主出库
(9)状态模块:用于修改车位状态
三、函数声明
1、单链表部分
头文件SLT.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<locale.h>
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<stdbool.h>
#include<assert.h>
#include"parking.h"
typedef Info SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SLTNode;
//链表的头插和尾插
void SLTPushBack(SLTNode** pphead, SLTDateType x);
void SLTPushFront(SLTNode** pphead, SLTDateType x);
//链表的头删、尾删
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);
//在指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDateType x);
//删除pos
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos之后的节点
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos);
//销毁链表
void SListDestroy(SLTNode** pphead);
2、泊车系统功能部分
头文件Parking.h
#pragma once
#define TEL_Max 20
#define ROW_MAX 10
#define COL_MAX 10
#define BLANK L'□'//代表空车位
#define CAR L'★'//代表有车
typedef enum
{
min = 1,
mid,
big
}Type;//类型
typedef enum
{
no,//无车
yes//有车
}state;//状态
typedef struct manager
{
char id[20];//账号
char secret[20];//密码
}login;//管理员登录信息
typedef struct ParkTime
{
int h;
int m;
int s;
}time;//停车时间
typedef struct CarInfo
{
Type carType;//车类型
char licensePlateNum[10];//车牌号
char tel[TEL_Max];//电话
int siteX;//位置横
int siteY;//位置纵
time startTime[10];//开始停车时间
time leaveTime[10];//离开时间
int fee;
}Info;//车辆信息
struct SListNode;
typedef struct SListNode Parking;
void SetPos(int x, int y);
int Entry();//是否进入系统
int Login();//登录
void parking();//登陆后进行系统操作
void LoadParking(Parking** pcar, int arr[ROW_MAX + 1][COL_MAX + 1],int* sitenum);//录入文件中现有信息
void SaveParking(Parking* car);//保存信息到文件
void AddParking(Parking** pcar, int* siteNum, int arr[ROW_MAX + 1][COL_MAX + 1]);//增加车辆信息
void DelParking(Parking** pcar);//删除车辆信息
Parking* FindByNum(Parking* pcar, char num[]);//通过车牌号来查找
void FindParking(Parking** pcar);//先通过车牌号,再查找车辆
void ShowParking(Parking** pcar);//展示车辆信息
void CountFee(Parking** pcar);//计算停车费用,未满一小时按照一小时计算
void createSite(int arr[ROW_MAX + 1][COL_MAX + 1]);//创造车位状态
void PrintSite(int arr[ROW_MAX + 1][COL_MAX + 1]);//查看车位状态
void SiteState(Parking** pcar, int arr[ROW_MAX + 1][COL_MAX + 1], int* siteNum);//找到离开的车辆确定离开时间并且修改车位状态,计算费用
void ParkingDestroy(Parking** pcar);//销毁
四、函数实现
1、链表部分
源文件:STL.c
#include"SLT.h"
SLTNode* SLTBuyNode(SLTDateType x)
{
SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
if (newnode == NULL)
{
perror("malloc fail!");
exit(1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void SLTPushBack(SLTNode** pphead, SLTDateType x)
{
assert(pphead);
//新节点申请
SLTNode* newnode = SLTBuyNode(x);
//链表为空,新节点作为phead
if (*pphead == NULL)
{
*pphead = newnode;
return;
}
//链表不为空,通过遍历找尾节点
SLTNode* ptail = *pphead;
while (ptail->next)
{
ptail = ptail->next;
}
ptail->next = newnode;
}
void SLTPushFront(SLTNode** pphead, SLTDateType x)
{
assert(pphead);
SLTNode* newnode = SLTBuyNode(x);
newnode->next = *pphead;//插入的节点指向第一个节点
*pphead = newnode;//再把newnode设为第一个节点
}
void SLTPopBack(SLTNode** pphead)
{
assert(pphead);
//链表不能为空
assert(*pphead);
//链表不为空
//链表只有一个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
return;
}
//有多个节点
SLTNode* ptail = *pphead;//遍历找尾节点
SLTNode* prev = NULL;//前驱
while (ptail->next)
{
prev = ptail;
ptail = ptail->next;
}
prev->next = NULL;
free(ptail);
ptail = NULL;
}
void SLTPopFront(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
SLTNode* next = (*pphead)->next;//->的优先级高于*
free(*pphead);
*pphead = next;
}
//找pos的前驱节点prev
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
//要加上链表不为空,因为pos是链表里的有效节点,空的话就找不到pos的前驱节点
assert(*pphead);
//pos是头结点
if (pos == *pphead)
{
//头插
SLTPushFront(pphead, x);
return;
}
//pos不是头结点的情况
SLTNode* newnode = SLTBuyNode(x);
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//prev找到了
prev->next = newnode;
newnode->next = pos;
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDateType x)
{
assert(pphead);
assert(pos);
assert(*pphead);
SLTNode* newnode = SLTBuyNode(x);
newnode->next = pos->next;
pos->next = newnode;
}
//删除pos,找到前驱prev
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
assert(*pphead);
//pos是头结点
if (pos == *pphead)
{
SLTPopFront(pphead);
return;
}
//不是头结点
SLTNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//找到prev
prev->next = pos->next;
free(pos);
pos = NULL;
}
//删除pos之后的节点
void SLTEraseAfter(SLTNode** pphead, SLTNode* pos)
{
assert(pphead);
assert(pos);
assert(pos->next);
SLTNode* del = pos->next;//不能直接释放pos->next
pos->next = pos->next->next;
free(del);
del = NULL;
}
void SListDestroy(SLTNode** pphead)
{
assert(pphead);
assert(*pphead);
//每个节点独立存在,应循环销毁
SLTNode* pcur = *pphead;
while (pcur)
{
SLTNode* next = pcur->next;
free(pcur);
pcur = next;
}
*pphead = NULL;
}
2、泊车系统部分
源文件Parking.c
#include"SLT.h"
void SetPos(int x, int y)
{
//获得设备句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//根据句柄设置光标的位置
COORD pos = { x,y };//表示控制台坐标
SetConsoleCursorPosition(handle, pos);
}
int Login()
{
int ret = -1;
login manager = { "1","1" };//账号密码由自己设定
char id[20] = { 0 };
char secret[20] = { 0 };
int chance = 5;
SetPos(40, 13);
printf("您有五次登陆机会");
SetPos(42, 20);
system("pause");
system("cls");
while (chance > 0)
{
SetPos(40, 13);
printf("请输入账号:");
scanf("%s", id);
SetPos(40, 15);
printf("请输入密码:");
scanf(" %s", secret);
SetPos(42, 20);
system("cls");
if (strcmp(manager.id, id)==0 && strcmp(manager.secret, secret)==0)
{
SetPos(40, 13);
printf("登陆成功\n");
ret = 1;
system("pause");
system("cls");
break;
}
else {
if (chance > 1)
{
SetPos(40, 13);
printf("登陆失败,您还剩%d次机会,请重新输入:",chance-1);
SetPos(42, 20);
system("pause");
system("cls");
}
else
{
SetPos(40, 13);
printf("登陆失败\n");
SetPos(42, 20);
system("pause");
system("cls");
ret = -1;
break;
}
chance--;
}
}
return ret;
}
int Entry()
{
SetPos(40, 13);
printf("欢迎进入泊车系统\n");
SetPos(42, 20);
system("pause");
system("cls");
int op = -1;
SetPos(40, 15);
printf("请选择:1.登录系统\n");
SetPos(40, 16);
printf("0.退出系统\n");
SetPos(40, 17);
printf("请选择:");
scanf("%d", &op);
system("cls");
int ret = 0;
do
{
switch (op)
{
case 1:
//登录
ret = Login();
break;
case 0:
//退出
SetPos(40, 13);
printf("退出系统\n");
ret = -1;
break;
default:
printf("选择错误,请重新选择:\n");
break;
}
if (ret == 1||ret == -1)
{
break;
}
} while (op);
return ret;
}
void menu()
{
SetPos(40, 12);
printf("1.下载之前的信息");
SetPos(40, 13);
printf("2.车辆入库");
SetPos(40, 14);
printf("3.删除车辆信息");
SetPos(40, 15);
printf("4.根据车牌号查找车辆");
SetPos(40, 16);
printf("5.展示车辆信息");
SetPos(40, 17);
printf("6.查看车位状态");
SetPos(40, 18);
printf("7.车辆出库");
SetPos(40, 19);
printf("8.保存当前信息");
SetPos(40, 20);
printf("9.查看剩余车位");
SetPos(40, 21);
printf("0.退出系统");
}
void parking()
{
int op = -1;
Parking* car = NULL;//
int sitenum = ROW_MAX * COL_MAX;
int arr[ROW_MAX + 1][COL_MAX + 1] = { 0 };
createSite(arr);//创造车位
do
{
menu();
SetPos(40, 22);
printf("请选择:");
scanf(" %d", &op);
system("cls");
switch (op)
{
case 1:
LoadParking(&car,arr,&sitenum);
system("pause");
system("cls");
break;
case 2:
AddParking(&car, &sitenum, arr);
system("pause");
system("cls");
break;
case 3:
DelParking(&car);
system("pause");
system("cls");
break;
case 4:
FindParking(&car);
system("pause");
system("cls");
break;
case 5:
ShowParking(&car);
system("pause");
system("cls");
break;
case 6:
PrintSite(arr);
system("pause");
system("cls");
break;
case 7:
SiteState(&car,arr, &sitenum);
system("pause");
system("cls");
break;
case 8:
SaveParking(car);
system("pause");
system("cls");
break;
case 9:
printf("剩余车位:%d\n", sitenum);
system("pause");
system("cls");
break;
case 0:
SetPos(40, 12);
printf("退出系统");
SetPos(40, 20);
break;
default:
SetPos(40, 15);
printf("输入错误,请重新选择\n");
system("pause");
system("cls");
break;
}
} while (op);
ParkingDestroy(&car);
}
void AddParking(Parking** pcar, int* siteNum, int arr[ROW_MAX + 1][COL_MAX + 1])
{
//判断车位是否已满
if (*siteNum == 0)
{
printf("车位已满,无法进入停车\n");
return;
}
else
{
Info car = { 0 };
printf("请选择车的类型(1.小轿车 2.面包车 3.大货车或客车):\n");
//选车的位置
scanf("%d", &car.carType);
printf("请输入车牌号:\n");
scanf("%s", car.licensePlateNum);
printf("请输入电话号码:\n");
scanf("%s", car.tel);
system("cls");
PrintSite(arr);
printf("请选择停车的位置(坐标行列(x,y)):\n");
scanf("%d%d", &car.siteX, &car.siteY);
while (car.siteX > ROW_MAX || car.siteY > COL_MAX)
{
printf("没有此车位,选择错误,请重新选择:");
scanf("%d%d",&car.siteX,&car.siteY);
}
while (arr[car.siteX][car.siteY] == yes)
{
printf("车位已有车主,无法进入,请重新选择:");
scanf("%d%d",&car.siteX,&car.siteY);
}
arr[car.siteX][car.siteY] = yes;
printf("请输入停车时间(时,分,秒):\n");
scanf("%d%d%d", &car.startTime->h, &car.startTime->m, &car.startTime->s);
SLTPushBack(pcar, car);
printf("停车入库成功!");
(*siteNum)--;
}
}
Parking* FindByNum(Parking* pcar, char num[])
{
Parking* cur = pcar;
while (cur)
{
if (strcmp(cur->data.licensePlateNum ,num)==0)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
void DelParking(Parking** pcar)
{
printf("请输入要删除的车牌号:\n");
char num[20];
scanf("%s", num);
Parking* pos = FindByNum(*pcar, num);
if (pos == NULL)
{
printf("要删除的车的信息不存在,删除失败!\n");
return;
}
if (pos->data.fee == 0) {
printf("要删除的车辆未离开不允许删除!");
return;
}
SLTErase(pcar, pos);
printf("删除成功!\n");
}
void SiteState(Parking** pcar, int arr[ROW_MAX + 1][COL_MAX + 1], int* siteNum)
{
printf("请选择要离开的车的车牌号:");
char num[20];
scanf("%s", num);
Parking* pos = FindByNum(*pcar, num);
if (pos == NULL)
{
printf("要出库的车辆不存在,选择失败!\n");
return;
}
while (pos->data.fee != 0)
{
//车辆已经离开
pos = pos->next;
pos = FindByNum(pos, num);
if (pos == NULL)
{
printf("要出库的车辆已经离开,选择失败!\n");
return;
}
}
printf("请输入离开的时间:");
scanf("%d%d%d", &pos->data.leaveTime->h,
&pos->data.leaveTime->m,
&pos->data.leaveTime->s);
arr[pos->data.siteX][pos->data.siteY] = no;
printf("车辆已离开,车位状态修改成功\n");
//自动计算费用
CountFee(&pos);
(*siteNum)++;
}
void FindParking(Parking** pcar)//通过车牌号查找
{
char num[20];
printf("请输入要查找车牌号:\n");
scanf("%s", num);
Parking* pos = FindByNum(*pcar, num);
if (pos == NULL)
{
printf("要查找的用户不存在,查找失败!\n");
return;
}
printf("查找成功!\n");
printf("%-4s %-10s %-10s %-8s %-13s %-10s %-8s\n", "类型", "车牌号", "电话", "位置", "停车时间", "离开时间", "费用");
printf("%-4d %-10s %-10s (%d,%d) %d时%d分%d秒 %d时%d分%d秒 %d元\n",
pos->data.carType,
pos->data.licensePlateNum,
pos->data.tel,
pos->data.siteX,
pos->data.siteY,
pos->data.startTime->h,
pos->data.startTime->m,
pos->data.startTime->s,
pos->data.leaveTime->h,
pos->data.leaveTime->m,
pos->data.leaveTime->s,
pos->data.fee
);
}
void ShowParking(Parking** pcar)
{
printf("%-4s %-10s %-10s %-8s %-13s %-10s %-8s\n", "类型", "车牌号", "电话", "位置", "停车时间","离开时间","费用");
Parking* pos = *pcar;
while (pos)
{
printf("%-4d %-10s %-10s (%d,%d) %d时%d分%d秒 %d时%d分%d秒 %d元\n",
pos->data.carType,
pos->data.licensePlateNum,
pos->data.tel,
pos->data.siteX,
pos->data.siteY,
pos->data.startTime->h,
pos->data.startTime->m,
pos->data.startTime->s,
pos->data.leaveTime->h,
pos->data.leaveTime->m,
pos->data.leaveTime->s,
pos->data.fee
);
pos = pos->next;
}
}
int Fee(int h1, int m1, int s1, int h2, int m2, int s2)
{
float timeS = (h1 - h2) * 3600 + (m1 - m2) * 60 + s1 - s2;
float timeH = timeS / 3600.0;
if (timeH == (int)timeH)
{
return (int)timeH;
}
else
{
return (int)timeH + 1;
}
}
void CountFee(Parking** pcar)
{
switch ((*pcar)->data.carType)
{
case min:
//五元每小时
(*pcar)->data.fee = 5 * Fee((*pcar)->data.leaveTime->h, (*pcar)->data.leaveTime->m, (*pcar)->data.leaveTime->s,
(*pcar)->data.startTime->h, (*pcar)->data.startTime->m, (*pcar)->data.startTime->s);
break;
case mid:
//六元每小时
(*pcar)->data.fee = 6 * Fee((*pcar)->data.leaveTime->h, (*pcar)->data.leaveTime->m, (*pcar)->data.leaveTime->s,
(*pcar)->data.startTime->h, (*pcar)->data.startTime->m, (*pcar)->data.startTime->s);
break;
case big:
//七元每小时
(*pcar)->data.fee = 7 * Fee((*pcar)->data.leaveTime->h, (*pcar)->data.leaveTime->m, (*pcar)->data.leaveTime->s,
(*pcar)->data.startTime->h, (*pcar)->data.startTime->m, (*pcar)->data.startTime->s);
break;
}
}
LoadParking(Parking** pcar, int arr[ROW_MAX + 1][COL_MAX + 1],int* sitenum)
{
FILE* pf = fopen("C:/Users/16637/Desktop/Parking/Parking/Parking.txt", "rb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//循环读取⽂件数据
Info info;
while (fread(&info, sizeof(info), 1, pf))
{
SLTPushBack(pcar, info);
}
printf("历史数据导入成功!\n");
Parking* cur = *pcar;
while (cur)
{
if(cur->data.fee == 0)
{
arr[cur->data.siteX][cur->data.siteY] = yes;
(*sitenum)--;
}
cur = cur->next;
}
}
void SaveParking(Parking* car)
{
FILE* pf = fopen("C:/Users/16637/Desktop/Parking/Parking/Parking.txt", "wb+,ccs = UTF-8");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//将通讯录数据写入文件
Parking* cur = car;
while (cur)
{
fwrite(&(cur->data), sizeof(cur->data), 1, pf);
cur = cur->next;
}
printf("通讯录数据保存成功!\n");
}
void createSite(int arr[ROW_MAX + 1][COL_MAX + 1])
{
int i = 0;
int j = 0;
//打印横坐标
for (i = 0; i <= ROW_MAX; i++)
{
for (j = 0; j <= COL_MAX; j++)
{
arr[i][j] = no;
}
}
}
void PrintSite(int arr[ROW_MAX + 1][COL_MAX + 1])
{
int i = 0;
int j = 0;
//打印横坐标
for (i = 0; i <= ROW_MAX; i++)
{
printf("%d ", i);
}
printf("\n");
for (i = 1; i <= COL_MAX; i++)
{
printf("%d ", i);
for (j = 2; j <= COL_MAX * 2; j += 2)
{
if(arr[i][j/2]==no)
{
SetPos(j, i);
wprintf(L"%lc", BLANK);
}
else
{
SetPos(j, i);
wprintf(L"%lc", CAR);
}
}
printf("\n");
}
printf("\n");
}
void ParkingDestroy(Parking** pcar)
{
SListDestroy(pcar);
}
五、主函数
源文件 ParkingTest.c
#include"SLT.h"
int main()
{
setlocale(LC_ALL, "");
system("mode con cols=100 lines=30");
system("title 泊车系统");
//登录系统
int entry = Entry();
if (entry == 1)
{
//进入系统
parking();
}
else
{
//退出系统
;
}
return 0;
}
六、操作提示
需要在控制台属性将终端修改为Windows控制台主机
显示结果
运行成功后就能按照提示进行接下来的操作了
登录账号1
密码1
选择界面
下载信息的文件路径由自己设定
车位样子如下:(星代表有车)