Массив, инициализированный со всеми элементами, поскольку ноль выплевывает случайные числа - PullRequest
0 голосов
/ 22 сентября 2019

Так что для моего задания я должен создать калькулятор, который работает с большими целыми числами длиной до 256 символов.Текущая часть задания, над которым я работаю, - заставить его работать с большими числами после начала с меньших.У меня есть массив, который заполняется числами и прекрасно работает с 10 числами во всех моих тестах.Я изменил значение DIGITS на 256 с 10, и после получения странных чисел я исследовал некоторые cout's, и оказалось, что если я добавлю 00000 + 00000 (могут быть числа любого размера или любые цифры, я выбрал их, так как это просто просеятьтак как все должно быть равно нулю во всех элементах массива) Я получаю очень странный ответ

(2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180000000000000020000000000000002000000000000000000000000000000000000000000000000000).

1004 * Я проверил каждый элемент массива и некоторые элементы будут заполнены случайным числом.Мой массив инициализирован с

digits_[DIGITS] = { 0 };, также пытался цикл for для установки элементов массива на ноль с теми же результатами.

DIGITS установлен в заголовочном файле как 256

Шаблон, который я заметил, состоит в том, что в обоих массивах n1 и n2, которые должны быть двумя разными числами, которые добавляются или вычитаются и т. Д., Заполняются тем же самым номером на этом конкретном элементе.Таким образом, n1 [81] и n2 [81] по некоторым причинам будут установлены в 9.Однако это меняется каждый раз, когда программа компилируется и запускается.

Полный код ниже (в методах приведены только метки для оценки массивов этих ошибок)

#include <iostream>
#include <string>
#include "Bigint.h"

using namespace std;

Bigint::Bigint()
{
        digits_[DIGITS] = { 0 };

}

ostream& operator<< (ostream& out, const Bigint& n)
{
    string s = "";
    bool found = false;
    for (int i = DIGITS - 1; i >= 0; --i) {
        if(n.digits_[i] > 0) {
            found = true;
        }
        if(n.digits_[i] != 0 || found == true) {
            s += char(n.digits_[i] + '0');
        }
    }
    if (s == "") {
        s = "0";
    }
    return out << s;
}

istream& operator>> (istream& in, Bigint& n)
{
    string s;
    if (in >> s) {
        for (int i = 0; i < DIGITS; ++i) {
            n.digits_[i] = s[s.length() - 1 - i] - '0';
        }
    }
    return in;
}

Bigint operator+ (const Bigint& n1, const Bigint& n2)
{
    Bigint ret;
    int cur_carry = 0;
    for(int i = 0; i < DIGITS; ++i) {
        int n1_digit = n1.get(i);
        int n2_digit = n2.get(i);
        if(n1_digit < 0 || n1_digit > 9) {
            n1_digit = 0;
        }
        if(n2_digit < 0 || n2_digit > 9) {
            n2_digit = 0;
        }
        printf("n1 : %d\n", n1_digit);
        printf("n2 : %d\n", n2_digit);
        int sum = n1_digit + n2_digit + cur_carry;
        cout << "sum : " << sum << endl;
        cur_carry = Bigint::getCarry(sum);
        cout << "new carry : " << cur_carry << endl;
        ret.set(i, Bigint::getDigitValue(sum));
        cout << "Set : " << i << "," << Bigint::getDigitValue(sum) << endl;
    }
    return ret;
}

Bigint operator- (const Bigint& n1, const Bigint& n2)
{
    Bigint ret;
    //Should only ever have a max value of 1, used to borrow values from next digit column of bigint
    int borrowed = 0;
    //Stores final value to subtract from
    int temp;
    for(int i = 0; i < DIGITS; --i) {
        int n1_digit = n1.get(i);
        int n2_digit = n2.get(i);
        if(n1_digit < 0 || n1_digit > 9) {
            n1_digit = 0;
        }
        if(n2_digit < 0 || n2_digit > 9) {
            n2_digit = 0;
        }


        //Ensure we take into account borrowed values from previous digit subtractions
        temp = n1_digit - borrowed;
        //Reset borrowed
        borrowed = 0;
        //If n1 digit value < n2 digit value we need to borrow a 10 from next digit column
        if(temp < n2_digit) {
            //Borrow 10 and increment borrowed for next computation
            temp = n1_digit + 10;
            borrowed++;
        }
        //Store value
        ret.set(i, temp - n2_digit);
    }
    return ret;
}

Bigint operator* (const Bigint& n1, const Bigint& n2)
{
    return n1; // Only correct when n2 equals 1.
}

Bigint operator/ (const Bigint& n1, const Bigint& n2)
{
    return n1; // Only correct when n2 equals 1.
}


int Bigint::get(int pos) const {
    int ret = digits_[pos];
    return ret;
}

void Bigint::set(int pos, int val) {
    this->digits_[pos] = val;
}

int Bigint::getCarry(int val) {
    return val/10;
}

int Bigint::getDigitValue(int val) {
    return val % 10;
}

Заголовочный файл:


#ifndef BIGINT_H_
#define BIGINT_H_

#define DIGITS 256

class Bigint
{
  public:

    /**
     * Creates a Bigint initialised to 0.
     */
    Bigint();

    /**
     * Inserts n into stream or extracts n from stream.
     */
    friend std::ostream& operator<< (std::ostream &out, const Bigint& n);
    friend std::istream& operator>> (std::istream &in, Bigint& n);

    /**
     * Returns the sum, difference, product, or quotient of n1 and n2.
     */
    friend Bigint operator+ (const Bigint& n1, const Bigint& n2);
    friend Bigint operator- (const Bigint& n1, const Bigint& n2);
    friend Bigint operator* (const Bigint& n1, const Bigint& n2);
    friend Bigint operator/ (const Bigint& n1, const Bigint& n2);

    int get(int pos) const;
    void set(int pos, int val);

    static int getCarry(int val);
    static int getDigitValue(int val);

  private:
    int digits_[DIGITS];
};

#endif // BIGINT_H_

Main.cpp

#include <iostream>
#include "Bigint.h"

using namespace std;

int main(int argc, char *argv[]) 
{
    Bigint n1, n2;
    char op;

    while (cin >> n1 >> op >> n2) {
        switch (op) {
        case '+' :
            cout << n1 + n2 << endl;
            break;
        case '-' :
            cout << n1 - n2 << endl;
            break;
        case '*' :
            cout << n1 * n2 << endl;
            break;
        case '/' :
            cout << n1 / n2 << endl;
            break;
        }
    }



    return 0;
}

1 Ответ

0 голосов
/ 22 сентября 2019

Проблема заключается в вашем конструкторе:

Bigint::Bigint()
{
        digits_[DIGITS] = { 0 };

}

Синтаксис digits_[DIGITS] = { 0 }; здесь не инициализирует все элементы от digits_ до 0.Он обращается к элементу DIGITS -ому (один за концом - это индекс вне границ) и устанавливает для него значение 0.Это неопределенное поведение , и программа, в которой он проявляется, может вести себя любым образом - ожидаемым или неожиданным.

Исправление довольно простое.Тот же самый синтаксис (digits_[DIGITS] = { 0 };) может использоваться для инициализации всех элементов 0, но он должен использоваться в объявлении .Итак, чтобы решить эту проблему, вы должны:

  1. избавиться от вышеуказанного конструктора
  2. заменить int digits_[DIGITS]; в заголовочном файле на int digits_[DIGITS] = {0};.

РЕДАКТИРОВАТЬ :

Похоже, у вас была другая ошибка - в вашем operator >>.Строка:

n.digits_[i] = s[s.length() - 1 - i] - '0';

также вызывает неопределенное поведение , если length() из s не равно DIGITS.При вводе 00000, s.length() == 5.Теперь ваш диапазон i составляет от 0 до DIGITS (255).Что происходит, когда, скажем, i == 100?Выполняется следующее:

n.digits_[100] = s[-96] - '0';

И это не то, что мы хотим.Вы должны добавить охрану для этого.Например:

n.digits_[i] = i < s.length() ? s[s.length() - 1 - i] - '0' : 0;
...