【问题标题】:*** glibc detected *** ./a.out: double free or corruption (out): 0xbfe69600 ****** 检测到 glibc *** ./a.out:双重释放或损坏(输出):0xbfe69600 ***
【发布时间】:2014-04-29 16:16:37
【问题描述】:

我正在做一个程序来表示“学生”表。它具有“ID”、“First Name”和“Last Name”属性。我做了一个二维数组并将 cout 语句全部放在检查...正确的信息存储在正确的单元格中,但我收到一个我不认识的错误。 .cpp 文件的代码是:

#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]<< ")";

        }


    }
}

我的 Table1.h 是:

#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

错误如下:

    *** 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)

【问题讨论】:

  • 请包含 Table1.h(并清理您的格式)——目前我们无法看到您在哪里初始化 Student 数组(如果未初始化,您会得到一个像你得到的错误)
  • 请提供类声明
  • 你如何定义Students
  • 为了便于指导,需要完整的声明、定义和构造函数细节。 Table1 构造函数没有足够的信息来确定应该如何使用二维Students“数组”。例如,Students 是整数到字符串键值对的 STL 映射容器吗?
  • 我在底部添加了 Table.h 部分。

标签: c++ debugging free glibc backtrace


【解决方案1】:

我收到一个我不认识的错误

这个错误仅仅意味着你已经损坏了堆。

破坏堆的最常见方法是:

  • 分配结束后写入
  • 释放未分配的内存
  • 释放某物两次。

发现错误的最快方法是在Valgrind 下运行二进制文件。

【讨论】:

    【解决方案2】:

    首先要像这样修改 Table1 的构造函数:

    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
       }
    }
    

    下面有三个独特的编辑。请查看所有这些以更好地了解情况以及解决问题的可能方法。

    开始编辑一个

    Table1::InsertStudent(string ID, string FN, string LN) 不能确保 RowPos 在0 &lt;= RowPos &lt; 16 的范围内。如果添加了第 17 个学生,则代码将访问不存在的数组单元格。因此会发生访问冲突/程序崩溃/意外行为。

    结束编辑


    开始编辑二
    163 的硬编码值可以替换为靠近标题最顶部的用户定义的宏,以进行简单的修改以修改最大学生数和/或学生详细信息。例如:

    #define MAX_STUDENTS 25
    #define MAX_COLUMNS 8
    

    然后在标头和 cpp 中,宏用于当前使用 163 的所有地方。循环的构造函数如下所示:

    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
    }
    


    结束编辑二


    开始编辑三
    在创建一个仅声明 Table1 本地实例的唯一 main.cpp 后,在 for 循环体中调用 Table1::InsertStudent,然后调用 Table1::Print,以下建议应该有助于改进并有望解决问题.所以,观察打印输出一起运行后,对Table1构造函数、InsertStudent和Print成员函数的修改如下:

    Table1 头文件:

    #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 源码(类实现)。流操纵器setw 用于配置输出屏幕以显示列。强烈建议在此处查看更多详细信息:std::setw。另请参阅 Stroustrup 书的副本。请注意,#include &lt;iomanip&gt; 对于定义输出宽度是绝对必要的。 Print 方法主体中的逗号和括号消失了。任何演示风格都是可能的,Print 方法修改是一个示例,指示了一种方法。许多其他方法是可能的。请注意,此修改集不再具有分配给第零位的任何固定值字符串。所有学生数据都从索引 0 开始,一直有效到并包括 MAX_STUDENTS - 1 索引位置。

    #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
          }
       }
    }
    

    最后一个版本应该可以解决发布的问题。希望这些建议能促进对iomanip 助手的进一步研究,以便只有数据存储在学生数组中。用于确认打印操作的字符串值(例如"students")也可以成为用户定义的宏。

    结束编辑三

    【讨论】:

    • 需要对上述内容进行额外修改。 OP 应阐明一些关键设计元素,以使学生数组的第零索引存储固定字符串值。我正在使用我自己的 main.cpp 版本测试实现,看看会发生什么。我的帖子随后将被修改,提出更多改进建议。
    猜你喜欢
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多