请解释一下函数中每个参数的意义

这是定义的结构体

//定义计费信息结构体,保留每次上机的信息
struct Billing
{
char aCardName[18]; //卡号
time_t tStart; //上机时间
time_t tEnd; //下机时间
float fAmount; //消费金额
int nStatus; //消费状态,0-未结算,1-已经结算
int nDel; //删除标识,0-未删除,1-删除
};

//定义计费信息链表结点类型
struct BillingNode
{
Billing data;
struct BillingNode* next;
};

这是函数部分

BillingNode* BillListInit(const string billingFilename)
{
ifstream billingfile(billingFilename);

BillingNode* pBillingNode, * pBillingNodeHead, * pBillingNodeTail;
Billing billing;

if (!billingfile.is_open())
{
    return NULL;
}

pBillingNodeHead = NULL;
pBillingNodeTail = NULL;

while (1)
{
    billingfile.read((char*)&billing, sizeof(Billing));
    if (billingfile.eof())
    {
        break;
    }

    pBillingNode = new BillingNode;
    pBillingNode->data = billing;

    if (pBillingNodeHead == NULL)
    {
        pBillingNodeHead = pBillingNode;
        pBillingNodeTail = pBillingNode;
    }
    else
    {
        pBillingNodeTail->next = pBillingNode;
        pBillingNodeTail = pBillingNode;
    }
}

pBillingNodeTail->next = NULL;

billingfile.close();

return pBillingNodeHead;

}

看不懂这个函数,希望有人帮忙解释一下

//定义计费信息结构体,保留每次上机的信息
struct Billing
{
char aCardName[18]; //卡号
time_t tStart; //上机时间
time_t tEnd; //下机时间
float fAmount; //消费金额
int nStatus; //消费状态,0-未结算,1-已经结算
int nDel; //删除标识,0-未删除,1-删除
};

//定义计费信息链表结点类型
struct BillingNode
{
Billing data;//链表结构中的数据部分
struct BillingNode* next;//指向下一个节点
};

这是函数部分
BillingNode* BillListInit(const string billingFilename)//要打开的文件名
{
ifstream billingfile(billingFilename);//打开文件

BillingNode* pBillingNode, * pBillingNodeHead, * pBillingNodeTail;//三个链表结构体指针,分别表示当前,表头,表尾
Billing billing;
 
if (!billingfile.is_open())//判断文件是否打开
{
    return NULL;
}
 //重置指针
pBillingNodeHead = NULL;
pBillingNodeTail = NULL;
 
while (1)
{
    //读取文件判断异常情况
    billingfile.read((char*)&billing, sizeof(Billing));
    if (billingfile.eof())
    {
        break;
    }
 
    //创建一个链表指针,数据部分指向从文件读取的数据
    pBillingNode = new BillingNode;
    pBillingNode->data = billing;
 
    //判断表头是否为空,为空则把new的指针pBillingNode放到头部,首尾指向同一个(因为只有一个)
    if (pBillingNodeHead == NULL)
    {
        pBillingNodeHead = pBillingNode;
        pBillingNodeTail = pBillingNode;
    }
    else  //不为空,则把当前指针放到尾部
    {
        pBillingNodeTail->next = pBillingNode;
        pBillingNodeTail = pBillingNode;
    }
}
 
pBillingNodeTail->next = NULL;//尾部指针指向空,避免悬挂
 
billingfile.close();//关闭文件
 
return pBillingNodeHead;//返回表头(从这里可以开始读取从文件中获取的数据)
}