2016-04-30 127 views
2

我遇到问题,我的乘法方法只处理一行,它目前没有前进到下一行。 add函数工作正常,我可以更新当前的十六进制数,但出于某种原因,我只能得到一行乘法运算。C++十六进制计算器乘法

Example input: 
111# * 333# = 333 
123# * 123# = 369 

这里是有问题的代码:

LList* Calculator::multiply(LList& left, LList& right) { 
    int product, carry = 0, lval = 0, rval = 0, zeros = 0; 
    bool calculating = true; 
    listnode *leftNode; 
    vector <LList*> addList; 
    listnode *rightNode; 
    LList* newHex; 
    while(calculating) { 

     leftNode = left.next(); 
     if(leftNode == NULL) { 
      break; 
     } 
     else { 
      lval = leftNode->data; 
     } 


     //leftNode = left.next(); 
     right.reset(); 

     if(leftNode == NULL) { 
      calculating = false; 
      if(carry != 0) { 
       //newHex->insertTail(carry); 
      } 
      lval = 0; 
      break; 
     } 

     LList* curList = new LList; 
     addList.push_back(curList); 

     while(rightNode != NULL) { 

      // Add however zeros we need for 
      // each entry based on the zero counter 
      for(int i = 0; i < zeros; i++) { 
       curList->insertTail(0); 
      } 

      rightNode = right.next(); 


      if(rightNode == NULL) { 

      } 
      else { 
      rval = rightNode->data; 

      product = lval * rval + carry; 
      carry = 0; 
      if(product >= 16) { 
       carry = (product/16); 
       product = (product % 16); 
      } 
      curList->insertTail(product); 
      } 
     } 
     zeros++; 


    } 

    Calculator calc; 
    LList* temp; 
    // Add up everything in the addList 
    for(int i = 0; i < addList.size() - 1; i++) { 
     if(temp == NULL) 
      temp = calc.add(*addList[i], *addList[i+1]); 
     else 
      temp = calc.add(*addList[i+1], *temp); 
    } 

    newHex = temp; 

    // Delete it 
    for(int i = 0; i < addList.size(); i++) { 

    } 

    return newHex; 
}; 

这里是下一个方法:

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

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

完整的程序:

#include <iostream> 
#include <vector> 
#include <stdlib.h> 
#include <string> 
using namespace std; 
#undef NULL 
const int NULL = 0; 
const char SENTINEL = '#'; 
typedef int element; 

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); 
     inline LList* multiply(LList& left, LList& right); 
}; 

Calculator::Calculator() { 

}; 

LList* Calculator::add(LList& left, LList& right) { 
    int sum, carry = 0, lval = 0, rval = 0; 
    bool calculating = true; 
    listnode *leftNode; 
    listnode *rightNode; 
    LList* newHex = new LList; 
    while(calculating) { 
     leftNode = left.next(); 
     rightNode = right.next(); 

     if(leftNode == NULL) { 
      lval = 0; 
     } 
     else 
      lval = leftNode->data; 

     if(rightNode == NULL) { 
      rval = 0; 
     } 
     else 
      rval = rightNode->data; 


     if(leftNode == NULL && rightNode == NULL) { 
      calculating = false; 
      if(carry != 0) { 
       newHex->insertTail(carry); 
      } 
      break; 
     } 

     sum = lval + rval + carry; 
     carry = 0; 
     if(sum >= 16) { 
      carry = 1; 
      sum -= 16; 
     } 

     newHex->insertTail(sum); 

    } 

    return newHex; 
}; 


LList* Calculator::multiply(LList& left, LList& right) { 
    int product, carry = 0, lval = 0, rval = 0, zeros = 0; 
    bool calculating = true; 
    listnode *leftNode; 
    vector <LList*> addList; 
    listnode *rightNode; 
    LList* newHex; 
    while(calculating) { 

     leftNode = left.next(); 
     if(leftNode == NULL) { 
      break; 
     } 
     else { 
      lval = leftNode->data; 
     } 


     //leftNode = left.next(); 
     right.reset(); 

     if(leftNode == NULL) { 
      calculating = false; 
      if(carry != 0) { 
       //newHex->insertTail(carry); 
      } 
      lval = 0; 
      break; 
     } 

     LList* curList = new LList; 
     addList.push_back(curList); 

     while(rightNode != NULL) { 

      // Add however zeros we need for 
      // each entry based on the zero counter 
      for(int i = 0; i < zeros; i++) { 
       curList->insertTail(0); 
      } 

      rightNode = right.next(); 


      if(rightNode == NULL) { 

      } 
      else { 
      rval = rightNode->data; 

      product = lval * rval + carry; 
      carry = 0; 
      if(product >= 16) { 
       carry = (product/16); 
       product = (product % 16); 
      } 
      curList->insertTail(product); 
      } 
     } 
     zeros++; 


    } 



    Calculator calc; 
    LList* temp; 
    // Add up everything in the addList 
    for(int i = 0; i < addList.size() - 1; i++) { 
     if(temp == NULL) 
      temp = calc.add(*addList[i], *addList[i+1]); 
     else 
      temp = calc.add(*addList[i+1], *temp); 
    } 

    newHex = temp; 

    // Delete it 
    for(int i = 0; i < addList.size(); i++) { 

    } 

    return newHex; 
}; 

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

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

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


LList::LList(){ 
    /* 
    next: 
    This is used to set the linked 
    list to NULL. 
    */ 
    head = NULL; 
    view = NULL; 
}; 


void LList::print() { 
    listnode * temp; 
    int i = 0; 
    string printValues; 
    temp = head; 
    while(temp != NULL) { 
     int var = temp -> data; 
     char character = ' '; 
     if(i % 3 == 0 && i != 0) 
      printValues += ','; 
     i++;  
     if(var > 9 && var < 16) { 
      character = static_cast <char>(var + 65 - 10); 
     }; 
     if (var <= 9 && var >= 0) { 
      character = static_cast <char>(var + 48); 
     }; 
     if (var > 96 && var < 103) { 
      character = static_cast <char>(var + 97 + 10); 
     }; 

     printValues += character; 
     temp = temp -> next; 

    } 
    string tempValues; 
    for(int i = printValues.length() - 1; i >= 0; i--) 
     tempValues += printValues[i]; 
    cout << tempValues; 
    cout << endl; 
}; 

void LList::read() { 
    string userval; 
    int i; 
    bool parsing = true; 
    char curval; 
    vector <int> values; 
    clean(); 
    while(parsing) { 
     cin >> userval; 
     for(unsigned int i = 0; i < userval.length(); i++) { 
      curval = userval[i];  
      if(curval >= 48 && curval <= 57) 
       values.push_back(static_cast <int>(curval - 
      48)); 

      if(curval >= 65 && curval <= 70) 
       values.push_back(static_cast <int>(curval - 
      65 + 10)); 

      if(curval >= 97 && curval <= 102) 
       values.push_back(static_cast <int>(curval - 
      97 + 10)); 

      if(curval == ' ') 
       break; 

      if(curval == SENTINEL) { 
       parsing = false; 
       break; 
      } 
     } 
    } 
    for(int i = values.size() -1; i >= 0; i--) { 
     insertTail(values[i]); 
    } 
}; 

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

void validCommands() { 
    cout << "Valid commands are:" << endl; 
    cout << " e enter enter the current "; 
    cout << "hexadecimal "; 
    cout << "number from the keyboard" << endl; 
    cout << " a add  add a new hexadecimal "; 
    cout << "number to the current hex. number" << endl; 
    cout << " m multiply "; 
    cout << "multiply a new hexadecimal number "; 
    cout << "by the current hex. number" << endl; 
    cout << " h help show this help menu" << endl; 
    cout << " q quit quit the program" << endl << endl; 
}; 

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

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

int main() { 
    LList L, add,multiply; 
    Calculator calc; 
    L.insertTail(0); 
    char option; 
    bool run; 
    cout << "Hexadecimal Calculator, Ver 1.0.0 \n"; 



    do { 
     /* 
    This do while is used to continuosly run the 
    program until the user decides to end. 
    */ 
    cout << "Current Hexadecimal number is: "; 
    L.print(); 
    cout << endl; 

    cout << "Command (h for help): "; 
    cin >> option; 

    cout << endl << endl; 
     switch(option) { 
      case 'e' : 
       cout << "Enter a hexadecimal number "; 
       cout << "followed by #: "; 
       L.read(); 
       cout << endl << "Entering completed."; 
       cout << endl << endl; 
      break; 
      case 'a' : 
       cout << "Adding a new hexadecimal number "; 
       cout << "to the current hex. number" << endl; 
       cout << endl; 
       cout << "Enter a hexadecimal "; 
       cout << "number, follow by #: "; 
       add.read(); 
       cout << endl << "Addition completed."; 
       cout << endl; 
       L = *calc.add(L, add); 
       cout << endl; 
       break; 
      case 'm' : 
       cout << "Multiplying a new hexadecimal "; 
       cout << "number "; 
       cout << "to the current hex. number" << endl; 
       cout << endl; 
       cout << "Enter a hexadecimal "; 
       cout << "number, follow by #: "; 
       multiply.read(); 
       cout << endl << "Multiplication completed."; 
       cout << endl; 
       L = *calc.multiply(L, multiply); 
       cout << endl; 
       break; 
      case 'h' : validCommands(); 
      break; 
      case 'q' : run = false; 
      break; 
     }; 
    } while (run); 
     exit(0); 

} 
+1

查找通过调试和/或断言发生不希望行为的确切行。 – krOoze

+0

我会建议您计算初始化'temp'的次数。 – molbdnilo

回答

1

while(rightNode != NULL)使用第一评价一个非初始的在运行程序时碰巧不为NULL的rightNode的值。在检查之后,在解除引用之前,rightNode被设置为从right.next()开始的有效节点指针值。但是对于下一个左边的数字,rightnode与前一个循环仍为NULL,因为它在right.reset()之后没有更新,所以对于第一个数字之后的每个数字,while(rightNode != NULL)总是以rightNode设置为NULL开始,因此第一个之后的所有循环都是跳过。

一旦这个问题得到解决,另一个bug就会暴露出来:在右侧数字循环内部的零点被添加到curList中,所以每当处理一个右数字时就会添加零。相反,在左数字循环内创建curList之后,应在右数字循环之前添加零。

还有另一个错误(我认为) - 右位循环结束后,任何进位值不添加到curList最后一个数字 - 而不是它被保存为下个右位循环的开始。这可能是故意的,但我不认为它总是会以正确的数字位置结束(但也许我在这一点上是错误的 - 我没有专心考虑可能性)。

为了调试你的问题,我不得不复制你的代码,填写缺失的部分并修复错误。此外,还有一些风格问题,并非实际的错误或错误,但已知会促成问题。因此,这里是我对版本所做的测试变化:

  • LLIST包含next()reset()访问的状态迭代器(view)。将来,您的代码的多个部分可能需要同时迭代同一个LList,但他们将无法共享LList对象所拥有的单个迭代状态。迭代器对象解决了这个问题。

  • 在“用户”代码中使用原始指针:应尽可能避免指针操作,或者限制为“库”代码 - 就像在LList对象中一样。没有必要处理Calculator类中的指针。

  • 变量应在其使用所需的最内层范围内声明。代码的第一个问题,rightNode从前一个循环中取得的值,如果遵循此样式点,则不会发生。

  • 有没有必要保留一个向量(addList)的条款总结在函数的结尾。我的版本保留一个运行总和LList名为prodSum

这里是我的版本的代码,包括我自己LList和计算器::增加,因为你没有做这些可用。请注意,LList适用于此处的迭代器,而不是view成员。我的迭代器可以在最终位置“取消引用”,并给出一个零。这是为了方便而完成的,因为对于任何值都隐含高于最高位的高位零的无限串:

#include <iostream> 
#include <string> 
#include <vector> 

struct listnode { 
    int data; 
    listnode *next; 
    listnode(int data=0) : data(data), next(0) {} 
}; 

class LList { 
    listnode *head, *tail; // head is least significant end 
    void delNodes() { 
     listnode* node = head; 
     while(node) { 
      listnode* todel = node; 
      node = node->next; 
      delete todel; 
     } 
     head = tail = 0; 
    } 
public: 
    LList() : head(0), tail(0) {} 
    LList(std::string digits) : head(0), tail(0) { 
     for(auto it = digits.rbegin(); it != digits.rend(); ++it) { 
      if(*it >= '0' && *it <= '9') insertTail(*it - '0'); 
      else if(*it >= 'a' && *it <= 'f') insertTail(*it - 'a' + 10); 
      else if(*it >= 'A' && *it <= 'F') insertTail(*it - 'A' + 10); 
    } } 
    LList(const LList& src) : head(0), tail(0) { 
     for(int data : src) { insertTail(data); } 
    } 
    ~LList() { delNodes(); } 
    LList& operator = (const LList& src) { 
     delNodes(); 
     for(int data : src) { insertTail(data); } 
     return *this; 
    } 
    void insertTail(int value) { 
     listnode *newnode = new listnode(value); 
     if(!head) { 
      head = tail = newnode; 
     } else { 
      tail->next = newnode; 
      tail = newnode; 
    } } 
    class iterator { 
     friend LList; 
     const listnode* node; 
     iterator(const listnode* node) : node(node) {} 
    public: 
     iterator& operator ++() { if(node) node = node->next; return *this; } 
     int operator *() const { return node ? node->data : 0; } 
     bool operator != (iterator iter) const { return iter.node != node; } 
     bool operator == (iterator iter) const { return iter.node == node; } 
    }; 
    iterator begin() const { return iterator(head); } 
    iterator end() const { return iterator(0); } 
    std::string get_digits() const { 
     static const char da[] = "abcdef"; 
     std::string digits; 
     for(int d : *this) { 
      digits = da[d] + digits; 
     } 
     return digits; 
    } 
}; 

LList add(const LList& left, const LList& right) { 
    LList sum; 
    auto liter = left.begin(); 
    auto riter = right.begin(); 
    int carry = 0; 
    while(liter != left.end() || riter != right.end()) { 
     int s = *liter + *riter + carry; 
     carry = s/16; 
     sum.insertTail(s % 16); 
     ++liter; 
     ++riter; 
    } 
    if(carry) sum.insertTail(carry); 
    return sum; 
} 

LList multiply(const LList& left, const LList& right) { 
    LList prodSum; 
    auto leftNode = left.begin(); 
    int zeros = 0; 
    for(;;) { 
     if(leftNode == left.end()) break; 
     int lval = *leftNode; 
     LList curList; 
     for(int i = 0; i < zeros; i++) { 
      curList.insertTail(0); 
     } 
     auto rightNode = right.begin(); 
     int carry = 0; 
     while(rightNode != right.end()) { 
      int rval = *rightNode; 
      int product = lval * rval + carry; 
      carry = product/16; 
      product %= 16; 
      curList.insertTail(product); 
      ++rightNode; 
     } 
     while(carry) { 
      curList.insertTail(carry % 16); 
      carry /= 16; 
     } 
     prodSum = add(prodSum, curList); 
     ++leftNode; 
     ++zeros; 
    } 

    return prodSum; 
} 

int main() { 
    LList a("111"); 
    LList b("333"); 
    LList c = multiply(a, b); // 36963 
    std::cout << c.get_digits() << '\n'; 
} 
+1

伟大的答案,如此深入。谢谢。如果您对我在@Christopher Oicles的做法感到好奇,我已经添加了完整的程序。 – Aaron

+1

“LList”的赋值操作符在两种方式中存在错误:1)不检查自赋值; 2)如果'insertTail'抛出异常,则删除了节点,此时对象无效。使用复制/交换。 '{LList temp(src); std :: swap(temp.head,head); std :: swap(temp.tail,tail);返回*这;}' – PaulMcKenzie

+1

好吧,现在我看到目前出现的情况,我想重新澄清我的意图。在我提交答案的时候,OP提供的唯一代码是'Calculator :: multiply(...)'和'LList :: next()'。为了调试'multiply(...)',我需要为''LList'类和'Calculator :: add(...)'创建最低限度的功能。这些只是答案,所以它的代码可以被构建和执行。后来才发布了OP的全部代码。所以在这里,唯一一个重要的威胁就是'multiply(...)'函数,我的版本的'LList'和'add(...)'不是OP的替代品。 –