C++学生信息管理 1.0记录
该信息管理没有太多可支持的操作,仅有一些基础设置,后续优化中将添加更多功能。
一.头文件引用和命名空间声明
#include <iostream> //输入输出操作
#include <string> //字符串操作
using namespace std; //为方便使用,不需要在cout,string等前方加前缀std
二.学生节点的结构体定义。
用来存储学生的基本信息,其中包括学号,姓名,性别,年龄以及指向下一节点的指针。结构体中还包括了一个构造函数,用来初始化成员变量。
struct StudentNode
{
unsigned studentNumber; //学号
string name; //姓名
int age; //年龄
string sex; //性别
StudentNode *next; //指向下一节点的指针
//构造函数用于初始化成员变量
StudentNode(unsigned sn, const string &na, int ag, const string &se)
: studentNumber(sn), name(na), age(ag), sex(se), next(nullptr) {}
};
1.这里的学号用的为无符号类型,由于学号整型数太大,int类型可支持范围不够,在输入学号后会超出范围生成垃圾值。
2.因为考虑到以后会对该代码进行优化,添加一些功能,少不了插入与删除操作,所有用链表的形式用来存储信息,便于后续代码的优化。
3.构造函数接受四个参数,其中两个为常量引用类型,因为无需对传递过来的实参做更改处理,设置为常量类型更为合理与安全,且效率也更高。
4.对于unsigned
和int
类型的参数,一般不需要将它们声明为引用类型,因为它们是基础数据类型,传递它们的值通常非常快,且不会涉及额外的内存分配。传递值意味着会创建参数的副本,但对于这些基础类型,这个副本的创建通常是非常高效的。
5.初始化列表是构造函数独有的特性,在其它成员函数中无法使用。与在函数体里面作赋值操作相比,初始化列表往往伴有更快捷的效率以及更明了的意图。
6.在这里将next指向空指针nullprt,nullprt为C++的一个关键字,可直接使用,不需要引用任何头文件和作用域。
三.链表类的定义
class StudentLinkList
{
public:
//公开构造函数,初始化链表的头节点为nullptr
StudentLinkList() : head(nullptr) {}
// 析构函数声明,具体实现在类的外部定义
~StudentLinkList();
// 成员函数声明,用于向链表中添加学生信息
void addStudent(unsigned sn, const string &na, int ag,
const string &se);
// 成员函数声明,用于打印链表中的学生信息
void printStudent();
private:
// 私有成员变量,指向链表的头节点,初始时为nullptr
StudentNode *head;
};
1.在这里使用C++的新特性class类来做为链表,便于对数据与操作这些数据的方法做一个封装,与struct相比,class有更多支持的操作(struct与class本质上并无什么很大的区别,最直观的就是struct结构的成员变量及成员函数均是公开的,而class如果不显式表面public,则默认全是私有的)。以后在进行代码优化的时候添加一些功能也比较方便。
2.构造函数使用初始化列表将链表中的头指针指向nullprt(空指针)。
3.析构函数StudentLinkList();
这是StudentLinkList
类的析构函数声明,用于在对象生命周期结束时执行清理操作,释放链表占用的内存。具体的析构函数实现在类的外部定义。
4.将head
指针设置为私有是面向对象编程中常见的做法,它有助于实现代码的某些特性,就是面向对象编程的几大特性。
四.析构函数的定义
StudentLinkList::~StudentLinkList()
{
// 初始化一个指针current,指向链表的头节点head
StudentNode *current = head;
// 当current不为空时,说明还有节点需要被删除
while (current != nullptr)
{
// 保存当前节点的下一个节点的指针
StudentNode *next = current->next;
// 删除当前节点,释放其占用的内存
delete current;
// 将current指针移动到下一个节点,继续删除操作
current = next;
}
// 将头节点指针设置为nullptr,表示链表为空
head = nullptr;
}
1.在析构函数开始时,首先初始化一个指针current,并将其指向链表的头节点head。这是开始遍历链表并删除节点的起点。
2.使用while循环来遍历链表中的每一个节点。循环继续的条件是current不为nullptr,即还有节点未被处理。
3.在删除当前节点之前,通过current->next保存下一个节点的指针到next变量中。这是因为一旦当前节点被删除,我们就无法通过它访问下一个节点了。
4.使用delete操作符(这是C++中的关键字,相当于C语言中的free())释放当前节点current所占用的内存。这会将该节点从内存中移除,并且任何对该节点的引用都将变得无效。
5.将current指针更新为next,即我们之前保存的下一个节点的指针。这样,在下一次循环迭代时,我们就可以处理链表中的下一个节点。
6.循环继续,直到current变为nullptr,表示链表中的所有节点都已被删除。
7.最后,将头节点指针head置为nullptr,表示链表现在为空。这是一个很重要的步骤,因为它确保了head指针不再指向任何已删除的内存区域,从而避免了很大的安全风险。
五.增添函数的定义
void StudentLinkList::addStudent(unsigned sn, const string &na,
int ag, const string &se)
{
//创建一个新的StudentNode对象,并使用传入的参数初始化它。这个新节点会被添加到链表的末尾。
StudentNode *newNode = new StudentNode(sn, na, ag, se);
//如果链表为空(即head为nullptr),则直接将新节点设置为链表的头节点。
if (head == nullptr)
{
head = newNode;
}
//如果链表不为空,初始化一个指针current,使其指向链表的头节点。
else
{
StudentNode *current = head;
//使用一个循环遍历链表,直到找到链表的最后一个节点(即next指针为nullptr的节点)。
while (current->next != nullptr)
{
current = current->next;
}
//将最后一个节点的next指针指向新创建的节点,从而将新节点添加到链表的末尾
current->next = newNode;
}
}
1.该函数操作为链表的基本操作,因为定义的函数体代码多,与上面的析构函数一样定义在了类外,所以要加上::作用域解析运算符,告诉编译器所属范围。
六.打印函数的定义
//用于打印出学生信息
void StudentLinkList::printStudent()
{
//将当前节点指向头节点
StudentNode *current = head;
//遍历整个链表,对联表内的所有内容进行打印
while (current != nullptr)
{
cout << "Student Number: " << current->studentNumber
<< ", Name: " << current->name
<< ", Age: " << current->age
<< ", Sex: " << current->sex << endl;
//打印完当前节点后将指针移动向下一节点
current = current->next;
}
}
七.函数主体
int main()
{
StudentLinkList student;
student.addStudent(2410145903, "Zhangsan", 18, "Man");
student.addStudent(2415343923, "Lisi", 21, "Man");
student.addStudent(2345351878, "Wangwu", 19, "Man");
student.printStudent();
return 0;
}
这个管理信息没有什么较为复杂的操作,在后续还将进行优化,增添一些插入和删除学生信息的操作,该系统学生信息的获取也是比较直观,在后续的优化中会进行一些升级。
八.完整代码
#include <iostream> //输入输出操作
#include <string> //字符串操作
using namespace std; //为方便使用,不需要在cout,string等前方加前缀std
//结构体的声明,学生的基本信息存储
struct StudentNode
{
unsigned studentNumber; //学号
string name; //姓名
int age; //年龄
string sex; //性别
StudentNode *next; //指向下一节点的指针
//构造函数用于初始化成员变量
StudentNode(unsigned sn, const string &na, int ag, const string &se)
: studentNumber(sn), name(na), age(ag), sex(se), next(nullptr) {}
};
//链表类的声明
class StudentLinkList
{
public:
//公开构造函数,初始化链表的头节点为nullptr
StudentLinkList() : head(nullptr) {}
// 析构函数声明,具体实现在类的外部定义
~StudentLinkList();
// 成员函数声明,用于向链表中添加学生信息
void addStudent(unsigned sn, const string &na, int ag,
const string &se);
// 成员函数声明,用于打印链表中的学生信息
void printStudent();
private:
// 私有成员变量,指向链表的头节点,初始时为nullptr
StudentNode *head;
};
//析构函数定义
StudentLinkList::~StudentLinkList()
{
// 初始化一个指针current,指向链表的头节点head
StudentNode *current = head;
// 当current不为空时,说明还有节点需要被删除
while (current != nullptr)
{
// 保存当前节点的下一个节点的指针
StudentNode *next = current->next;
// 删除当前节点,释放其占用的内存
delete current;
// 将current指针移动到下一个节点,继续删除操作
current = next;
}
// 将头节点指针设置为nullptr,表示链表为空
head = nullptr;
}
//增添学生信息
void StudentLinkList::addStudent(unsigned sn, const string &na,
int ag, const string &se)
{
//创建一个新的StudentNode对象,并使用传入的参数初始化它。这个新节点会被添加到链表的末尾。
StudentNode *newNode = new StudentNode(sn, na, ag, se);
//如果链表为空(即head为nullptr),则直接将新节点设置为链表的头节点。
if (head == nullptr)
{
head = newNode;
}
//如果链表不为空,初始化一个指针current,使其指向链表的头节点。
else
{
StudentNode *current = head;
//使用一个循环遍历链表,直到找到链表的最后一个节点(即next指针为nullptr的节点)。
while (current->next != nullptr)
{
current = current->next;
}
//将最后一个节点的next指针指向新创建的节点,从而将新节点添加到链表的末尾
current->next = newNode;
}
}
//用于打印出学生信息
void StudentLinkList::printStudent()
{
//将当前节点指向头节点
StudentNode *current = head;
//遍历整个链表,对联表内的所有内容进行打印
while (current != nullptr)
{
cout << "Student Number: " << current->studentNumber
<< ", Name: " << current->name
<< ", Age: " << current->age
<< ", Sex: " << current->sex << endl;
//打印完当前节点后将指针移动向下一节点
current = current->next;
}
}
int main()
{
StudentLinkList student;
student.addStudent(2410145903, "Zhangsan", 18, "Man");
student.addStudent(2415343923, "Lisi", 21, "Man");
student.addStudent(2345351878, "Wangwu", 19, "Man");
student.printStudent();
return 0;
}