伙计们,我的代码应该创建一个学生的链接列表,并且必须为每个学生创建该学生的成绩的链接列表。我无法真正确定两个链接列表是否设置正确,因为当我尝试遍历列表时不会打印任何成绩。
struct Grade{
float score;
};
struct GradeNode{
Grade grade;
GradeNode *next_gnode;
};
struct StudentNode {
string name;
GradeNode *ghead;
StudentNode *next_snode;
};
StudentNode* head; //head of student linked list
下面的函数从文件中获取输入,并使用其值以及指向链接的成绩列表的指针(ghead)组成节点,首先将其设置为null。
void buildStudentList(string n){
StudentNode *newNode{ new StudentNode}; //initialize new Student node
StudentNode *curr; //to traverse thru Student lIst
//initialize student node
newNode->name = n;
newNode->next_snode = nullptr;
//have HEAD of THIS student's grades set to null, since there are no grades present for this student at this moment
newNode->ghead = nullptr;
//if student list is empty
if(!head){
//make this student node the head of the list
head = newNode;
}
else{
//else add it to the end of the list
curr = head;
//traverse to the end of the list
while(curr->next_snode){
curr= curr->next_snode;
}
//make grades for this student
buildGradeList(newNode->ghead, newNode->name);
//assign new node to the end of the list
curr->next_snode = newNode;
}
};
建立成绩列表功能
//parameter is Grade Head, where we will attach a grade link list to it
void buildGradeList(GradeNode *head, string n){
//NOTE: head is HEAD OF GRADE LIST
bool quit = false;
int x;
while (!quit) {
cout<<"ENTER GRADE FOR "<<n<< ": (0 to quit)"<<endl;
cin>>x;
cout<<endl;
if(x==0){
//exit while loop and return //when one presses 0, they go to the next student on the list!!!
quit=true;
}
else{
//append this value to head
appendGrades(head, x);
}
}
//return to prev function
return;
}
将成绩附加到链表中,头仍然不正常(该学生的成绩表头)
void appendGrades(GradeNode *head, int s){
//create a new node with new score value
GradeNode *new_grade = {new GradeNode};
new_grade->grade.score = s;
new_grade->next_gnode = nullptr;
//node to traverse list
GradeNode *curr;
if(!head){
head = new_grade;
}else{
curr=head;
while (curr->next_gnode) {
curr= curr->next_gnode;
}
curr->next_gnode = new_grade;
}
};
谢谢大家的投入!
答案 0 :(得分:5)
最简单的解决方案是将GradeNode * head
和GradeNode *& head
函数的签名中的buildGradeList
更改为appendGrades
。可以,但是我不建议您使用它,因为它错过了锻炼的重点。
您的代码对我来说似乎最正确(我还没有运行它,所以我不确定),除了一个问题:当您将成绩列表的开头传递给这两个函数时,就将它传递给了我按价值。这意味着将复制一个头部,并且您所做的所有更改都将被复制,这意味着它们不会生效,并且您学生的GradeNode * ghead
永远不会指向任何东西。
基于您在此处拥有的最正确的代码(以及基于我的经验,大多数程序员都在使用指针和链接列表),我认为您了解按值传递某些东西而不是将指针/引用传递给某种东西的概念。但是,要能够使用指针,您必须了解指针本身就是地址,即值。因此,当您将指针传递给函数时,可以修改其指向的对象的值,并且调用者可以看到该更改,但是对指针本身所做的任何更改都将在结束时丢失。功能,因为这些更改是针对地址的副本进行的,这意味着您无权访问-因此无法更改-原始地址。
所有这些都意味着在将指针传递给函数时,您无法更改其指向的位置。但是解决方案很简单。
当您想在函数内更改int
变量的值并使调用者看到更改时,您可以以int *
的形式将该整数的地址传递给函数。 。因此,如果要更改函数内部的“ int *”变量的值(不是指针指向的值,而是指针本身的值),则可以将该指针的地址以以下形式传递给函数int **
。
在您的情况下,这意味着您必须更改我提到的这两个功能的签名:
void buildGradeList(GradeNode **head, string n);
void appendGrades(GradeNode **head, int s);
当然,您还必须对appendGrade
的正文进行一些修改:
...
if(!*head){
*head = new_grade;
}else{
curr=*head;
...
这将是正确的,并且会起作用,而且将本着原始问题和您的解决方案的精神是正确的。
我在顶部建议的解决方案也可以使用,除了将&
(称为“引用”,或更确切地说是“左值引用”)添加到函数签名外,没有任何变化,因为这是正是C ++中的“引用”是什么。引用是不需要特殊语法的指针(无需*
即可取消引用,也无需&
即可获取某些地址。)这意味着引用更易于使用,但它们无法完成您使用指针所做的许多事情(例如,您无法找到链接列表末尾的循环无法使用引用以这种形式编写。)
但是我想提出更好的建议。排在成绩列表可能头上的这两个函数也会更改该列表。因此,我建议不要总是接受指向列表头的指针(或指向头的指针的引用),而应始终将指针返回到头。这意味着它们有时会返回一个新的头部指针,有时还会返回传递给它们的指针,但是它们自己并不会更改实际的头部指针。他们返回他们认为应该是头部的指针,然后让调用它们的人决定。
您需要进行的更改如下:
// First, change how we call buildGradeList inside buildStudentList:
newNode->ghead = buildGradeList(newNode->ghead, newNode->name);
// then, change the signature for buildGradeList:
GradeNode * buildGradeList (GradeNode * head, string n) {
// then, when you are calling appendGrades, store the value it returns in "head":
head = appendGrades(head, x);
// appendGrades will return the "head" (sometimes new, sometimes the same old one)
GradeNode * appendGrades (GradeNode *head, int s){
// just add this to the end of the appendGrades function:
return head;
就是这样。您也可以更改buildStudentList
函数以遵循此设计,并始终返回学生链接列表的头部(有时是新的,有时是相同的旧列表。)我相信这样做会更好,更有用,尤其是在更复杂的问题中/您以后会遇到的任务。