1

I have a class Student and the dynamically created array of students:

class Student{
public:
  void create(){
    system("cls");
    cout << "First name: ";
    cin >> fn;
    cout << "Last name: ";
    cin >> ln;
    cout << "How many subjects? ";
    cin >> sub_number;
    subjects = new string[sub_number];
    for(int i = 0; i < sub_number; i++){
      cout << "Subject name: ";
      cin >> subject[i];
    }
  }

  //This just display the student with a bunch of couts
  friend ostream& operator<<(ostream&, const Student&);

  ~Student(){ delete[] subjects; }
private:
  string fn;
  string ln;
  string* subjects;
  int sub_number;
};

I need to increase the size of this array by 1 and add a new student to it.

When I tried to do it by simply:

void main(){
   int stu_number = 0;
   cout << "How many students? "
   cin >> stu_number;
   Student* students = new Student[stu_number];

   //creating/updating initial students using user input
   for(int i = 0; i < stu_number; i++){
     students[i].create();
   }

   //displaying all students
   for(int i = 0; i < stu_number; i++){
     cout << students[i];
   }

   //trying to add a student
   add_new_student(students, stu_number);

   //displaying all students again
   for(int i = 0; i < stu_number; i++){
     cout << students[i];
   }
}

And the add_new_student function:

void add_new_student(Student* students, int& stu_number){
  Student* temp = new Student[stu_number++];
  for (int i = 0; i < stu_number - 1; i++){
    temp[i] = students[i];
  }
  temp[stu_number - 1].create(); 
  delete[] students;
  students = temp;
}

I am getting memory violation errors and Unhandled exceptions: Access violation writing location 0xABABABAB inside the add_new_student function.

  • What will be the correct way of doing this?
  • Is Student class missing some important components?

I can't use std::vector or a std::list as this is a school assignment:)

Kocur4d
  • 6,701
  • 8
  • 35
  • 53
  • 1
    You need to show more code with more context. For example *where* do you "increase" the size? In a function? Do you pass the pointer by value or by reference? And ***where*** do the crash happen? Run in a debugger to locate it. And can you create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) and show us? – Some programmer dude Mar 25 '15 at 13:30
  • Stop this madness and use `std::vector`. It is a zero-overhead, implementation of resizable, dynamically allocated arrays. Why would you not use `std::vector` if you are doing C++. – Félix Cantournet Mar 25 '15 at 13:37
  • 1
    Oh, and what does `Student` look like? Do you perhaps need a copy-assignment operator? You might want to read about [the rule of three](http://en.wikipedia.org/wiki/Rule_of_three_) (alternatively about [the rule of zero](http://flamingdangerzone.com/cxx11/2012/08/15/rule-of-zero.html)). – Some programmer dude Mar 25 '15 at 13:37
  • @FélixCantournet They mentioned this is for a class assignment and they cannot use `std::vector` or `std::list`. That is not uncommon in coursework for learning purposes. – Cory Kramer Mar 25 '15 at 13:37
  • 1
    The only "dynamic" here is *dynamically allocated*. Once allocated, there is nothing more "dynamic" about it: it won't change size! C++ container classes are *dynamic* in the sense that they change size dynamically as needed. – crashmstr Mar 25 '15 at 13:38
  • 1
    What exactly is `Student`? What does `create()` really do? – PaulMcKenzie Mar 25 '15 at 13:39
  • hopefully you can use `std::unique_ptr` at least! – Mgetz Mar 25 '15 at 13:39
  • 1
    @Cyber I know. it is not uncommon for bad teachers to try to miss the point of encapsulation and instead of teaching people how to **USE** `std::vector` and then **AFTER** teaching them how to implement it, they mix the two and produces thousands upon thousands of terrible "C-style" C++ programmers. But I guess resistance is futile... – Félix Cantournet Mar 25 '15 at 13:39
  • @Cyber - `That is not uncommon in coursework for learning purposes` Yeah, learning how to be frustrated. Then switch to Java. Seriously, I have yet to see a student code this correctly *and* be told how to write it correctly, unless they come here or go to a similar site. – PaulMcKenzie Mar 25 '15 at 13:40
  • I'm not saying it's a good way to go about it, I remember having to do that kind of stuff when I was in school. If I could go back, I'm sure I'd have some recommendations for the professors now that I've been around the block. – Cory Kramer Mar 25 '15 at 13:43
  • Stop advising him to use std:: containers/utilities. Learning C++ often begins in understanding how things work internally. He was told to implement this without `vector`, so "use `std::vector`" is not an answer. "Switch to Java" isn't either. @Kocur4D Post code of `Student` class, please. Except for memory leak, there is no error in this code. Probably something bad is happening when you copy elements from old array to the new one. – Mateusz Grzejek Mar 25 '15 at 13:51
  • @MateuszGrzejek `"Use Java" isn't either.` That wasn't what was recommended. That is what students do when they get C++ frustration given assignments like this that really want to write real programs. Second, this is the comment section -- answers would go in the answer section. – PaulMcKenzie Mar 25 '15 at 13:54
  • 2
    `I don't think that it is impotent to know how create() works ` If I had a dollar for every time supposedly non-important code *is* important in answering the question, I would be a rich man. – PaulMcKenzie Mar 25 '15 at 14:01
  • 1
    @ALL : If use std::vector isn't the answer then the answer is implement a nicely contained abstraction for resizable array (i.e; std::vector, but simpler). NOT "do this crappy management of memory in the middle of your business logic". – Félix Cantournet Mar 25 '15 at 14:02
  • @PaulMcKenzie Amen to that. – Mateusz Grzejek Mar 25 '15 at 14:07
  • ABABABAB is a memory overflow - accessing memory outside the allocated range. To help more we need to know exactly what line of code gives that error - the debugger should tell you that. – Andy Newman Mar 25 '15 at 14:08
  • 1
    `and it is still not correct way to increase the size of this array` Your code is on a high-level, correct in the way to resize the array. The issue is that there is much more going on than just resizing the array. You are assigning one Student object to another within the loop, and we have no idea if `Student` has correct copy semantics. You also call `create()`, and we don't know if that function causes memory corruption in some way. – PaulMcKenzie Mar 25 '15 at 14:15
  • What does the [default constructor](http://stackoverflow.com/a/29258043/2932052) do? You have one right? – Wolf Mar 25 '15 at 14:17
  • I'm going to be psychic and guess that `Student` itself uses `char *` member variables instead of `std::string`, and improper usage of these members is causing the fault. – PaulMcKenzie Mar 25 '15 at 14:40
  • Updated the answer with more code. After reading comments I think I know where the problem is now but I will not do any more assumptions today. Thank you for all the suggestions. I have learned my lesson! – Kocur4d Mar 25 '15 at 18:53
  • @Kocur4d you write *`I am getting memory violation errors and Unhandled exceptions: Access violation writing location 0xABABABAB inside the add_new_student function.`* - but this is important: **where** do you get the exception? can you point at the statement in the code? – Wolf Mar 25 '15 at 18:55
  • @wolf I know:( but I don't have this information atm(I will get crucified for this) basically I was helping some with this code and I don't have a stack installed on my computer to recreate it:/ – Kocur4d Mar 25 '15 at 18:59
  • @Kocur4d - Well, my psychic powers were almost spot on: `string* subjects;` Do you see that your homework problem has become a catch-22 issue here? You are trying to implement a dynamic array, but your `Student` class itself needs to have a dynamic array of string implemented. The comment that you should be developing a vector class, and not do this one-off attempt of allocating and deallocating memory in business logic has turned out to be prophetic. If you make copies of your `Student` object, you will be erroneously destroying your data due to the destructor being called. – PaulMcKenzie Mar 25 '15 at 19:39
  • @PaulMcKenzie agree 100%, I am a Ruby person. In my world thing are happening(and de-happening) magically. Puff! My sister is taking C++ Uni classes and I didn't get used to(forget) about the evil land of C++ where the pointers and memory allocation will chase you down:) She was told that she can't use the std::vector. Maybe it was a good call, it will teach you to use it all the time! – Kocur4d Mar 25 '15 at 20:08

4 Answers4

5

To increase the size of the array, you basically have to:

  • Create a new array with a larger size
  • Copy over the values from the old smaller array to the new larger one
  • Delete the old smaller array

That being said, if you are able to I would recommend switching to std::vector since it has utility methods that will resize for you.

Kocur4d
  • 6,701
  • 8
  • 35
  • 53
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
2

The problem is that your Student class does not follow the "rule of 3":

What is The Rule of Three?

If your class has a user-defined destructor, then it should also provide a user-defined copy constructor and assignment operator. What is happening now is that when this line is performed:

temp[i] = student[i];

you are invoking the assignment operator. However, your Student object, when assigned, will just copy the pointer value from one object to the other. What happens when the destructor for either of these Student objects is called? The destructor will delete the same pointer value twice, thus an error.

Here is a slimmed down version of your current Student class.

#include <string>

class Student
{
      std::string* subjects;
      std::string fn;
      std::string ln;
      int sub_number;

   public:
      Student(size_t numSubjects=5) : subjects(new std::string[numSubjects]), 
                                      sub_number(numSubjects){} 

      ~Student() { delete [] subjects; }
};

// Test code
int main()
{
    Student s1(10);
    Student s2 = s1;
    Student s3;
    s3 = s1;
}

If you run this program, you will see that there are problems with memory leaks and double deletion errors, as shown here: http://ideone.com/MQhpcK

All I'm doing is copying Student objects, and the issue appears.

To fix the problem, you must add and implement these functions in your Student class:

      Student(const Student& rhs);  // copy constructor
      Student& operator=(const Student& rhs); // assignment operator

Once you implement these functions, test the program above to ensure it truly does make the copies correctly, without memory leaks and segmentation faults/access violation errors. When done, your original issue of the copying causing the access violation should be resolved.

Community
  • 1
  • 1
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
1

Your problem is caused by the missing assignment operator. In the assignment within the for loop, there is a flat copy of the subjects array which is deleted when the original students array is deleted. After that, there is a so-called dangling pointer in first Student object.

The assignment operator has the job to safely (and semantically correct) copy all elements from one object to another.

Additionally: It would be really interesting (informative) to add some trace output as to get a detailed understanding what's going on here.

Wolf
  • 9,679
  • 7
  • 62
  • 108
  • can you elaborate a bit more on assignment operator? maybe you can draft a possible method. I will correct it if it will be wrong as soon as I will get access to the code? – Kocur4d Mar 25 '15 at 19:08
  • I will add more info about errors as soon as I will get a chance to try assignment operator. – Kocur4d Mar 25 '15 at 19:20
0

Whatever create is called for[1], there must be something wrong with the default constructor[2] of your Student class: it seems to miss initializing important elements that are used within create.


  • [1] BTW: what is the purpose of create?
  • [2] Is there a default constructor? What C++ standard is used?
Wolf
  • 9,679
  • 7
  • 62
  • 108