【问题标题】:malloc(): memory corruption (fast) c++malloc():内存损坏(快速)c++
【发布时间】:2014-03-19 16:25:16
【问题描述】:

我是 C++ 新手,我正在尝试使用 C++ 计算 Point(x,y,z) 集的凸包。

我在main方法中调用了如下方法:

vector<Point> convexHull(Point Points[], int n) {
    vector<Point> v;
    // Find the bottommost Point
    int ymin = Points[0].getY();
    int min = 0;
    for (int i = 1; i < n; i++) {
        int y = Points[i].getY();

        // Pick the bottom-most or chose the left most Point in case of tie
        if ((y < ymin) || (ymin == y && Points[i].getX() < Points[min].getX()))
            ymin = Points[i].getY(), min = i;
    }
    // Place the bottom-most Point at first position
    Points[min] = Points[0].swap(Points[min]);

    // Sort n-1 Points with respect to the first Point. A Point p1 comes
    // before p2 in sorted ouput if p2 has larger polar angle (in 
    // counterclockwise direction) than p1
    p0 = Points[0];
    qsort(&Points[1], n - 1, sizeof (Point), compare);

    // Create an empty stack and push first three Points to it.
    stack<Point> S; //  on debug the project I find that the problem is here 
    S.push(Points[0]);
    S.push(Points[1]);
    S.push(Points[2]);

    // Process remaining n-3 Points
    for (int i = 3; i < n; i++) {
        // Keep removing top while the angle formed by Points next-to-top, 
        // top, and Points[i] makes a non-left turn
        while (orientation(nextToTop(S), S.top(), Points[i]) != 2)
            S.pop();

        S.push(Points[i]);
    }

    // Now stack has the output Points, print contents of stack
    while (!S.empty()) {
        Point p = S.top();
        cout << "(" << p.getX() << ", " << p.getY() << ", " << p.getZ() << ")" << endl;
        v.push_back(Point(p.getX(), p.getY(), 0));
        S.pop();
    }
    return v;
}

它给出了这个错误:

*** glibc detected *** /home/user/NetBeansProjects/DGILOG-ask/dist/Debug/GNU-Linux-x86/dgilog-task: malloc(): memory corruption (fast): 0x08de1238 ***

我在网上搜索过同样的错误,但我不知道该怎么办。

Point.cpp

#include <iostream>
#include <math.h>
#include <ostream>

using namespace std;

#include "Point.h"

Point::Point() : x(0), y(0), z(0) {
}

Point::Point(ostream &strm) {
    strm << "Type the abscissa: ", cin >> this->x;
    strm << "Type the ordinate: ", cin >> this->y;
    strm << "Type the applicate: ", cin >> this->z;
}

Point::Point(float x, float y, float z) : x(x), y(y), z(z) {
}

/**
 * Destructor
 */
Point::~Point() {
}

//Other methods

float Point::dist2D(Point &other) {
    float xd = x - other.x;
    float yd = y - other.y;
    return sqrt(xd * xd + yd * yd);
}

float Point::dist3D(Point &other) {
    float xd = x - other.x;
    float yd = y - other.y;
    float zd = z - other.z;
    return sqrt(xd * xd + yd * yd + zd * zd);
}

Point Point::swap(Point p) {
    Point aux(x, y, z);
    x = p.x;
    y = p.y;
    z = p.z;
    return aux;
}

void Point::print(ostream &strm) {
    strm << "Point(" << this->x << "," << this->y << "," << this->z << ")" << endl;
}

bool Point::operator<(const Point &p) const {
    return x < p.x || (x == p.x && y < p.y);
}

谢谢。

【问题讨论】:

  • 您确定您的Points[] 至少有3 个元素吗?您是否使用调试器逐步完成了此操作?
  • 你应该做的是用-g编译你的代码,然后通过valgrind运行它
  • 1) 使用 qsort 退出。学习使用 std::sort。 2)你为什么使用vector(好),同时使用Point数组(有问题)?
  • 在valgrind下运行程序(如果可以的话)
  • @clcto 是有超过 3 个元素。我试图用for循环显示他的内容。效果很好。

标签: c++ memory malloc


【解决方案1】:

由于您没有发布完整的程序,因此您应该注意以下几点:

convexHull(Point Points[], int n)

您在该函数中没有任何地方检查 n 是否在 Points 数组的范围内。您应该在整个函数中使用向量。例如:

 int ymin = Points[0].getY();
 int min = 0;
 for (int i = 1; i < n; i++) {
    int y = Points[i].getY();

如果我将一个 NULL 指针作为第一个参数(甚至是一个无效指针)传递,或者如果 n 太大,则存在访问冲突。使用向量可以大大减少或彻底消除这些问题。使用向量,您可以使用 size() 成员函数进行完整性测试,以确保 Point 具有相关数量的条目。目前,无法在您的函数中进行此类测试。

下一期:

S.push(Points[0]);
S.push(Points[1]);
S.push(Points[2]);

你怎么知道至少有 3 个条目?您不知道,并且该功能无法检查。您所拥有的只是一个正在传递的指针,以及一些任意数字 n。如果您使用的是 C++,则不应养成刻意以类似“C”的风格进行编码的习惯。你有向量,所以要充分利用它。

下一期:

qsort(&Points[1], n - 1, sizeof (Point), compare);

由于您没有发布 Point 是什么,因此如果 Points 是非 POD 类型,则 qsort() 的这种用法会导致未定义的行为。

停止使用 qsort()。在 C++ 程序中使用 qsort() 表明编码器是 1) 使用他们习惯的 C 程序员(通常会出现令人惊讶的意外结果)或 2) 新手 C++ 程序员阅读 C 书籍或程序作为编写正确 C++ 程序的指导。

使用 std::sort() -- 您正在编写 C++ 应用程序,而不是 C 应用程序。 std::sort 是类型安全的,更易于使用和设置,适用于遵循严格-弱排序的 POD 和非 POD 类型。

【讨论】:

  • 加上std::sort 更快。经常大约两次。因为编译器可以内联它。
  • 如果您还包括对迭代器的切换,那就太好了。 C++ 有很多东西都有迭代器,但是没有索引,也没有办法将它们转换为指针,所以这是一个好习惯。
【解决方案2】:

从错误的外观和你说它崩溃的地方(声明)来看,它很可能在 qsort 函数中。它是代码中唯一的 C 库调用,并且错误不能出现在堆栈的声明中,因为它只是一个声明。

你应该做的第一件事是检查边界

vector<Point> convexHull(Point Points[], int n) {
  vector<Point> v;
  if(n <= 3){ 
     // error
  }else{
    //the chunk of code
  } 
  return v;
}

但是等等……还有更多,假设你想用一个向量替换 Points 数组

std::vector<Point> convexHull(vector<Point>::iterator begin, vector<Point>::iterator end) {
  std::vector<Point> returnVal;
  if(n <= 3){ 

  }else{
    //the chunk of code
  } 
  return returnVal;
}
// just don't forget to check your returnVal for empty size, error handling is a must

或者您可以只使用带有矢量的 c 风格的老式方法...我不建议这样做,因为您停止学习迭代器,您应该这样做。

vector<Point> Points(100);
vector<Point> v;
if(convexHull(&Points[0], Points.size())) ///< how would you be testing this
{
   //yay
}

哦,对了,实现std::sort真的很简单,别怕,是这样的

std::sort (&Points[1], &Points[1]+ (n-1));

如果 Points where iterators 会更容易

std::sort (begin+1, end);

您甚至可以更进一步并使用 std::advance,您应该这样做

vector<Point>::iterator it = begin;   
std::advance(it,1);
std::sort (it, end);

因此,总而言之,第一部分如何使用迭代器?

std::vector<Point> convexHull(vector<Point>::iterator begin, vector<Point>::iterator end)
{
  vector<Point> v;
  // Find the bottommost Point
  int ymin = begin->getY();
  vector<Point>::iterator l_it = begin; 
  vector<Point>::iterator min_position = begin;
  std::advance(l_it, 1);
  for (; l_it != end; ++l_it) 
  {
      int y = l_it->getY();

      // Pick the bottom-most or chose the left most Point in case of tie
      if ((y < ymin) || (ymin == y && l_it->getX() < min_position->getX()))
      {
          ymin = l_it->getY();
          min_position = l_it;
      }
   /// MORE CODE
}

【讨论】:

  • 如果不是输出参数,我会赞成(糟糕;总是更喜欢返回值而不是输出参数;使用 C++11 移动语义返回向量是微不足道的操作),错误使用的 int返回(如果你想用if检查它应该是一个bool;并且值也都是true)以及使用异常失败。
  • 使用异常失败?你的意思是我应该使用异常?我们使用断言来实现该功能。我不认为这是对或错,这只是事情的完成方式。应该从一开始就选择其中一个并坚持下去。
  • 好吧,如果函数返回计算值,那么返回错误的唯一方法也是最方便的方法是异常。当然调用convexHull...convexHull 无论如何定义都小于3 点,所以它不应该返回错误(除了std::vector::push_back 可能抛出的std::bad_alloc)。
  • 看起来很合理,即使它不应该失败,也许用户可能想要那层安全。
  • 安全层经常会在路上的某个地方咬住你。在大多数情况下,首选方法是失败 fastloud,这在大多数情况下意味着 assertthrow。但我同意,什么是适当的错误处理取决于我们这里没有的很多上下文。
猜你喜欢
  • 1970-01-01
  • 2013-02-15
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
相关资源
最近更新 更多