C++ - 在统计分配的数组中打印对象会导致分段错误
C++ - printing objects in statistically allocated array causes segmentation fault
所以我正在创建一个程序来实现多个 classes 代表一所学校及其学生和课程。当我尝试打印出 studentCoursePairs[] 数组中的所有 Taken 对象时,我遇到了分段错误,该数组代表参加特定课程的 Student 对象。我认为我的分段错误来自 School.cc 中的 addTaken() 函数,它的工作是找到具有给定学号和课程 ID 的学生对象和课程对象,然后用找到的学生创建一个新的 Taken 对象和课程对象以及成绩。然后我尝试将这个新对象添加到 Taken 集合的后面,即 studentCoursePairs。
当我注释掉 studentCoursePairs[i]->print() 时,分段错误消失了。我不太确定我做错了什么,希望得到一些帮助。
我不确定除了 School.cc 之外是否还需要其他 classes,但我还是将它们包括在内以帮助理解。
School.cc:
#include <iostream>
#include <iomanip>
using namespace std;
#include <string.h>
#include "School.h"
School::School(string s1) : name(s1){
numTaken = 0;
}
void School::addTaken(string number, int code, string grade){
Student* s = nullptr;
Course* c = nullptr;
for(int i = 0; i < numTaken; ++i){
if((studentsCollection->find(number, &s)) && (coursesCollection->find(code, &c))){
Taken* taken = new Taken(s, c, grade);
studentCoursePairs[i] = taken;
++numTaken;
}
}
}
void School::printTaken(){
cout << name << " === TAKEN: "<< endl;
for(int i = 0; i < sizeof(studentCoursePairs)/sizeof(studentCoursePairs[0]); ++i){
studentCoursePairs[i]->print(); //seg fault
}
}
其他文件:
StudentCollection.cc
bool StudentCollection::find(string num, Student** s){
for(int i = 0; i < size; ++i){
if(students[i]->getNumber() == num){ //find student number
*s = students[i];
}
}
}
CoursesCollection.cc
bool CoursesCollection::find(int id, Course** c){
for(int i = 0; i < numCourses; ++i){
if(courses[i]->getId() == id){ //find course id
*c = courses[i];
}
}
}
我还有一个学生 class 和课程 class,它们只是声明和初始化信息,例如学生的姓名、课程、gpa 以及课程代码、讲师、姓名、年份一门课程。
您的 School 对象有两个主要问题。让我们从您在问题中发布的那个开始:
void School::printTaken(){
cout << name << " === TAKEN: "<< endl;
for(int i = 0; i < sizeof(studentCoursePairs)/sizeof(studentCoursePairs[0]); ++i){
studentCoursePairs[i]->print(); //seg fault
}
}
这个 for 循环总是 运行 正好 MAX_PAIRS 次,因为这个变量被定义为
Taken* studentCoursePairs[MAX_PAIRS];
所以sizeof(studentCoursePairs) === MAX_PAIRS * sizeof(studentCoursePairs[0])
.
相反,您只想循环实际包含有效指针的前几个槽。你有一个变量:numTaken
。因此,将条件更改为 i < numTaken
并且您的打印循环将起作用。
第二个主要问题在addTaken
:
void School::addTaken(string number, int code, string grade){
Student* s = nullptr;
Course* c = nullptr;
for(int i = 0; i < numTaken; ++i){
if((studentsCollection->find(number, &s)) && (coursesCollection->find(code, &c))){
Taken* taken = new Taken(s, c, grade);
studentCoursePairs[i] = taken;
++numTaken;
}
}
}
让我们来玩玩电脑,看看如果输入的数字和代码有效会发生什么:
- 如果 numTaken 为 0,则循环立即停止(因为
0 < 0
为假)并且 numTaken 不递增。 addTaken
随便叫,永远不会变numTaken
- 假设你解决了这个问题,让我们假设 numTaken = 5。在第一次迭代中,你检查条件并同意这是一个有效的 number-code 组合。因此,您创建了一个新的 Taken 对象并 .. 用新对象覆盖
studentCoursePairs[0]
。在第二次迭代中,您执行相同的操作并用等效对象覆盖 studentCoursePairs[1]
。
这可能不是预期的行为。
相反,您可能想在 studentCoursePairs[numTaken]
中放置一个新对象并碰撞 numTaken
:
void School::addTaken(string number, int code, string grade){
Student* s = nullptr;
Course* c = nullptr;
if((studentsCollection->find(number, &s)) && (coursesCollection->find(code, &c))){
Taken* taken = new Taken(s, c, grade);
studentCoursePairs[numTaken] = taken;
++numTaken;
}
}
弄清楚如何处理传递的组合无效或超过 MAX_PAIRS 组合的情况留给您作为练习。
编辑:您的 CoursesCollection 中存在第三个主要问题:您为一个对象 new Course()
分配 space,同时将其视为数组,并将结果存储在局部变量中的一个成员。你的构造函数应该看起来像:
CoursesCollection::CoursesCollection(){
courses = new Course*[MAX_COURSES];
numCourses = 0;
}
或者,使用成员初始值设定项列表:
CoursesCollection::CoursesCollection()
: courses(new Course*[MAX_COURSES]), numCourses(0) {}
所以我正在创建一个程序来实现多个 classes 代表一所学校及其学生和课程。当我尝试打印出 studentCoursePairs[] 数组中的所有 Taken 对象时,我遇到了分段错误,该数组代表参加特定课程的 Student 对象。我认为我的分段错误来自 School.cc 中的 addTaken() 函数,它的工作是找到具有给定学号和课程 ID 的学生对象和课程对象,然后用找到的学生创建一个新的 Taken 对象和课程对象以及成绩。然后我尝试将这个新对象添加到 Taken 集合的后面,即 studentCoursePairs。
当我注释掉 studentCoursePairs[i]->print() 时,分段错误消失了。我不太确定我做错了什么,希望得到一些帮助。
我不确定除了 School.cc 之外是否还需要其他 classes,但我还是将它们包括在内以帮助理解。
School.cc:
#include <iostream>
#include <iomanip>
using namespace std;
#include <string.h>
#include "School.h"
School::School(string s1) : name(s1){
numTaken = 0;
}
void School::addTaken(string number, int code, string grade){
Student* s = nullptr;
Course* c = nullptr;
for(int i = 0; i < numTaken; ++i){
if((studentsCollection->find(number, &s)) && (coursesCollection->find(code, &c))){
Taken* taken = new Taken(s, c, grade);
studentCoursePairs[i] = taken;
++numTaken;
}
}
}
void School::printTaken(){
cout << name << " === TAKEN: "<< endl;
for(int i = 0; i < sizeof(studentCoursePairs)/sizeof(studentCoursePairs[0]); ++i){
studentCoursePairs[i]->print(); //seg fault
}
}
其他文件:
StudentCollection.cc
bool StudentCollection::find(string num, Student** s){
for(int i = 0; i < size; ++i){
if(students[i]->getNumber() == num){ //find student number
*s = students[i];
}
}
}
CoursesCollection.cc
bool CoursesCollection::find(int id, Course** c){
for(int i = 0; i < numCourses; ++i){
if(courses[i]->getId() == id){ //find course id
*c = courses[i];
}
}
}
我还有一个学生 class 和课程 class,它们只是声明和初始化信息,例如学生的姓名、课程、gpa 以及课程代码、讲师、姓名、年份一门课程。
您的 School 对象有两个主要问题。让我们从您在问题中发布的那个开始:
void School::printTaken(){
cout << name << " === TAKEN: "<< endl;
for(int i = 0; i < sizeof(studentCoursePairs)/sizeof(studentCoursePairs[0]); ++i){
studentCoursePairs[i]->print(); //seg fault
}
}
这个 for 循环总是 运行 正好 MAX_PAIRS 次,因为这个变量被定义为
Taken* studentCoursePairs[MAX_PAIRS];
所以sizeof(studentCoursePairs) === MAX_PAIRS * sizeof(studentCoursePairs[0])
.
相反,您只想循环实际包含有效指针的前几个槽。你有一个变量:numTaken
。因此,将条件更改为 i < numTaken
并且您的打印循环将起作用。
第二个主要问题在addTaken
:
void School::addTaken(string number, int code, string grade){
Student* s = nullptr;
Course* c = nullptr;
for(int i = 0; i < numTaken; ++i){
if((studentsCollection->find(number, &s)) && (coursesCollection->find(code, &c))){
Taken* taken = new Taken(s, c, grade);
studentCoursePairs[i] = taken;
++numTaken;
}
}
}
让我们来玩玩电脑,看看如果输入的数字和代码有效会发生什么:
- 如果 numTaken 为 0,则循环立即停止(因为
0 < 0
为假)并且 numTaken 不递增。addTaken
随便叫,永远不会变numTaken
- 假设你解决了这个问题,让我们假设 numTaken = 5。在第一次迭代中,你检查条件并同意这是一个有效的 number-code 组合。因此,您创建了一个新的 Taken 对象并 .. 用新对象覆盖
studentCoursePairs[0]
。在第二次迭代中,您执行相同的操作并用等效对象覆盖studentCoursePairs[1]
。
这可能不是预期的行为。
相反,您可能想在 studentCoursePairs[numTaken]
中放置一个新对象并碰撞 numTaken
:
void School::addTaken(string number, int code, string grade){
Student* s = nullptr;
Course* c = nullptr;
if((studentsCollection->find(number, &s)) && (coursesCollection->find(code, &c))){
Taken* taken = new Taken(s, c, grade);
studentCoursePairs[numTaken] = taken;
++numTaken;
}
}
弄清楚如何处理传递的组合无效或超过 MAX_PAIRS 组合的情况留给您作为练习。
编辑:您的 CoursesCollection 中存在第三个主要问题:您为一个对象 new Course()
分配 space,同时将其视为数组,并将结果存储在局部变量中的一个成员。你的构造函数应该看起来像:
CoursesCollection::CoursesCollection(){
courses = new Course*[MAX_COURSES];
numCourses = 0;
}
或者,使用成员初始值设定项列表:
CoursesCollection::CoursesCollection()
: courses(new Course*[MAX_COURSES]), numCourses(0) {}