The following is a relatively short and simple program that creates an array of student objects. Information for each student is read in, and then printed out.
The reading in part works fine. However, once the data starts printing, the program crashes.
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class Student{
private:
string name;
int year;
static string year_name[4];
string semester;
int num_courses;
public:
//Constructor
Student()
{
string name = "";
int year = 0;
string semester = "";
int num_courses = 0;
}
// Copy Constructor
Student(const Student& rhs)
{
this->name = rhs.name;
this->year = rhs.year;
this->semester = rhs.semester;
this->num_courses = rhs.num_courses;
}
// Set functions
void setName(string stName){name = stName;}
void setYear(int yr){year = yr;}
void setSemester(string currentSemester){semester = currentSemester;}
void setCourses(int courses){num_courses = courses;}
// Get functions;
string getName(){return name;}
int getYear(){return year;}
string getSemester(){return semester;}
int getCourses(){return num_courses;}
string getYearName()
{
if(year==1)
return year_name[0];
if(year==2)
return year_name[1];
if(year==3)
return year_name[2];
if(year==4)
return year_name[4];
elsereturn year_name[0];
}
};
// Definition of static array
string Student::year_name[4] = {"Freshman", "Sophomore", "Junior", "Senior"};
//Prototype functions
void readStudentData(Student&);
void printStudentData(Student);
int main()
{
cout << "Enter in number of students: ";
int numb_students;
cin >> numb_students;
cout << "\n\n";
int * pointer = newint [numb_students]; // allocate memory
Student student[numb_students]; // create array of objects
// pass each object to function one by one
for(int i=0; i<numb_students; i++)
readStudentData(student[i]);
// pass each object to function one by one
for(int i=0; i<numb_students; i++)
printStudentData(student[i]);
delete [] pointer; // deallocate memmory
pointer = 0; // set pointer to NULL
return 0;
}
// Passing by reference, copy constructor not used
void readStudentData(Student& student)
{
string stname, currentSemester;
int yr, courses;
staticint s=1; // static variable to keep track of student number
// Read in a bunch of data from standard input
cout << "Enter name of student " << s << ": ";
cin.ignore();
getline(cin, stname);
cout << "Enter year number of student (1-4) " << s << ": ";
cin >> yr;
cout << "Enter current semester of student " << s << ": ";
cin.ignore();
getline(cin, currentSemester);
cout << "Enter number of courses student " << s << " is taking: ";
cin >> courses;
cout << "\n\n";
//Put data into object
student.setName(stname);
student.setYear(yr);
student.setSemester(currentSemester);
student.setCourses(courses);
s++; // increment static variable
}
// Passing by value, copy constructor used
void printStudentData(Student student)
{
staticint s = 1; // static variable again
// Print out data for object
cout << "Name of student " << s << ": " << student.getName() << endl;
cout << "Student " << s << " is a: " << student.getYearName() << endl;
cout << "Current semester of student " << s << ": " << student.getSemester() << endl;
cout << "Number of courses student " << s << " is taking: " << student.getCourses() << endl;
cout << "\n\n";
s++;
}
Here is my output:
Enter in number of students: 3
Enter name of student 1: Arslan Sana
Enter year number of student (1-4) 1: 2
Enter current semester of student 1: Fall, 2015
Enter number of courses student 1 is taking: 5
Enter name of student 2: John Wick
Enter year number of student (1-4) 2: 3
Enter current semester of student 2: Fall, 2014
Enter number of courses student 2 is taking: 5
Enter name of student 3: Alex Trebek
Enter year number of student (1-4) 3: 4
Enter current semester of student 3: Fall, 2015
Enter number of courses student 3 is taking: 6
Name of student 1: Arslan Sana
Student 1 is a: Sophomore
Current semester of student 1: Fall, 2015
Number of courses student 1 is taking: 5
Name of student 2: John Wick
Student 2 is a: Junior
Current semester of student 2: Fall, 2014
Number of courses student 2 is taking: 5
Name of student 3: Alex Trebek
Process returned 255 (0xFF) execution time : 54.112 s
Press any key to continue.
As you can see, the program crashed before printing could be completed. The pop-up message displayed "Lab7.exe. has stopped working" (lab7 is just the name of the project on codeblocks).
$ gdb a.out
> run < input
(Program received signal SIGSEGV, Segmentation fault.)
> backtrace
#0 std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string (this=0x7fffffffdeb0,
__str=<error reading variable: Cannot access memory at address 0xffffffffffffffe8>)
at /build/gcc/src/gcc-build/x86_64-unknown-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:617
#1 0x0000000000401abe in Student::getYearName (this=0x7fffffffdf80) at foo.cpp:55
#2 0x000000000040140e in printStudentData (student=...) at foo.cpp:130
#3 0x0000000000401052 in main () at foo.cpp:85
> frame 1
#1 0x0000000000401abe in Student::getYearName (this=0x7fffffffdf80) at foo.cpp:55
55 return year_name[4];
But the declaration is static string year_name[4];, index 4 is invalid, you are accessing out of bounds.
Because out of bounds is undefined behaviour, you may not be lucky enough to get a crash. Another way to detect it
$ valgrind ./a.out < input
==19600== Invalid read of size 4
==19600== at 0x4F0473B: _M_is_leaked (basic_string.h:2588)
==19600== by 0x4F0473B: _M_grab (basic_string.h:2624)
==19600== by 0x4F0473B: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (basic_string.tcc:617)
==19600== by 0x401ABD: Student::getYearName() (foo.cpp:55)
==19600== by 0x40140D: printStudentData(Student) (foo.cpp:130)
==19600== by 0x401051: main (foo.cpp:85)
==19600== Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd
It tells you that you are trying to access memory that you don't own (it works better with dynamic allocated memory)