2016-05-01 12 views
1

私は最初、私はデバッガへのアクセス権を持っていないと私は私の電卓で、C++進乗算セグメンテーションフォールト

現在、私のエディタとしてnanoを使用していますと言ってみましょう、私はレンガに対して私の頭を叩いています壁(セグメンテーションフォルト)。私は自分の問題点を発見するために私の指針を通そうとしましたが、私の経験/知識の欠如はこれまでのところ私にしかわかりませんでした。私のプログラムでこれまでのことを説明しましょう。現在、私はリンクされたリストに16進数を格納し、それらを一緒に追加することができます。問題は私の乗法から来ています。何とかleftNodeはセグメンテーションフォールトを投げている乗算方法の途中でNULLになっています。私はleftNodeがどの点でNULLになるのだろうかと思っていますか?

乗算方法:乗算に関連

LList Calculator::multiply(LList& left, LList& right) { 
    LList prodSum; 
    listnode *leftNode = (left.next()); 
    int zeros = 0; 
    for(;;) { 
     if(leftNode == NULL) break; 
     int lval = leftNode->data; 
     LList curList; 
     for(int i = 0; i < zeros; i++) { 
      curList.insertTail(0); 
     } 
     right.reset(); 
     listnode *rightNode = (right.next()); 
     int carry = 0; 
     while(rightNode != NULL) { 
      int rval = rightNode->data; 
      int product = lval * rval + carry; 
      carry = product/16; 
      product %= 16; 
      curList.insertTail(product); 
      rightNode = (right.next()); 
     } 
     while(carry) { 
      curList.insertTail(carry % 16); 
      carry /= 16; 
     } 
     prodSum = *add(prodSum, curList); 
     leftNode = (left.next()); // eventually causes a segmentation fault 
     leftNode->data << endl; 
     ++zeros; 
    } 

    return prodSum; 
} 

クラス:ノードをトラバースに関する

class listnode { 
    public: 
     element data; 
     listnode * next; 
}; 

class LList { 
    private: 
     listnode * head; 
     listnode * tail; 
     listnode * view; 

    public: 
     LList(); 
     ~LList(); 
     void read(); 
     listnode* next(); 
     void reset(); 
     void print(); 
     void insertTail(element val); 
     void clean(); 

     element deleteHead(); 
}; 

class Calculator { 
    public: 
     Calculator(); 
     //inline LList* add(LList& left, LList& right); works 
     inline LList multiply(LList& left, LList& right); 
}; 

Calculator::Calculator() { 

}; 

他の方法:

listnode* LList::next() { 
    listnode* temp = view; 
    if(temp != NULL) 
     view = view->next; 

    if(view == NULL) { 
    } 
    return temp; 
}; 

void LList::reset() { 
    view = head; 
} 


LList::LList(){ 
    head = NULL; 
    view = NULL; 
}; 

void LList::insertTail(element val) { 
    listnode * temp; 
    temp = new listnode; 
    temp -> data = val; 
    temp -> next = NULL; 

    if(head == NULL) { 
     head = temp; 
     view = head; 
    } 
    else 
     tail -> next = temp; 
    tail = temp; 
}; 

void LList::clean() { 
    while(head != NULL) 
     deleteHead(); 
}; 

element LList::deleteHead() { 
    listnode * temp; 
    temp = head; 
    head = head -> next; 
    delete temp; 
    return temp -> data; 
}; 

LList::~LList(){ 
    delete head; 
}; 
+1

どのような問題がありますか?あなたの質問は何ですか? –

+0

なぜ乗算関数でセグメンテーションフォルトが発生しますか? – Aaron

+3

*私はデバッガにアクセスできない* - だから、どうやって簡単なことを書いていますか?あなたは間違いを探すために "あなたの頭の中で"プログラムを実行するつもりですか?あるいは、プログラムを初めて完全に書くことを期待していて、それらをデバッグする必要はありませんか?あなた自身をデバッガにしてください。 – PaulMcKenzie

答えて

1

もう一度私です。

唯一の例外は、あなたがマークされた行の後に発生します。// eventually causes a segmentation faultを、coutleftNode->dataを送信するための部分的に形成されたラインがあるようですが、の左のノードを介して、最終的な反復で、leftNode = (left.next());はNULLにleftNodeを設定しますので、ここでは逆参照障害を引き起こしている可能性があります。

もう1つの問題は、LListにコピーコンストラクタや代入演算子が定義されていないことです。この行はで、直後に削除される一連のリストノードをprodSumに与えます。

しかし、LListのデストラクタは、リスト全体ではなく、ヘッドノードを削除しているように見えるので、無効で有効な作業が行われています。

また、乗算するとprodSumが返されるため、コピーコンストラクタが不足すると同様のことが起こります。

動作するように思われるコードのバージョンが含まれています。私は自分でadd関数を作っていなければなりません、なぜなら私はここにそれが見えないからです。

デストラクターにLListのすべてのノードを削除させました。

デフォルトのコピーコンストラクタと代入演算子=deleteをマークしました。これはデフォルトの実装が間違っているからです。

LListオブジェクトを値で渡すために、移動コンストラクタと移動代入演算子を追加しました。これらはあるオブジェクトから別のオブジェクトに割り当てられたノードを渡し、1つのオブジェクトだけが1組のノードを保持することができるため、二重破壊を心配する必要はありません。

#include <iostream> 
#include <string> 

typedef int element; 

class listnode { 
    public: 
     element data; 
     listnode * next; 
}; 

class LList { 
     listnode *head, *tail, *view; 
    public: 
     LList() { head = view = tail = NULL; } 
     LList(LList&& src) : head(src.head), tail(src.tail), view(src.view) { src.head = src.tail = src.view = nullptr; } 
     LList(const LList&) = delete; 
     ~LList() { clean(); } 
     LList& operator = (LList&& src) { 
      clean(); 
      /* OK here */ 
      head = src.head; 
      tail = src.tail; 
      view = src.view; 
      src.head = src.tail = src.view = nullptr; 
      return *this; 
     } 
     LList& operator = (const LList&) = delete; 
     listnode* next() { 
      listnode* temp = view; 
      if(temp) view = view->next; 
      return temp; 
     } 
     void reset() { view = head; } 
     void print(); 
     void insertTail(element val) { 
      listnode* temp = new listnode; 
      temp->data = val; 
      temp->next = NULL; 

      if(!head) { view = head = temp; } 
      else  { tail->next = temp; } 
      tail = temp; 
     } 
     void clean() { while(head) deleteHead(); } 

     element deleteHead() { 
      listnode* temp = head; 
      head = head->next; 
      const element data = temp->data; 
      delete temp; 
      return data; 
     } 
}; 

LList add(LList& left, LList& right) { 
    LList sum; 
    int carry = 0; 
    left.reset(); 
    right.reset(); 
    for(;;) { 
     const listnode* leftNode = left.next(); 
     const listnode* rightNode = right.next(); 
     if(!leftNode && !rightNode) break; 
     if(leftNode) carry += leftNode->data; 
     if(rightNode) carry += rightNode->data; 
     sum.insertTail(carry % 16); 
     carry /= 16; 
    } 
    if(carry) sum.insertTail(carry); 
    return sum; 
} 

LList multiply(LList& left, LList& right) { 
    LList prodSum; 
    listnode *leftNode = left.next(); 
    int zeros = 0; 
    for(;;) { 
     if(!leftNode) break; 
     int lval = leftNode->data; 
     LList curList; 
     for(int i = 0; i < zeros; i++) { 
      curList.insertTail(0); 
     } 
     right.reset(); 
     listnode *rightNode = right.next(); 
     int carry = 0; 
     while(rightNode) { 
      int rval = rightNode->data; 
      int product = lval * rval + carry; 
      carry = product/16; 
      product %= 16; 
      curList.insertTail(product); 
      rightNode = right.next(); 
     } 
     while(carry) { 
      curList.insertTail(carry % 16); 
      carry /= 16; 
     } 
     prodSum = add(prodSum, curList); 
     leftNode = left.next(); // eventually causes a segmentation fault 
     //std::cout << leftNode->data << std::endl; 
     ++zeros; 
    } 
    return prodSum; 
} 

LList string_to_list(std::string hex_string) { 
    LList list; 
    for(size_t i=hex_string.length()-1; i+1; --i) { 
     char c = hex_string[i] | 0x20; 
     if  (c >= '0' && c <= '9') list.insertTail(c - '0'); 
     else if(c >= 'a' && c <= 'f') list.insertTail(c - 'a' + 10); 
    } 
    return list; 
} 

std::string list_to_string(LList& list) { 
    std::string hex_string; 
    list.reset(); 
    for(;;) { 
     listnode* node = list.next(); 
     if(!node) return hex_string; 
     static const char digits[] = "abcdef"; 
     hex_string = digits[node->data] + hex_string; 
    } 
} 

int main() { 
    //LList list = string_to_list("1234aBcd"); 
    //std::string s = list_to_string(list); 
    //std::cout << s << '\n'; 

    LList left = string_to_list("111"); 
    LList right = string_to_list("333"); 
    LList prod = multiply(left, right); 
    std::cout << list_to_string(prod) << '\n'; 
} 
+0

私の救世主!おかげで再び友人。 – Aaron

+0

*デフォルトのコピーコンストラクタと代入演算子= deleteは、デフォルトの実装が間違っているためマークしました。*コピーコンストラクタを記述するだけで済み、代入演算子はコピー/スワップを使って実装できます。私はすでにコメント[ここ](http://stackoverflow.com/questions/36961466/c-hexadecimal-calculator-multiplication)でこれを言及した – PaulMcKenzie

+0

@Xarotic私はこの行についてsometingについて忘れていた: 'prodSum = * add(prodSum 、curList); 'もし' add'が削除する必要のあるポインタ値を返すと、ポインタの値が失われ、メモリがリークします。また、ポインタのオブジェクトの値は左辺値なので、私の例を作るために必要なものを追加しただけなので、ポールの素晴らしいコピーコンストラクタを追加する必要があります。 –