为什么我的程序有时且一致地抛出了段错误?

时间:2016-07-01 22:30:21

标签: c++ segmentation-fault

我正在实现一个名为BigNum的类,旨在处理任意大数。我实现它的方式是使用无符号整数数组,使其实际上是一个base-(2 ^ 32)数字,其长度为int成员。

我得到了减法,乘法和所有6个比较运算符,但模数函数有时会引发分段错误。

我的函数的工作方式首先是检查其他是否至少是“this”(调用对象)的一半。如果是,它只是从中减去其他。如果不是,

我正在测试一个长三个整数的bigNum。最重要的是1,中间是0,最不重要的是415,所以它是1 * 2 ^ 64 + 0 * 2 ^ 32 + 415 * 2 ^ 0,这是18446744073709552031.我用循环来测试我的数字模数1到29之间的每个数字。如果第二个操作数是5,14,15,21,23或26,它总是抛出一个seg-fault。否则,它永远不会引发seg-fault。我还没有检查答案是否适合其他人。

我将cout语句放在一系列行上以缩小seg-fault行,这是“返回结果”行(标记如下)。我还将模数语句单独放在我的测试中(而不是使用cout)并且它仍然抛出了seg-fault,所以我知道这不是我输出导致seg-fault的数字。

我正在调用下面的第一个函数,它接受一个unsigned long,然后将long转换为BigNum,然后对两个BigNum执行模数:抛出seg-fault的操作。

以下是我的功能

BigNum *BigNum::operator% (unsigned long number) { //converts the long to a BigNum, then performs modulus on two BigNums
    //dynamically allocated because the BigNum destructor requires it
    unsigned int *parts = new unsigned int [2];
    parts [0] = (int) number;
    parts [1] = (int) (number >> 32);
    BigNum *asBig = new BigNum (parts, 2);
    BigNum *result = *this % *asBig;
    delete asBig;
    asBig = NULL;
    return result;
}

BigNum *BigNum::operator% (BigNum& other) { //two BigNums. Does the actual modular work
    BigNum *result;
    BigNum *replica;
    BigNum *test;
    this->simplify(); //cuts off any leading zero ints
    other.simplify();
    if (*(*this - other) < other) { //if other is less than half of this
        result = new BigNum(this->numbers, this->length);
        while (*result > other) {
            result = *result - other;
        }
        return result; //line throwing seg-fault
    }
    //if other is significantly smaller than this, the O(n) solution above is inefficient
    else {
        replica = new BigNum (other.numbers, other.length);
        while (true) { //makes "replica" equal "other" times the highest power of two possible without exceeding "this"
            test = *replica * 2;
            if (*test > *this) {
                break;
            }
            replica = test;
        }
        replica = (*this) % (*replica); //replica is smaller than this, but replica%other == this%other
        return (*replica % other);
    }
}

以下是我在那里调用的所有函数的原型。

BigNum::BigNum (unsigned int*, int);
BigNum *BigNum::operator* (unsigned long);
BigNum *BigNum::operator- (BigNum&);
bool BigNum::operator< (BigNum&);
bool BigNum::operator> (BigNum&);
void BigNum::simplify();

我尝试检查流氓指针,但没有看到任何指针,这些会更频繁地抛出seg-fault并且不那么一致。我在网上找到了堆栈损坏的想法,但这似乎只是一个流氓指针可以引起的。

我还尝试取消引用指针并在返回之前输入值,并且cout工作(尽管我仍然有一个seg-fault)。最后,我尝试返回其他BigNum指针,并且在相同的数字上仍然有一个seg-fault。我在看一个损坏的堆栈吗?如果是这样,我该如何解决?如果不是,那么什么会导致我的return语句出现seg-fault?

2 个答案:

答案 0 :(得分:0)

此评论:

//dynamically allocated because the BigNum destructor requires it

意味着BigNum构造函数只是将numbers成员设置为参数,而析构函数执行delete [] numbers。但这意味着你不应该有两个具有相同BigNum指针的numbers个对象,因为当其中一个被销毁时,另一个将有一个无效的numbers指针。

因此%运算符中的这些行是个问题:

    result = new BigNum(this->numbers, this->length);
    ...
    replica = new BigNum (other.numbers, other.length);

在使用numbers之前,您需要复制 unsigned int *newnumbers = new numbers[this->length]; memcpy((void*)newnumbers, (void*)this->numbers, sizeof(unsigned int) * this->length); result = new BigNum(newnumbers, this->length);

BigNum

在{{1}}构造函数中执行此操作可能会更好,而不是要求调用者提供动态分配的数组 - 通常最好负责在同一模块中分配和释放内存。

答案 1 :(得分:0)

回答我自己的问题:

@Barmar注意到我试图为两个不同的数字使用相同的动态分配数组,我应该更改它们。这是一个奇妙的想法,但它没有解决问题。

事实证明,无论出于何种原因,我的阻止就像

一样

if (*(*this - other) < other) {

如果问题类似于7%4,那么

正在工作,但如果它是1%5则不行(第一个操作数必须更大,而不是总是这样)。我解决它的方法是在检查第一个操作数是否已经较小之前添加一个块。