С Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
AlexSome
0 / 0 / 0
Регистрация: 14.01.2012
Сообщений: 6
#1

Ошибка при освобождении памяти - C++

14.01.2012, 05:48. Просмотров 813. Ответов 10
Метки нет (Все метки)

Здравствуйте. Знаю, что тема уже много раз поднималась в самых разнообразных местах и с очень отличающимися примерами, но, увы, я тоже с ней столкнулся, и не могу никак найти свою ошибку.

В общем, решил я написать библиотеку длинной арифметики. Так, для себя. Раньше уже таким занимался, но теперь решил сделать всё красиво и через классы. Даже не дойдя до самих арифметических операций, столкнулся с ошибкой при использовании оператора delete.

В общем, вот:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
 
const unsigned int max_digits = 4; // сколько десятичных цифр может поместиться в одном разряде класса number
const unsigned int max_value = 65535; // максимальное значение выбранного типа
 
class number
{
    private:
    unsigned int* base;
    public:
    number();
    number(const number& obj); // конструктор копии
    void clear_nulls(); // очистка незначащих нулей
    void input();
    void output();
    friend bool operator== (number obj1, number obj2);
};
 
number::number() // создание нулевого числа
{
    base = new unsigned int[2];
    base[0] = 1; // длина нулевого числа
    base[1] = 0; // сам ноль
}
 
number::number(const number& obj)
{
    base = new unsigned int [obj.base[0] + 1]; // выделяем столько же памяти (1 для разряда размера)
    for (unsigned int i = 1; i<= base[0]; i++)
        base[i] = obj.base[i]; // копирование разрядов
}
 
void number::clear_nulls()
{
    unsigned int new_n = base[0]; // длина нового слова
    while (base[new_n] == 0)
        new_n--; // доходим до старшего ненулевого разряда
    if (new_n < base[0]) // если есть смысл очищать
    {
        unsigned int* temp_array = new unsigned int [new_n+1]; // создаём новый массив + место для разряда размера
        temp_array[0] = new_n; // он будет новой длины
        for (unsigned int i=1; i<=new_n; i++)
            temp_array[i] = base[i]; // переносим значения из изначального массива
        delete []base; // очищаем изначальный массив
        // так как temp_array очистится при выходе из видимости, то опять выделяем память под base
        // код идентичный коду выше
        base = new unsigned int [new_n+1];
        base[0] = new_n;
        for (unsigned int i=1; i<=new_n; i++)
            base[i] = temp_array[i];
        delete []temp_array;
    }
}
 
void number::input()
{
    delete []base; // очистка предидущего содержания числа
    // т.к. мы не знаем, каких размеров число мы введём, то зададим максимальный
    base = new unsigned int [max_value];
    base[0] = max_value;
    for (unsigned int i=1; i<=max_value; i++)
        base[i] = 0; // обнуление числа
 
    unsigned int signs_count = 0; // число введённых знаков
    char curr_char; // текущий введённый символ
    cin.get(curr_char); // считывание символа
    while (isdigit(curr_char)) // работа до тех пор, пока считанный символ - цифра
    {
        signs_count++; // прибавляем счётчик считанных символов
        unsigned int temp_add; // будет использовать при сдвиге цифр
        temp_add = curr_char - '0'; // изначально равен введённой цифре
        for (unsigned int i=1; i <= ( signs_count-1 ) / max_digits + 1; i++) // (s_c-1) / max_digits + 1 - число разрядов, которые придётся сдвигать (экономия времени)
        {
            base[i] *= 10; // сдвиг разряда влево на 1
            base[i] += temp_add; // вносим в его младший разряд наше число
            temp_add = base[i] / pow(10, max_digits); // делим текущий разряд на его максимальную вместимость (степень десятки)
            base[i] %= (unsigned int)pow(10, max_digits); // откидываем старший (не из имеющихся, а заданный) разряд
        }
        cin.get(curr_char); // считывание следующего символа
    }
 
    this->clear_nulls(); // очищаем незначащие нули
}
 
void number::output()
{
    unsigned int i = base[0]; // старший разряд
    cout << base[i]; // вывели его (без значащих нулей)
    i--; // сместились на разряд влево
    while (i >= 1) // пока не дошли до 0го разряда (количество разрядов)
    {
        cout<<setfill('0')<<setw(max_digits)<<base[i]; // вывели, даже если есть нули
        i--; // смещаемся дальше влево
    }
}
 
bool operator==(number obj1, number obj2)
{
    if (obj1.base[0] != obj2.base[0]) // если не совпадают длины, то это явно не одинаковые числа
        return false;
    else
    {
        unsigned int i = 1;
        bool eq = true; // допускаем, что числа равны
        while (i <= obj1.base[0] && eq) // пока ещё не дошли до конца и пока не опровергли гипотезу о равности
        {
            if (obj1.base[i] == obj2.base[i]) // если в данном месте числа равны - идём дальше
                i++;
            else
                eq = false; // если хоть в одном месте числа не равны - сразу выход
        }
        return eq;
    }
}
 
int main()
{
    number numb1;
    numb1.input();
    number numb2;
    numb2.input();
    cout << boolalpha << (numb1 == numb2);
    cin.get();
    return 0;
}
Код комментировал для себя, надеюсь, и вам будет всё понятно.
При выполнении выдаёт (замечу: ошибка происходит именно на строке "numb2.input();", что есть загадка: первый раз, для первого объекта, всё проходит гладко, а для второго - ошибка):
123
123
*** glibc detected *** /home/alex/CB/long_ar/bin/Debug/long_ar: double free or corruption (out): 0x0804b028 ***
======= Backtrace: =========
/lib/libc.so.6(+0x714ae)[0xb761f4ae]
/lib/libc.so.6(cfree+0x70)[0xb7623050]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb77fbff1]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xb77fc04d]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048961]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048bbf]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048d36]
/lib/libc.so.6(__libc_start_main+0xe6)[0xb75c4db6]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048791]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:03 1190984 /home/alex/CB/long_ar/bin/Debug/long_ar
0804a000-0804b000 rw-p 00001000 08:03 1190984 /home/alex/CB/long_ar/bin/Debug/long_ar
0804b000-080ac000 rw-p 00000000 00:00 0 [heap]
b7400000-b7421000 rw-p 00000000 00:00 0
b7421000-b7500000 ---p 00000000 00:00 0
b75ab000-b75ae000 rw-p 00000000 00:00 0
b75ae000-b770a000 r-xp 00000000 08:03 403253 /lib/libc-2.13.so
b770a000-b770b000 ---p 0015c000 08:03 403253 /lib/libc-2.13.so
b770b000-b770d000 r--p 0015c000 08:03 403253 /lib/libc-2.13.so
b770d000-b770e000 rw-p 0015e000 08:03 403253 /lib/libc-2.13.so
b770e000-b7711000 rw-p 00000000 00:00 0
b7711000-b772c000 r-xp 00000000 08:03 1053512 /usr/lib/libgcc_s.so.1
b772c000-b772d000 rw-p 0001a000 08:03 1053512 /usr/lib/libgcc_s.so.1
b772d000-b7751000 r-xp 00000000 08:03 403257 /lib/libm-2.13.so
b7751000-b7752000 r--p 00023000 08:03 403257 /lib/libm-2.13.so
b7752000-b7753000 rw-p 00024000 08:03 403257 /lib/libm-2.13.so
b7753000-b7830000 r-xp 00000000 08:03 1054254 /usr/lib/libstdc++.so.6.0.14
b7830000-b7834000 r--p 000dd000 08:03 1054254 /usr/lib/libstdc++.so.6.0.14
b7834000-b7835000 rw-p 000e1000 08:03 1054254 /usr/lib/libstdc++.so.6.0.14
b7835000-b783c000 rw-p 00000000 00:00 0
b7852000-b7854000 rw-p 00000000 00:00 0
b7854000-b7871000 r-xp 00000000 08:03 403295 /lib/ld-2.13.so
b7871000-b7872000 r--p 0001c000 08:03 403295 /lib/ld-2.13.so
b7872000-b7873000 rw-p 0001d000 08:03 403295 /lib/ld-2.13.so
bfd94000-bfdb5000 rw-p 00000000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]

Process returned -1 (0xFFFFFFFF) execution time : 1.678 s
Press ENTER to continue.
Должен ещё сказать, что до этого я уже реализовывал эту библиотеку. Но тогда я обошёл проблему не задумываясь, просто не освобождая память (очень срочно надо было её написать, и так проконало). Теперь же второй раз так поступать не хочу, но уже битый час сижу в попытках понять, что я делаю не так.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.01.2012, 05:48
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Ошибка при освобождении памяти (C++):

Ошибка при освобождении памяти - C++
Задача: Из стандартного входного потока вводятся сроки. Признаком завершения каждой сроки является символ ‘\n’. Признаком конца текста...

Ошибка при освобождении памяти - C++
#include &lt;iostream&gt; using namespace std; template&lt;class T&gt; class pvector { T **p; int sz; public:

Ошибка при освобождении памяти - C++
Здравствуйте, программа завершает работу в этом коде #include &lt;iostream&gt; #include &lt;ctime&gt; #include &lt;cmath&gt; int main() { ...

Ошибка при освобождении памяти - C++
Все идет замечательно, но вот когда происходит удаление массива программа крашится.. #include &lt;iostream&gt; using namespace std; ...

Ошибка при освобождении памяти - C++
Добрый День! Написал простую программу для понимания сути. Проблема в том, что код, который прилагается выдает ошибку. Но если убрать...

Ошибка при освобождении памяти - C++
#include &lt;iostream&gt; using namespace std; #include &lt;stdlib.h&gt; #include &lt;fstream&gt; #include &lt;stdio.h&gt; void *malloc (size_t...

10
greeezz
274 / 167 / 4
Регистрация: 10.07.2011
Сообщений: 441
14.01.2012, 06:11 #2
запустите ваш код с вот такой функцией main
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main() {
    number numb1;
 
    cout << "\nPlease enter first number\n";
    numb1.input();
 
 
    cout << "\nPRINT NUMB1\n";
    numb1.output();
 
    number numb2;
    cout << "\n\nPlease enter second number\n";
    numb2.input();
 
    cout << "\nPRINT NUMB2\n";
    numb2.output();
 
//  cout << "\nBOLLALPHA"<< boolalpha << (numb1 == numb2);
    cin.get();
    return 0;
}
ошибка которая приводит к крэшу в операторе сравнения.

Добавлено через 2 минуты
ВЫВОД

Please enter first number
1234

PRINT NUMB1
1234

Please enter second number
12345

PRINT NUMB2
12346



кстати еще обратите внимание на разницу между инпут данными и аутпут данными
0
AlexSome
0 / 0 / 0
Регистрация: 14.01.2012
Сообщений: 6
14.01.2012, 06:14  [ТС] #3
Спасибо за быстрый ответ.
ошибка которая приводит к крэшу в операторе сравнения.
Увы, мой ПК так не считает.
Please enter first number
1234

PRINT NUMB1
1234

Please enter second number
1234
*** glibc detected *** /home/alex/CB/long_ar/bin/Debug/long_ar: double free or corruption (out): 0x0804b028 ***
======= Backtrace: =========
/lib/libc.so.6(+0x714ae)[0xb75a94ae]
/lib/libc.so.6(cfree+0x70)[0xb75ad050]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb7785ff1]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xb778604d]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048941]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048b9f]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048d63]
/lib/libc.so.6(__libc_start_main+0xe6)[0xb754edb6]
/home/alex/CB/long_ar/bin/Debug/long_ar[0x8048771]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:03 1190984 /home/alex/CB/long_ar/bin/Debug/long_ar
0804a000-0804b000 rw-p 00001000 08:03 1190984 /home/alex/CB/long_ar/bin/Debug/long_ar
0804b000-080ac000 rw-p 00000000 00:00 0 [heap]
b7400000-b7421000 rw-p 00000000 00:00 0
b7421000-b7500000 ---p 00000000 00:00 0
b7535000-b7538000 rw-p 00000000 00:00 0
b7538000-b7694000 r-xp 00000000 08:03 403253 /lib/libc-2.13.so
b7694000-b7695000 ---p 0015c000 08:03 403253 /lib/libc-2.13.so
b7695000-b7697000 r--p 0015c000 08:03 403253 /lib/libc-2.13.so
b7697000-b7698000 rw-p 0015e000 08:03 403253 /lib/libc-2.13.so
b7698000-b769b000 rw-p 00000000 00:00 0
b769b000-b76b6000 r-xp 00000000 08:03 1053512 /usr/lib/libgcc_s.so.1
b76b6000-b76b7000 rw-p 0001a000 08:03 1053512 /usr/lib/libgcc_s.so.1
b76b7000-b76db000 r-xp 00000000 08:03 403257 /lib/libm-2.13.so
b76db000-b76dc000 r--p 00023000 08:03 403257 /lib/libm-2.13.so
b76dc000-b76dd000 rw-p 00024000 08:03 403257 /lib/libm-2.13.so
b76dd000-b77ba000 r-xp 00000000 08:03 1054254 /usr/lib/libstdc++.so.6.0.14
b77ba000-b77be000 r--p 000dd000 08:03 1054254 /usr/lib/libstdc++.so.6.0.14
b77be000-b77bf000 rw-p 000e1000 08:03 1054254 /usr/lib/libstdc++.so.6.0.14
b77bf000-b77c6000 rw-p 00000000 00:00 0
b77db000-b77de000 rw-p 00000000 00:00 0
b77de000-b77fb000 r-xp 00000000 08:03 403295 /lib/ld-2.13.so
b77fb000-b77fc000 r--p 0001c000 08:03 403295 /lib/ld-2.13.so
b77fc000-b77fd000 rw-p 0001d000 08:03 403295 /lib/ld-2.13.so
bf897000-bf8b8000 rw-p 00000000 00:00 0 [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]

Process returned -1 (0xFFFFFFFF) execution time : 2.444 s
Press ENTER to continue.
UPD: При вводе ваших данных всё равно ошибка. Про отличие входных и выходных данных - не знаю, не могу проверить.
0
greeezz
274 / 167 / 4
Регистрация: 10.07.2011
Сообщений: 441
14.01.2012, 06:15 #4
Цитата Сообщение от AlexSome Посмотреть сообщение
Увы, мой ПК так не считает.
хм... сейчас еще потестирую
0
AlexSome
0 / 0 / 0
Регистрация: 14.01.2012
Сообщений: 6
14.01.2012, 06:18  [ТС] #5
В общем, у меня программа падает конкретно на 47ой строке моего кода, и конкретно при вводе второго числа.
0
soon
2542 / 1307 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
14.01.2012, 06:25 #6
Косяк в строках ##47-50

Добавлено через 1 минуту
Тут недавно обсуждалась тема с "glibc detected". Насколько я помню, она возникает, когда пытаются освободить память, которая не выделялась.
0
AlexSome
0 / 0 / 0
Регистрация: 14.01.2012
Сообщений: 6
14.01.2012, 06:32  [ТС] #7
Цитата Сообщение от soon Посмотреть сообщение
Косяк в строках ##47-50
То, что у меня программа падает на 47ой строке, я уже написал и сам.
Цитата Сообщение от soon Посмотреть сообщение
Тут недавно обсуждалась тема с "glibc detected". Насколько я помню, она возникает, когда пытаются освободить память, которая не выделялась.
Да, она возникает в том случае, что вы написали, или при попытке дважды очистить одну и ту же область памяти (в принципе то же самое). Но я от этого как-то ошибку до сих пор не нашёл. Для этого и обратился за помощью на форум, т.к. уже не знаю, с какой бы стороны подойти.
0
soon
2542 / 1307 / 81
Регистрация: 09.05.2011
Сообщений: 3,086
Записей в блоге: 1
14.01.2012, 06:34 #8
AlexSome, я полагаю, нужно еще раз пересмотреть input(). Потому, что даже если заново вводить numb1 - ошибка. Может есть смысл глянуть в сторону std::vector?

Добавлено через 21 секунду
Цитата Сообщение от AlexSome Посмотреть сообщение
То, что у меня программа падает на 47ой строке, я уже написал и сам.
Я просто страницу не обновил.
0
AlexSome
0 / 0 / 0
Регистрация: 14.01.2012
Сообщений: 6
14.01.2012, 06:41  [ТС] #9
Цитата Сообщение от soon Посмотреть сообщение
AlexSome, я полагаю, нужно еще раз пересмотреть input(). Потому, что даже если заново вводить numb1 - ошибка.
Я уже всю ночь копаюсь в этих 100 строках кода Вроде бы всё логично: освободили память из-под старого числа, выделили память под новое, ввели его, убрали лишние разряды - но тем не менее, ошибка. Хотя 1й раз почему-то и срабатывает. Мне кажется, это какая-то особенность использования классов на C++, иначе бы ошибка появлялась бы и при первом обращении к input

Цитата Сообщение от soon Посмотреть сообщение
Может есть смысл глянуть в сторону std::vector?
Я планирую пользоваться своей библиотекой при отсылке задач на сайт электронных олимпиад. А насколько я помню, функции stl не сильно быстрые. Ну и вообще, по-моему тут не должно быть никаких сложностей при реализации через массив. Если бы не эта...
0
greeezz
274 / 167 / 4
Регистрация: 10.07.2011
Сообщений: 441
14.01.2012, 07:46 #10
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от AlexSome Посмотреть сообщение
Косяк в строках ##47-50
ошибки не только там.
что пока бросилось в глаза.
- функция pow (double, double); а вы используете как int и unsigned int
- в строке 64 for (unsigned int i=1; i<=max_value; i++) выход за пределы массива

Добавлено через 3 минуты
если устранить этот выход вот так
C++
1
for (unsigned int i = 1; i < max_value; i++)
то input отрабатывает корректно
далее проблемы начинаются с функцией output.
она зацикливается.
и ошибка в операторе сравнения.

Добавлено через 20 минут
Цитата Сообщение от AlexSome Посмотреть сообщение
Я уже всю ночь копаюсь в этих 100 строках кода Вроде бы всё логично:
Я вам рекомендую отложить код в сторону. НАРИСОВАТЬ на листочке ход вашей программы. и описать основные узлы и написать программу заново. Кстати раз уже вы решили делать с использованием классов то зачем вы из функции в функцию "таскаете" размер вашего числа ??? создайте для этого private переменную size в классе и в результате у вас будет всегда простой доступ к ее значению.
сейчас например функция
void number::clear_nulls()
не имеет понятия какая новая длина вашего числа.
под нулевым индексом в массиве у вас там 65535.

з.ы.
Еще если вы хотите все сделать самостоятельно почему бы не реализовать связанный список ?
Для этого вам для удобства понадобится два класса.
1 - для описания (объекта) элемента списка.
2 - для манипуляции с (объектами) элементами в списке.

.. этопросто мое мнение.

Добавлено через 12 минут
я пофиксил ваш код. вроде работает что-то
так или иначе рекомендую переписать
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
 
const unsigned int max_digits = 4; // сколько десятичных цифр может поместиться в одном разряде класса number
const unsigned int max_value = 65535; // максимальное значение выбранного типа
 
class number {
private:
    unsigned int* base;
public:
    number();
    number(const number& obj); // конструктор копии
    void clear_nulls(); // очистка незначащих нулей
    void input();
    void output();
    bool operator==(const number &obj1);
};
 
number::number() // создание нулевого числа
{
    base = new unsigned int[2];
    base[0] = 1; // длина нулевого числа
    base[1] = 0; // сам ноль
}
 
number::number(const number& obj) {
    base = new unsigned int[obj.base[0] + 1]; // выделяем столько же памяти (1 для разряда размера)
    for (unsigned int i = 1; i <= base[0]; i++)
        base[i] = obj.base[i]; // копирование разрядов
}
 
void number::clear_nulls() {
    cout << base[0] << endl;
    unsigned int new_n = base[0]; // длина нового слова
    while (base[new_n] != 0){
        new_n++;
    
    }
 
 
 
         // доходим до старшего ненулевого разряда
    if (new_n < base[0]) // если есть смысл очищать
    {
        unsigned int* temp_array = new unsigned int[new_n + 1]; // создаём новый массив + место для разряда размера
        //cout << "!!!!!!" << new_n;
        temp_array[0] = new_n; // он будет новой длины
        for (unsigned int i = 1; i <= new_n; i++)
            temp_array[i] = base[i]; // переносим значения из изначального массива
        delete[] base; // очищаем изначальный массив
        // так как temp_array очистится при выходе из видимости, то опять выделяем память под base
        // код идентичный коду выше
        base = new unsigned int[new_n + 1];
        base[0] = new_n;
        for (unsigned int i = 1; i <= new_n; i++)
            base[i] = temp_array[i];
        delete[] temp_array;
    }
    
}
 
void number::input() {
    delete[] base; // очистка предидущего содержания числа
    // т.к. мы не знаем, каких размеров число мы введём, то зададим максимальный
    base = new unsigned int[max_value];
    base[0] = max_value;
    for (unsigned int i = 1; i < max_value; i++)   /////////////////////////!!!!!!!!!!!!!!!!!!!!!!!!! 
        base[i] = 0; // обнуление числа
 
    unsigned int signs_count = 0; // число введённых знаков
    char curr_char; // текущий введённый символ
    cin.get(curr_char); // считывание символа
    while (isdigit(curr_char)) // работа до тех пор, пока считанный символ - цифра
    {
        signs_count++; // прибавляем счётчик считанных символов
        unsigned int temp_add; // будет использовать при сдвиге цифр
        temp_add = curr_char - '0'; // изначально равен введённой цифре
        for (unsigned int i = 1; i <= (signs_count - 1) / max_digits + 1; i++) // (s_c-1) / max_digits + 1 - число разрядов, которые придётся сдвигать (экономия времени)
        {
            base[i] *= 10; // сдвиг разряда влево на 1
            base[i] += temp_add; // вносим в его младший разряд наше число
            temp_add = base[i] / pow(10.0, (double)max_digits); // делим текущий разряд на его максимальную вместимость (степень десятки)
            base[i] %= (unsigned int) pow(10.0, (double)max_digits); // откидываем старший (не из имеющихся, а заданный) разряд
        }
        cin.get(curr_char); // считывание следующего символа
    }
 
    base[0] = signs_count;
    this->clear_nulls(); // очищаем незначащие нули
}
 
void number::output() {
    unsigned int i = base[0]; // старший разряд
    cout << base[i]; // вывели его (без значащих нулей)
    i--; // сместились на разряд влево
    while (i >= 1) // пока не дошли до 0го разряда (количество разрядов)
    {
        cout << setfill('0') << setw(max_digits) << base[i]; // вывели, даже если есть нули
        i--; // смещаемся дальше влево
    }
}
 
bool number::operator==(const number &obj2) {
    if (this->base[0] != obj2.base[0]) // если не совпадают длины, то это явно не одинаковые числа
        return false;
    else {
        unsigned int i = 1;
        bool eq = true; // допускаем, что числа равны
        while (i <= this->base[0] && eq) // пока ещё не дошли до конца и пока не опровергли гипотезу о равности
        {
            if (this->base[i] == obj2.base[i]) // если в данном месте числа равны - идём дальше
                i++;
            else
                eq = false; // если хоть в одном месте числа не равны - сразу выход
        }
        return eq;
    }
}
 
int main() {
    number numb1;
 
    cout << "\nPlease enter first number\n";
    numb1.input();
 
 
    cout << "\nPRINT NUMB1\n";
//  numb1.output();
 
    number numb2;
    cout << "\n\nPlease enter second number\n";
    numb2.input();
 
    //cout << "\nPRINT NUMB2\n";
    //numb2.output();
 
    cout << "\nBOLLALPHA "<< (numb1 == numb2);
    cin.ignore(1000,'\n');
    cin.get();
    return 0;
}
ВЫВОД РАЗ

Please enter first number
123456

PRINT NUMB1


Please enter second number
123456

BOLLALPHA 1


ВЫВОД 2


Please enter first number
123456

PRINT NUMB1


Please enter second number
12345

BOLLALPHA 0



обратите внимания на изменения в перегруженном операторе сравнения, на строку 91 в моем коде и я попроавил выход за границы массива.
1
AlexSome
0 / 0 / 0
Регистрация: 14.01.2012
Сообщений: 6
14.01.2012, 15:07  [ТС] #11
greeezz, спасибо! Наконец-то я нашёл ошибку! А теперь всё по порядку:

функция pow (double, double); а вы используете как int и unsigned int
Я знаю, что это не совсем верно, но, тем не менее, одним из вариантов является такое использование:
double pow ( double base, int exponent );
а перевод потом из double в int меня устраивает.
в строке 64 for (unsigned int i=1; i<=max_value; i++) выход за пределы массива
Вот! Вот это место, из-за которого я сидел всю ночь! Как всегда, одну единичку не доглядел - и сиди мучайся Только я устранил не так, как вы предложили, а наоборот,
C++
1
base = new unsigned int [max_value + 1]; // + 1 для первого разряда (размера)
так как у меня разряд адреса (0й элемент моего массива) вполне может хранить значение <= 65535. Только всё равно для меня остаётся загадкой: если я всего-навсего 1 раз вылазил за пределы выделенной памяти - почему оно не ругалось при этом обращении, а именно потом при освобождении памяти? Тем не менее, теперь работает
Я вам рекомендую отложить код в сторону. НАРИСОВАТЬ на листочке ход вашей программы. и описать основные узлы и написать программу заново.
Я уже делал библиотеку длинной арфиметики, как я уже писал выше. Я пока что даже не успел дойти до особых сложностей, и ещё нет смысла ничего рисовать т.к. у меня всё прекрасно в голове укладывается. Как видите, вся проблема в том одном недовыделенном элементе
Кстати раз уже вы решили делать с использованием классов то зачем вы из функции в функцию "таскаете" размер вашего числа ???
Логичный совет. Я выбрал именно такую реализацию, т.к. есть идея потом сделать также вариацию без классов, а только используя функции. Если бы я ввёл дополнительную переменную, то я практически отрезал бы себе такую возможность, или пришлось бы создавать структуры (почему бы тогда не использовать те же классы).
сейчас например функция
void number::clear_nulls()
не имеет понятия какая новая длина вашего числа.
под нулевым индексом в массиве у вас там 65535.
Она не имеет понятия только когда работает после input'a, т.к. input по умолчанию задаёт максимальный размер числа.
Еще если вы хотите все сделать самостоятельно почему бы не реализовать связанный список ?
Для этого вам для удобства понадобится два класса.
1 - для описания (объекта) элемента списка.
2 - для манипуляции с (объектами) элементами в списке.
По-моему в таком случае будет намного сложнее писать функции длинной арифметики. Хотя это так, навскидку. Но в любом случае, связный список будет потреблять больше памяти (за счёт своих указателей) и выполняться, скорее всего, медленнее.

Спасибо за пример кода. Правда я там по-своему исправил, но, в любом случае, спасибо за помощь!

Вот теперь мой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
 
const unsigned int max_digits = 4; // сколько десятичных цифр может поместиться в одном разряде класса number
const unsigned int max_value = 65535; // максимальное значение выбранного типа
 
class number
{
    private:
    unsigned int* base;
    public:
    number();
    ~number();
    number(const number& obj); // конструктор копии
    void clear_nulls(); // очистка незначащих нулей
    void input();
    void output();
    friend bool operator== (number obj1, number obj2);
};
 
number::number() // создание нулевого числа
{
    base = new unsigned int[2];
    base[0] = 1; // длина нулевого числа
    base[1] = 0; // сам ноль
}
 
number::~number()
{
    delete []base; // просто очищаем память
}
 
number::number(const number& obj)
{
    base = new unsigned int [obj.base[0] + 1]; // выделяем столько же памяти (1 для разряда размера)
    base[0] = obj.base[0];
    for (unsigned int i = 1; i<= base[0]; i++)
        base[i] = obj.base[i]; // копирование разрядов
}
 
void number::clear_nulls()
{
    unsigned int new_n = base[0]; // длина нового слова
    while (base[new_n] == 0)
        new_n--; // доходим до старшего ненулевого разряда
    if (new_n < base[0]) // если есть смысл очищать
    {
        unsigned int* temp_array = new unsigned int [new_n+1]; // создаём новый массив + место для разряда размера
        temp_array[0] = new_n; // он будет новой длины
        for (unsigned int i=1; i<=new_n; i++)
            temp_array[i] = base[i]; // переносим значения из изначального массива
        delete []base; // очищаем изначальный массив
        // так как temp_array очистится при выходе из видимости, то опять выделяем память под base
        // код идентичный коду выше
        base = new unsigned int [new_n+1];
        base[0] = new_n;
        for (unsigned int i=1; i<=new_n; i++)
            base[i] = temp_array[i];
        delete []temp_array;
    }
}
 
void number::input()
{
    delete []base; // очистка предидущего содержания числа
    // т.к. мы не знаем, каких размеров число мы введём, то зададим максимальный
    base = new unsigned int [max_value + 1]; // + 1 для первого разряда (размера)
    base[0] = max_value;
    for (unsigned int i=1; i<=max_value; i++)
        base[i] = 0; // обнуление числа
 
    unsigned int signs_count = 0; // число введённых знаков
    char curr_char; // текущий введённый символ
    cin.get(curr_char); // считывание символа
    while (isdigit(curr_char) && signs_count < max_value * max_digits) // работа до тех пор, пока считанный символ - цифра, и пока число не превысит максимальный размер
    {
        signs_count++; // прибавляем счётчик считанных символов
        unsigned int temp_add; // будет использовать при сдвиге цифр
        temp_add = curr_char - '0'; // изначально равен введённой цифре
        for (unsigned int i=1; i <= ( signs_count-1 ) / max_digits + 1; i++) // (s_c-1) / max_digits + 1 - число разрядов, которые придётся сдвигать (экономия времени)
        {
            base[i] *= 10; // сдвиг разряда влево на 1
            base[i] += temp_add; // вносим в его младший разряд наше число
            temp_add = base[i] / pow(10, max_digits); // делим текущий разряд на его максимальную вместимость (степень десятки)
            base[i] %= (unsigned int)pow(10, max_digits); // откидываем старший (не из имеющихся, а заданный) разряд
        }
        cin.get(curr_char); // считывание следующего символа
    }
    if (signs_count > 0) // если ввели хоть одну цифру
    {
        base[0] = (signs_count - 1) / max_digits + 1; // размер высчитывается в зависимости от введённыих символов (для экономии времени при очистке нулей)
        this->clear_nulls(); // очищаем незначащие нули
    }
    else // иначе число считается нулём
    {
        delete []base; // очищаем ранее выделенную под число память
        base = new unsigned int [2];
        base[0] = 1;
        base[1] = 0;
    }
}
 
void number::output()
{
    unsigned int i = base[0]; // старший разряд
    cout << base[i]; // вывели его (без значащих нулей)
    i--; // сместились на разряд влево
    while (i >= 1) // пока не дошли до 0го разряда (количество разрядов)
    {
        cout<<setfill('0')<<setw(max_digits)<<base[i]; // вывели, даже если есть нули
        i--; // смещаемся дальше влево
    }
}
 
bool operator==(number obj1, number obj2)
{
    if (obj1.base[0] != obj2.base[0]) // если не совпадают длины, то это явно не одинаковые числа
        return false;
    else
    {
        unsigned int i = 1;
        bool eq = true; // допускаем, что числа равны
        while (i <= obj1.base[0] && eq) // пока ещё не дошли до конца и пока не опровергли гипотезу о равности
        {
            if (obj1.base[i] == obj2.base[i]) // если в данном месте числа равны - идём дальше
                i++;
            else
                eq = false; // если хоть в одном месте числа не равны - сразу выход
        }
        return eq;
    }
}
 
int main()
{
    number numb1;
    numb1.input();
    number numb2;
    numb2.input();
    cout << boolalpha << (numb1 == numb2);
    cin.get();
    return 0;
}
0
14.01.2012, 15:07
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.01.2012, 15:07
Привет! Вот еще темы с ответами:

Ошибка при освобождении памяти - C++
Здравствуйте! Пишу на MS Visual C++ 2010, windows 7. При вызове функции resize() на строке delete arr; происходит ошибка,...

Ошибка при освобождении памяти? - C++
Доброго времени суток! Я только-только взялся за изучение c++. Дошел до динамической памяти (разбираю по учебнику) и столкнулся с...

Ошибка при освобождении памяти (delete) - C++
Здравствуйте! Есть массив lines, созданный вот так : int *line = new int ; Потом, пытаюсь его удалить и пересоздать : delete...

Ошибка при освобождении памяти массива string - C++
Вот тут вот при delete возникает ошибка, и пишет &quot;The program ' Array Template.exe: Native' has exited with code 3 (0x3).&quot; template...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.