*** glibc detected *** ./a.out: double free or corruption (out): 0xbfe69600 ***

31,509

Solution 1

I get an error I don't recognize

The error simply means that you've corrupted heap.

The most common ways to corrupt heap are:

  • writing past the end of allocation
  • freeing memory that you didn't allocate
  • freeing something twice.

The fastest way to discover your bug is to run your binary under Valgrind.

Solution 2

The very first thing is to modify the Table1 constructor like so:

Table1::Table1()
{

   //
   // C++ arrays are zero based, previous code skips the 0th row.
   // The RowPos and starting value for i are now zero.
   //
   RowPos = 0; 
   ColPos = 0;

   for(int i=0; i<16; i++)
   {
      for(int j=0; j<3 ; j++)

      Students[i][j] = "FakeNull"; // fill the array with Null value
   }
}

There are three unique edits below. Please review all of them to better understand the situation and possible ways to solve it.

Start Edit One

The Table1::InsertStudent(string ID, string FN, string LN) does not make sure that RowPos is in the range of 0 <= RowPos < 16. If the 17th student is added, then the code will access array cells that do not exist. Hence an access violation / program crash / unexpected behavior will occur.

End Edit One


Start Edit Two
The hard coded values of 16 and 3 can be replaced with user defined macros near the very top of the header, to have a simple modification for modifying the maximum number of students and/or student details. For example:

#define MAX_STUDENTS 25
#define MAX_COLUMNS 8

Then later in the header and the cpp, the macros are used in all places currently using 16 and 3. The constructor for loop would then look like:

for(int i=0; i<MAX_STUDENTS; i++)
{
   for(int j=0; j<MAX_COLUMNS ; j++)

   Students[i][j] = "FakeNull"; // fill the array with Null value
}


End Edit Two


Start Edit Three
After creating a unique main.cpp that only declares a local instance of Table1, calls Table1::InsertStudent in a for loop body, and then calls Table1::Print, the following suggestions should help to improve and hopefully resolve the issues. So, after observing the printed output running together, modifications to the Table1 constructor, InsertStudent and Print member functions are the following:

Table1 header file:

#ifndef GRADE_HEADER
#define GRADE_HEADER

//
// The first two lines are not necessary and should be deleted
// Note that "std::" must be used in front of the string class
// 
// #include <iostream>
// using namespace std;
#include <string>

//
// Added three user defined macros to make modifications easy and to 
// to have a single location for the signaling string value to stop 
// printing student details to the cout stream.
//
#define MAX_STUDENTS 16
#define MAX_COLUMNS 3
#define EMPTY_CELL "FakeNull"

class Table1
{ // added

private:
      std::string Students[MAX_STUDENTS][MAX_COLUMNS];
      std::string Grades[MAX_STUDENTS][MAX_COLUMNS];
      int RowPos;
      int ColPos;

public:
      Table1();
      std::string InsertStudent(std::string ID, std::string FN, std::string LN);
      void Print(std::string Name);

      std::string InsertGrade(std::string, std::string, std::string, std::string);
      void Select(std::string, std::string, int);
      void Select(std::string, std::string, std::string);
      void Select(std::string, std::string, char);
      void Join();
      std::string Converter(int);

};

#endif


Table1 cpp source (class implementation). The stream manipulator setw is used to configure the output screen to display the columns. It is highly recommended to review more details here: std::setw. Also consult a copy of the Stroustrup book. Note that the #include <iomanip> is absolutely necessary to define an output width. The commas and parenthesis in the body of the Print method are gone. Any presentation style is possible, the Print method modifications are a sample, indicating one way to do it. Many others ways are possible. Note that this modification set no longer has any fixed value strings assigned to the zeroth position. All student data commences at index zero and is valid up to and including the MAX_STUDENTS - 1 index position.

#include "Table1.h"
#include <sstream>
#include <iostream>
#include <iomanip>

using namespace std;

Table1::Table1()
{
   //
   // C++ arrays are zero based, previous code skips the 0th row.
   // The RowPos and starting value for i are now zero.
   //
   RowPos = 0; 
   ColPos = 0;

   //
   // Initialize the MAX_STUDENTS elements to a set string, indicating 
   // no data present.  The use of the zeroth element as string constants
   // is no longer necessary.
   //
   for(int i=0; i < MAX_STUDENTS; i++)
   {
      for(int j=0; j < MAX_COLUMNS; j++)

      Students[i][j] = EMPTY_CELL; // fill the array with Null value
   }

}


//
// Note that sOut is an additional local variable to provide a string output
// for success or failure.  The range checking is new too.
//
string Table1::InsertStudent(string ID, string FN, string LN)
{
   string sOut = "Successfully added student";

   //
   // Must be sure the RowPos index is never beyond the last element of the 
   // Students array!!!  
   //
   if (RowPos < 0 || RowPos >= MAX_STUDENTS) 
   {
      sOut = "Students array full.  Cannot add any more students";
      return sOut;
   }
   Students[RowPos][ColPos] = ID; //Assign ID to first column
   ColPos++; //Move to next column
   Students[RowPos][ColPos] = FN;
   ColPos++;
   Students[RowPos][ColPos] = LN;

   //  
   // Incrementing this accomplishes nothing since it is set to zero next
   //
   // ColPos++;

   ColPos = 0;
   RowPos++;
   return sOut;
}

void Table1::Print(string Name)
{

   if(Name == "students")
   {
      cout << "StudentID" << setw(15) << "FirstName" << setw(17);
      cout << "LastName" << endl;


      //
      // It is much more efficient to declare variables outside a loop and 
      // not within a loop body.  To promote best practices, both variables
      // are declared together.  The reality is that j is the one which 
      // should be declared outside the for loop body (or at the same time
      // as this: for (int i = 0, j; ...
      // Keep in mind that j always has to be set to zero to start the loop body
      // 
      int i, j;
      for(i=0; i < MAX_STUDENTS; i++)
      {
         j=0;
         if(Students[i][j] == EMPTY_CELL)
               break;
         else
         { // added
            cout << setw(9) << Students[i][j] << setw(15);
            j++;
            cout << Students[i][j] << setw(18);
            j++;
            cout << Students[i][j] << endl;
         } // added
      }
   }
}

This last version should resolve the posted issues. Hopefully the suggestions will foster additional research into the iomanip helpers so that only data is stored in the Students array. The string value used to confirm the print action (e.g. "students") could also become a user defined macro.

End Edit Three

Share:
31,509
user3448739
Author by

user3448739

Updated on September 18, 2020

Comments

  • user3448739
    user3448739 almost 4 years

    I'm doing a program to represent a table of "Students". It has the attributes 'ID', 'First Name' and 'Last Name'. I did a two-dimensional array and put cout statements all throughout to check... The correct info IS stored in the correct cell, but I get an error I don't recognize. the code for the .cpp file is:

    #include "Table1.h"
    #include <sstream>
    #include <iostream>
    using namespace std;
    
    Table1::Table1(){
    
    RowPos = 1;
    ColPos = 0;
    
    for(int i=1; i<16; i++)
    {
        for(int j=0; j<3 ; j++)
    
            Students[i][j] = "FakeNull"; // fill the array with Null value
        }
    }
    
    string Table1::InsertStudent(string ID, string FN, string LN){
    
        Students[0][0] = "StudentID";
        Students[0][1] = "FirstName";
        Students[0][2] = "LastName";
    
    
        Students[RowPos][ColPos] = ID; //Assign ID to first column
        ColPos++; //Move to next column
        Students[RowPos][ColPos] = FN;
        ColPos++;
        Students[RowPos][ColPos] = LN;
        ColPos++;
    
        ColPos = 0;
        RowPos++;
    }
    
    void Table1::Print(string Name){
    
        if(Name == "students"){
    
            for(int i=1; i<16; i++)
            {
                int j=0;
                if(Students[i][j] == "FakeNull")
                        break;
                else
                    cout<< "("<< Students[i][j]<< ",";
                    j++;
                    cout<< Students[i][j]<< ",";
                    j++;
                    cout<< Students[i][j]<< ")";
    
            }
    
    
        }
    }
    

    My Table1.h is:

    #include <iostream>
    using namespace std;
    #include <string>
    
    
    #ifndef GRADE_HEADER
    #define GRADE_HEADER
    class Table1
    
    private:
    
        string Students[16][3];
    
        string Grades[16][3];
        int RowPos;
        int ColPos;
    
    public:
        Table1();
        string InsertStudent(string, string, string);
        string InsertGrade(string, string, string, string);
        void Print(string);
        void Select(string, string, int);
        void Select(string, string, string);
        void Select(string, string, char);
        void Join();
        string Converter(int);
    
    
    };
    #endif
    

    The ERROR is the following:

        *** glibc detected *** ./a.out: double free or corruption (out): 0xbfbdeae0 ***
        ======= Backtrace: =========
        /lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xeadee2]
        /usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0x9a951f]
        /usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)          [0x99099b]
        /usr/lib/i386-linux-gnu/libstdc++.so.6(+0x909dc)[0x9909dc]
        /usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x2e)[0x990a4e]
        ./a.out[0x8049299]
        /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xe514d3]
        ./a.out[0x8048a71]
        ======= Memory map: ========
        003a0000-003ca000 r-xp 00000000 08:01 150255     /lib/i386-linux-gnu/libm-2.15.so
        003ca000-003cb000 r--p 00029000 08:01 150255     /lib/i386-linux-gnu/libm-2.15.so
        003cb000-003cc000 rw-p 0002a000 08:01 150255     /lib/i386-linux-gnu/libm-2.15.so
        005a5000-005a6000 r-xp 00000000 00:00 0          [vdso]
        007c5000-007e5000 r-xp 00000000 08:01 150250     /lib/i386-linux-gnu/ld-2.15.so
        007e5000-007e6000 r--p 0001f000 08:01 150250     /lib/i386-linux-gnu/ld-2.15.so
        007e6000-007e7000 rw-p 00020000 08:01 150250     /lib/i386-linux-gnu/ld-2.15.so
        00900000-009d8000 r-xp 00000000 08:01 393409     /usr/lib/i386-linux gnu/libstdc++.so.6.0.16
        009d8000-009d9000 ---p 000d8000 08:01 393409     /usr/lib/i386-linux gnu/libstdc++.so.6.0.16
        009d9000-009dd000 r--p 000d8000 08:01 393409     /usr/lib/i386-linux gnu/libstdc++.so.6.0.16
        009de000-009e5000 rw-p 00000000 00:00 0
        00c13000-00c2f000 r-xp 00000000 08:01 132412     /lib/i386-linux-gnu/libgcc_s.so.1
        00c2f000-00c30000 r--p 0001b000 08:01 132412     /lib/i386-linux-gnu/libgcc_s.so.1
        00c30000-00c31000 rw-p 0001c000 08:01 132412     /lib/i386-linux-gnu/libgcc_s.so.1
        00e38000-00fdc000 r-xp 00000000 08:01 150260     /lib/i386-linux-gnu/libc-2.15.so
        00fdc000-00fde000 r--p 001a4000 08:01 150260     /lib/i386-linux-gnu/libc-2.15.so
        00fde000-00fdf000 rw-p 001a6000 08:01 150260     /lib/i386-linux-gnu/libc-2.15.so
        00fdf000-00fe2000 rw-p 00000000 00:00 0
        08048000-0804a000 r-xp 00000000 00:19 52698567   
        0804a000-0804b000 r--p 00001000 00:19 52698567   
        0804b000-0804c000 rw-p 00002000 00:19 52698567   
        09df7000-09e18000 rw-p 00000000 00:00 0          [heap]
        b77c9000-b77cc000 rw-p 00000000 00:00 0
        b77de000-b77e3000 rw-p 00000000 00:00 0
        bfbbe000-bfbdf000 rw-p 00000000 00:00 0          [stack]
        Aborted (core dumped)
    
  • CPlusPlus OOA and D
    CPlusPlus OOA and D over 10 years
    Additional modifications are necessary to the above. The OP should clarify some key design elements for having the zeroth index of the Students array store fixed string values. I am testing the implementation as is with my own version of main.cpp to see what happens. My post will subsequently be modified, suggesting more improvements.