2016-07-01 5 views
-2

私はBigNumという名前のクラスを実装しています。私が実装した方法は、符号なし整数の配列を使用して、長さのintメンバーを使用して、それを事実上ベース(2^32)数にしています。なぜ私のプログラムは時々seg-faultsを投げつけていますか?

私は減算、乗算、および6つの比較演算子のすべてを動作させましたが、モジュラス関数は時々セグメンテーションフォールトを投げます。

私の関数が動作する方法は、まず、 "this"(呼び出し元のオブジェクト)の少なくとも半分であるかどうかを調べることです。そうであれば、それは単にこれから他を差し引くだけです。そうでない場合は、

私は3つのintsのbigNumでテストしています。最も重要なものは1、中央のものは0、最下位のものは415なので、1 * 2^64 + 0 * 2^32 + 415 * 2^0です。これは18446744073709552031です。第2オペランドが5,14,15,21,23、または26の場合、常にseg-faultがスローされます。それ以外の場合は、決してseg-faultをスローしません。私は答えが他の人に正しければまだチェックしていない。

私は、seg-fault行を絞り込むために一連の行にcout文を入れました。これは "return result"(以下に記された行)でした。私はモジュラスステートメントだけを私のテストに入れました。(それはcoutを使うのとは対照的ですが)それでもseg-faultを投げたので、seg-faultの原因となった番号を出力していないことが分かりました。

私はunsigned longを取って、次にlongをBigNumに変換し、次に2つの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-障害をスローしていました。私は、オンラインでスタック破損のアイデアを見つけましたが、それは不正なポインタが原因であるようです。

私はまた、ポインタの逆参照を試みて戻り値の直前に値を取り戻しました。そして、coutは機能しました(私はまだsegフォルトがあります)。最後に、他のBigNumポインタを返そうとしましたが、同じ数字にseg-faultがあります。私は破損したスタックを見ていますか?もしそうなら、どうすれば修正できますか?そうでなければ、私のreturn文がseg-faultになる原因は何ですか?

+0

デバッガ、デバッガを使用しましたか?もしそうなら、障害の前に実行された最後のステートメントは何ですか? –

+2

すべてのテキストの代わりに[mcve]を投稿すると便利です。 See [ask]。 –

+1

これは私にとって心配です: 'result = new BigNum(this-> numbers、this-> length);'動的に割り当てられた同じ配列を参照する2つの 'BigNum'オブジェクトがあります。 'BigNum'デストラクタがコメントに暗示されているように配列を削除した場合、一方が破壊されたときにそのポインタの1つが無効なポインタを持ちます。 – Barmar

答えて

0

@Barmarは、私は2つの異なる番号に同じ動的に割り当てられた配列を使用しようとしている、と私はそれらを変更する必要があることをされたことに気づきました。それは素晴らしいアイデアでしたが、問題を解決しませんでした。

それは問題が最初に(それが1%5だった場合、7%4のようなものだったが、ない場合は、何らかの理由でif (*(*this - other) < other) {

よう

を始めた私のブロックが働いていたことが判明オペランドは大きくなければならず、必ずしもそうではありませんでした)。私がそれを解決した方法は、最初のオペランドが既に小さかったかどうかをチェックする前にブロックを追加することでした。

0

このコメント:

//dynamically allocated because the BigNum destructor requires it 

BigNumコンストラクタは単に引数にnumbersメンバーを設定し、デストラクタはdelete [] numbersを行うことを意味します。しかし、これは同じnumbersポインタを持つ2つのBigNumオブジェクトを持つべきではないことを意味します。その1つが破棄されると、もう1つは無効な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コンストラクタでこれを行うには良いだろう - それは、同じモジュール内のメモリを割り当て、解放のために責任を持つことが一般的にお勧めします。自分の質問に答える

関連する問題