为什么我的程序总是出现分段错误?

Why is my program throwing seg-faults sometimes and consistently?

本文关键字:分段 错误 我的 程序 为什么      更新时间:2023-10-16

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

我已经得到减法,乘法和所有6个比较操作符工作,但模函数有时抛出分割错误。

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

我正在测试一个长为3 int的大整数。最高有效的是1,中间是0,最低有效的是415,所以是1*2^64+0*2^32+415*2^0,就是18446744073709552031。我使用了一个循环来测试我的数字模取1到29之间的每个数字。如果第二个操作数是5、14、15、21、23或26,它总是抛出一个段错误。否则,它永远不会抛出隔离错误。我还没有检查这些答案是否正确。

我将cout语句放在一系列行中以缩小分段错误线,它是"返回结果"行(如下所示)。我还在测试中单独使用了模数语句(而不是使用cout),它仍然抛出了segfault,所以我知道不是我输出的数字导致了segfault。

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

下面是我的函数

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();

我试着检查流氓指针,但没有看到任何,这些会更频繁地抛出segfault,不太一致。我在网上找到了堆栈损坏的想法,但这似乎只是由一个流氓指针引起的。

我还尝试在返回之前解引用指针和计数值,并且计数工作(尽管我仍然得到了一个段错误)。最后,我尝试返回其他BigNum指针,并且仍然在相同的数字上得到一个segfault。我看到的是一个损坏的堆栈吗?如果是这样,我该如何解决?如果不是,是什么导致我的返回语句出现分段错误?

注释:

//dynamically allocated because the BigNum destructor requires it

表示BigNum构造函数仅仅将numbers成员设置为实参,而析构函数将delete [] numbers成员设置为实参。但这意味着你不应该有两个具有相同numbers指针的BigNum对象,因为当其中一个被销毁时,另一个将具有无效的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构造函数中这样做可能会更好,而不是要求调用者提供一个动态分配的数组——通常最好是在同一个模块中负责分配和释放内存。

回答我自己的问题:

@Barmar注意到我试图为两个不同的数字使用相同的动态分配数组,我应该改变它们。这是个好主意,但并不能解决问题。

结果是,不管什么原因,我的block以

开头

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

如果问题是7%4,

可以工作,但如果是1%5就不行(第一个操作数必须更大,但并不总是这样)。我解决这个问题的方法是在前面添加一个块,检查第一个操作数是否已经更小了。