Segmentation Fault Error

Even though the source compiles with no error, I'm having some segmentation fault error in my program when I run the debugger. This program creates a dynamic database that implements the vector class, pointers, and dynamic arrays/objects, and is to be tested on the main function. I have no idea which part of the code is causing this issue, nor do I know how to fix it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
// Preprocessor directives
#include <cstdlib>
#include <iostream>
#include <string>

// Avoid name conflicts.
using namespace std;

/*---------------------------- CLASS DECLARATIONS ----------------------------*/

class Person
{
      public:
       Person();
       Person(int ID, string firstName, string lastName);
       string getFirstName();
       string getLastName();
       int getID();
       bool equals(const Person& theOtherPerson);
      private:
       string firstName;
       string lastName;
       int ID;
};

class Student: public Person
{
      public:
       Student();
       Student(int ID, string firstName, string lastName, string major, int collegeYear);
      private:
       string major;
       int collegeYear;
};

class Vector
{
      public:
       Vector();
       int getCapacity();
       int getSize();
       int getIndex(int ID);
       Student get(int index);
       void print();
       bool add(Student *newStudent);
       int remove(int productID);
      private:
       Student *list[];
       int capacity;
       int size;
};

class Database
{
      public:
       Database();
       bool add(int ID, string firstName, string lastName, string major, int collegeYear);
       int remove(int ID);
       Student get(int index);
       int getIndex(int ID);
       void print();
      private:
       Vector *list;
};

/*----------------------------- 'main' FUNCTION ------------------------------*/

int main ()
{
  Database *testDatabase = new Database();
  testDatabase->remove(2);

  testDatabase->add(1, "John", "Doe", "Computer Science", 4);
  testDatabase->add(2, "Jane", "Doe", "Computer Science", 3);
  testDatabase->add(3, "Joe", "Shmoe", "Computer Science", 2);

  testDatabase->print();

  testDatabase->add(3, "Joe", "Shmoe", "Computer Science", 2);

  testDatabase->remove(2);

  testDatabase->print();
  
  system("PAUSE");
  return 0;
}

/*--------------------------- FUNCTION DEFINITIONS ---------------------------*/

Person::Person()
{
}

Person::Person(int ID, string firstName, string lastName)
{
     this->firstName = firstName;
     this->lastName = lastName;
     this->ID = ID;
}

string Person::getFirstName()
{
     return firstName;
}

string Person::getLastName()
{
     return lastName;
}

int Person::getID()
{
    return ID;
}

bool Person::equals(const Person& theOtherObject)
{
     if(!(this->firstName.compare(theOtherObject.firstName)) && !(this->lastName.compare(theOtherObject.lastName)) && (this->ID == theOtherObject.ID))
     {
       return true;
     }
     else
     {
       return false;
     }
}

Student::Student()
{
}

Student::Student(int ID, string firstName, string lastName, string major, int collegeYear):Person(ID, firstName, lastName)
{
     this->major = major;
     this->collegeYear = collegeYear;
}

Vector::Vector():capacity(2), size(0)
{
     *list = new Student[capacity];
}

int Vector::getCapacity()
{
     return capacity;
}

int Vector::getSize()
{
     return size;
}

int Vector::getIndex(int ID)
{
  int index = -1;
  
  for(int i=0; i<size; i++)
  {
    if(list[i]->getID() == ID)
    {
      index = i;
    }
  }
  
  return index;
}

Student Vector:: get(int index)
{
  return *list[index];
}

void Vector::print()
{
  for(int i=0; i<size; i++)
  {
    cout << list[i]->getID() << " " << list[i]->getFirstName() << " " << list[i]->getLastName() << "\n";
  }
}

bool Vector::add(Student *newStudent)
{
  bool result = true;
  int index = getIndex(newStudent->getID());
  if(index == -1)
  {
    if(size < capacity)
    {
      *list[size] = *newStudent;
      size++;
    }
    else //grow
    {
      capacity *= 2;
      Student *tmpList = new Student[capacity]; 
      for(int i=0; i<size; i++)
      {
        tmpList[i] = *list[i];
        *list = tmpList;
        *list[size] = *newStudent;
        size++;
      }
    }
  }
  else
  {
    result = false;
  }
  
  return result;
}

int Vector::remove(int productID)
{
  int result = 1;
  int index = getIndex(productID);
  if(index == -1)
  {
    result = index;
  }
  else
  {
    for(int i = index; i < size-1; i++)
    {
      *list[i] = *list[i+1];
      size -= 1;
    }
    if(size*2 == capacity) //shrink
    {
      capacity /= 2;
      Student *tmpList = new Student[capacity];
      for(int i=0; i<size; i++)
      {
        tmpList[i] = *list[i];
      }
      *list = tmpList;
      size = capacity;
    }
  }
  
  return result;
}

Database::Database()
{
  Vector *list = new Vector();
}

bool Database::add(int ID, string firstName, string lastName, string major, int collegeYear)
{
  bool result = list->add(new Student(ID, firstName, lastName, major, collegeYear));
  if(!result)
  {
    cout << "This student(" << ID << ") is already in the database.\n";
  }
  else
  {
    cout << ID << " has been been added.\n";
  }
  
  return result;
}

int Database::remove(int ID)
{
  int result = list->remove(ID);
  if(result == -1)
  {
    cout << "This student (" << ID << ") is not in the database.\n";
  }
  else
  {
    cout << "This student (" << ID << ") has been deleted.\n";
  }
  
  return result;
}

Student Database::get(int index)
{
  return list->get(index);
}

int Database::getIndex(int ID)
{
  return list->getIndex(ID);
}

void Database::print()
{
  return list->print();
}
Last edited on
I have no idea which part of the code is causing this issue,

How is that? The debugger will show you the line that caused the segmentation fault.
Okay, let me clarify. The debugger stops right before iterating the for loop on the Vector::getIndex function, but there are no compiler issues there, so I don't know where the segmentation error arises from.
Not sure what you mean by "compiler issues", but if it stops on the loop, then the segmentation fault is caused by accessing size, which means the function was called for an invalid instance.
The debugger will tell you more than just the line - in particular, it can tell you the values of variables at the time of the crash (including the this pointer) and the callstack.

This looks fishy, by the way: Vector *list = new Vector();
You create a Vector using new, but forget about the pointer right away. So that's just a memory leak and probably doesn't do what you want.
Talking about memory leaks, there are lots of "new"s in your program (more than there should be), but not a single delete (nor smart pointers or anything else of that sort).
The implicit several "new" in #70 during the declaring of the testDatabase is a little unusual. I suspect there is some problem during that objects constructing.

What I could suggest is: make those "new" (list assignings) explicitly. Firstly avoid using "new" assigning in constructors, take them out from the constructors and explicitly assign them one by one to your private numbers in main function, make sure every object gets its place. Once it's clear, you can then wrap them into constructor later on. First make the thing simpler.
Thank you all for your suggestions. I've finally got up to 2 objects constructing, but then it gets stuck when I either display or add another object. I've added the delete commands and still couldn't troubleshoot where the trouble is coming from. Here is how it looks like now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
// Preprocessor directives
#include <cstdlib>
#include <iostream>
#include <string>

// Avoid name conflicts.
using namespace std;

/*---------------------------- CLASS DECLARATIONS ----------------------------*/

class Person
{
      public:
       Person();
       Person(int ID, string firstName, string lastName);
       string getFirstName();
       string getLastName();
       int getID();
       bool equals(const Person& theOtherPerson);
      private:
       string firstName;
       string lastName;
       int ID;
};

class Student: public Person
{
      public:
       Student();
       Student(int ID, string firstName, string lastName, string major, int collegeYear);
      private:
       string major;
       int collegeYear;
};

class Vector
{
      public:
       Vector();
       int getCapacity();
       int getSize();
       int getIndex(int ID);
       Student get(int index);
       void print();
       bool add(Student *newStudent);
       int remove(int productID);
      private:
       Student *list[];
       int capacity;
       int size;
};

class Database
{
      public:
       Database();
       bool add(int ID, string firstName, string lastName, string major, int collegeYear);
       int remove(int ID);
       Student get(int index);
       int getIndex(int ID);
       void print();
      private:
       Vector *list;
};

/*----------------------------- 'main' FUNCTION ------------------------------*/

int main ()
{
  Database *testDatabase = new Database();
  testDatabase->remove(2);

  testDatabase->add(1, "John", "Doe", "Computer Science", 4);
  testDatabase->add(2, "Jane", "Doe", "Computer Science", 3);
  testDatabase->add(3, "Joe", "Shmoe", "Computer Science", 2);

  testDatabase->print();

  testDatabase->add(3, "Joe", "Shmoe", "Computer Science", 2);

  testDatabase->remove(2);

  testDatabase->print();
  
  delete testDatabase; // delete dynamic Database object
  testDatabase = NULL; // prevent dangling pointer
  
  system("PAUSE");
  return 0;
}

/*--------------------------- FUNCTION DEFINITIONS ---------------------------*/

Person::Person()
{
}

Person::Person(int ID, string firstName, string lastName)
{
     this->firstName = firstName;
     this->lastName = lastName;
     this->ID = ID;
}

string Person::getFirstName()
{
     return firstName;
}

string Person::getLastName()
{
     return lastName;
}

int Person::getID()
{
    return ID;
}

bool Person::equals(const Person& theOtherObject)
{
     if(!(this->firstName.compare(theOtherObject.firstName)) && !(this->lastName.compare(theOtherObject.lastName)) && (this->ID == theOtherObject.ID))
     {
       return true;
     }
     else
     {
       return false;
     }
}

Student::Student()
{
}

Student::Student(int ID, string firstName, string lastName, string major, int collegeYear):Person(ID, firstName, lastName)
{
     this->major = major;
     this->collegeYear = collegeYear;
}

Vector::Vector():capacity(2), size(0)
{
     *list = new Student[capacity];
}

int Vector::getCapacity()
{
     return capacity;
}

int Vector::getSize()
{
     return size;
}

int Vector::getIndex(int ID)
{
  int index = -1;
  
  for(int i=0; i<size; i++)
  {
    if(list[i]->getID() == ID)
    {
      index = i;
    }
  }
  
  return index;
}

Student Vector::get(int index)
{
  return *list[index];
}

void Vector::print()
{
  for(int i=0; i<size; i++)
  {
    cout << list[i]->getID() << " " << list[i]->getFirstName() << " " << list[i]->getLastName() << "\n";
  }
}

bool Vector::add(Student *newStudent)
{
  bool result = true;
  int index = getIndex(newStudent->getID());
  if(index == -1)
  {
    if(size < capacity)
    {
      list[size] = newStudent;
      size++;
    }
    else //grow
    {
      capacity *= 2;
      Student *tmpList = new Student[capacity]; // creates a new pointer array with twice the capacity
      for(int i=0; i<size; i++)
      {
        tmpList[i] = *list[i]; // assigns each pointer in array to each dynamic Student object
        delete list[i]; // deletes dynamic Student objects
      }
      delete [] list; // deletes pointer array that pointed to the dynamic Student objects
      *list = tmpList; // assigns new pointer array to temp pointer array
      list[size] = newStudent; // assigns new dynamic student object to next pointer in array 
      size++;
    }
  }
  else
  {
    result = false;
  }
  
  return result;
}

int Vector::remove(int productID)
{
  int result = 1;
  int index = getIndex(productID);
  if(index == -1)
  {
    result = index;
  }
  else
  {
    for(int i = index; i < size-1; i++)
    {
      list[i] = list[i+1];
      size -= 1;
    }
    if(size*2 == capacity) //shrink
    {
      capacity /= 2;
      Student *tmpList = new Student[capacity]; // creates a new pointer array with half the capacity
      for(int i=0; i<size; i++)
      {
        tmpList[i] = *list[i]; // assigns each pointer in array to each dynamic Student object
        delete list[i]; // deletes dynamic Student objects
      }
      delete [] list; // deletes pointer array that pointed to the dynamic Student objects
      *list = tmpList; // assigns new pointer array to temp pointer array
      size = capacity;
    }
  }
  
  return result;
}

Database::Database()
{
  Vector *list = new Vector();
}

bool Database::add(int ID, string firstName, string lastName, string major, int collegeYear)
{
  bool result = list->add(new Student(ID, firstName, lastName, major, collegeYear));
  if(!result)
  {
    cout << "This student(" << ID << ") is already in the database.\n";
  }
  else
  {
    cout << ID << " has been been added.\n";
  }
  
  return result;
}

int Database::remove(int ID)
{
  int result = list->remove(ID);
  if(result == -1)
  {
    cout << "This student (" << ID << ") is not in the database.\n";
  }
  else
  {
    cout << "This student (" << ID << ") has been deleted.\n";
  }
  
  return result;
}

Student Database::get(int index)
{
  return list->get(index);
}

int Database::getIndex(int ID)
{
  return list->getIndex(ID);
}

void Database::print()
{
  return list->print();
}
You're allocating an array of Students:

Student *tmpList = new Student[capacity];

But your vector is a list of pointers to students:

Student *list[];

I think what you are trying to do is store a list of pointers to students. If this is indeed what you want, don't delete the students when you move them from the temp list to the list. The pointers refer to a single student. Until they are actually removed, the students shouldn't be deleted.

There are other issues, but perhaps this will get you started.
I did some debugging on that simplified coding at your first paste and managed to get it work. Here are modifications.

1, Declared a Vector* outside and explicitly assigned it to the "list" in DataBase.

2, changed the ordering of the numbers of Vector as.

int capacity;
int size;
Student *list[];

In debugging, "size" was assinged correctly but always disturbed after "Students" were constructed, I suspect since the "list" is a dynamic array, the memeory position of "capacity" and "siz" could become confusing for the compiler. I put the two at the front, then their values are kept unchanged.

3, In the default constructor for Student, I added the construor for "Person". This's not big issue.


4, "*list = new Student[capacity]" make me confusing. It may be understood as only list[0] is for "Student[capacity]". The code looks skilled, but not clear enough.

I changed them to a loop based on the "capacity" to assign students one by one as
"*(list+i) = new Student;"

After above changes, at least, the testDatabase->print() is ok ( I blocked other codes to add, remove or something)

And there are still several issues about the codes on managing the memory. One obvious one is there is no "delete" for the memory and memeory leaking is certain, but you can fix it later on. Another one is the "remove" function, at the first glance, it won't work.

My idea is: first let the "print" work, then let "add" work, then "remove", then.... do the things one by one.

Hopefully it's helpful for your checking.

B2ee
Last edited on
Topic archived. No new replies allowed.