Форум программистов, компьютерный форум CyberForum.ru

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

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 13, средняя оценка - 4.69
tes
0 / 0 / 0
Регистрация: 19.01.2011
Сообщений: 3
#1

И снова malloc... - C++

07.06.2011, 16:33. Просмотров 1676. Ответов 13
Метки нет (Все метки)

Всем привет!

Читаю книгу "Герберт Шилдт - самоучитель С++"
В нём такое задание:
Код
Измените класс stack так, чтобы память для стека выделялась динамически.
При этом длина стека должна задаваться параметром конструктора. 
(Не забудьте освободить эту память с помощью деструктора.)
Я выполнил в таком виде:

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
#include <cstdlib>
#include <iostream>
 
using namespace std;
 
#define max_size 100
 
class stack{
     char *stck;
     int tos;
     char who;
public:
     stack (char c, int pam);
     ~stack();
     void push(char ch);
     char pop(); 
};
 
stack::stack(char c, int pam)
{
     tos = 0;
     who = c;
     stck = (char*) malloc(pam);
     cout << pam << endl;
     if (!stck)
     {
          cout << "Ошибка выделения памяти" << endl;
          exit(1);
     }    
}
 
void stack::push(char ch)
{
     if (tos >= max_size){
          cout << "Стек " << who << " полон." << endl;
          return;
     }
 
     stck[tos] = ch;
     ++tos;
}
 
char stack::pop()
{
     if (tos == 0) {
          cout << "Стек " << who << " пуст." << endl;
          return 0x20;
     }
     else
     {
          --tos;
          return  stck[tos];
     };
}
 
stack::~stack()
{
     cout << "Освобождение памяти" << endl;
     free(stck);              
}
 
int main()
{
    stack s1('A',0), s2('B',0);
    int i;
    
    s1.push('a');
    s2.push('x');
    s1.push('b');
    s2.push('y');
    s1.push('c');
    s2.push('z');
    
 
    for (i = 0; i < 5; ++i) cout << "Символ из стека s1: " << s1.pop() << endl; //Для проверки запихиваем 3 , вытаскиваем 5
    for (i = 0; i < 5; ++i) cout << "Символ из стека s2: " << s2.pop() << endl;
 
    return EXIT_SUCCESS;
}
Потом меня взяли сомнения по поводу выделения памяти и я решил посмотреть ответы данные в конце книги, как оказалось там память выделяется так же...

Так собственно вопрос, почему когда я ставлю stack s1('A',0), s2('B',0);, у меня всё проходит нормально? Почему УМВР? ЧЯДН? Может кто нибудь прояснить ситуацию?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.06.2011, 16:33     И снова malloc...
Посмотрите здесь:

И снова динамическая память, malloc и free в конструкторе и деструкторе - C++
Короче есть, класс, который например хранит строку, я его храню в структуре, после я выдиляю динамическу память пот эту структуру и копирую...

Malloc vs new - C++
Здравствуйте. Вникаю в ручное управление памятью. Абзац из книги &quot;C++ для профессионалов&quot; не совпадает с моим представлением...

New и malloc - C++
Если смотреть на выделение памяти для арифметических типов уступает ли функций new malloc'у в скорости? Если да, то насколько это критично?

new vs malloc - C++
Чем new безопаснее(или лучше?) malloc?

malloc в С++ - C++
Подскажите пожалуйста как в данной программе выделить динамическую память с помощью malloc для объекта #include &lt;iostream&gt; ...

new, malloc, - C++
Добрый день. При роботе с дин. памяттю в конец выделяемой памяти добавляеться какойто бред, чтото топа &quot;&lt;&lt;&lt;ЮЮЮээээ&quot;. Почему так...

malloc() - C++
4to takoe malloc(), za4em nam ono nujno? pomogite=)))))))

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Evg
Эксперт CАвтор FAQ
17537 / 5775 / 370
Регистрация: 30.03.2009
Сообщений: 15,904
Записей в блоге: 26
07.06.2011, 17:06     И снова malloc... #2
Цитата Сообщение от tes Посмотреть сообщение
Потом меня взяли сомнения по поводу выделения памяти
Тебя сомнения одолели правильные и с памятью работа сделана некорректно. В качестве pam ты всюду подаёшь 0. Когда 0 подаётся в malloc, то во многих реализациях номинально выделяется 1 байт. Далее malloc выделяет выровненную память, в слчае i386 она выравнивается на 16 байт (или на 8). Т.е. при вызове malloc(0) у тебя реально выделяется на машине 8 или 16 байт. При этом в стек ты суёшь только по 3 элемента, а потому у тебя ошибка не проявляется

Модифицируй немного свою программу. В main у тебя стеки создаются сначала s1, потом s2. Поменяй их местами. И сделай не по 3 push'а, а по 17. При таком раскладе у меня на твоём коде программа сломалась

Добавлено через 11 секунд
Цитата Сообщение от tes Посмотреть сообщение
Почему УМВР? ЧЯДН?
Цэ шо?

Добавлено через 13 секунд
А... понял
tes
0 / 0 / 0
Регистрация: 19.01.2011
Сообщений: 3
07.06.2011, 21:04  [ТС]     И снова malloc... #3
Цитата Сообщение от Evg Посмотреть сообщение
И сделай не по 3 push'а, а по 17. При таком раскладе у меня на твоём коде программа сломалась
Очень странно программа себя ведёт... Сколько malloc "по умолчанию" выделяет не совсем понятно...

Вот немного переписал программу:
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
#include <cstdlib>
#include <iostream>
 
using namespace std;
 
#define max_size 100
 
class stack{
     char *stck;
     unsigned int tos;
     char who;
public:
     stack (char c, int pam);
     ~stack();
     void push(char ch);
     char pop(); 
};
 
stack::stack(char c, int pam)
{
     tos = 0;
     who = c;
     stck = (char*) malloc(pam);
     cout << pam << endl;
     if (!stck)
     {
          cout << "Ошибка выделения памяти" << endl;
          exit(1);
     }    
}
 
void stack::push(char ch)
{
     if (tos >= max_size){
          cout << "Стек " << who << " полон." << endl;
          return;
     }
 
     stck[tos] = ch;
     ++tos;
}
 
char stack::pop()
{
     if (tos == 0) {
          cout << "Стек " << who << " пуст." << endl;
          return 0x20;
     }
     else
     {
          --tos;
          return  stck[tos];
     };
}
 
stack::~stack()
{
     cout << "Освобождение памяти" << endl;
     free(stck);              
}
 
int main()
{
    stack s1('A',85), s2('B',85), s3('C',85);
    unsigned int i;
    
    cout << "В стек A->>>>" << endl;
    for (i = 0; i < max_size; ++i) s1.push('f');
 
    cout << "В стек B->>>>" << endl;
    for (i = 0; i < max_size; ++i) s2.push('g');    
 
    cout << "В стек C->>>>" << endl;
    for (i = 0; i < max_size; ++i) s3.push('h'); 
    
    cout << "Из стека A->>>>" << endl;
    for (i = 0; i < max_size; ++i) 
    {
        if ((i % 100) != 99)
           if (s1.pop() == 'f') cout << "*";
           else cout << "x";
        else
           if (s1.pop() == 'f') cout << "*" << endl;
           else cout << "x" << endl;
    }
    
    cout << "Из стека B->>>>" << endl;
    for (i = 0; i < max_size; ++i) 
    {
        if ((i % 100) != 99)
           if (s2.pop() == 'g') cout << "*";
           else cout << "x";
        else
           if (s2.pop() == 'g') cout << "*" << endl;
           else cout << "x" << endl;
    }
 
    cout << "Из стека C->>>>" << endl;
    for (i = 0; i < max_size; ++i) 
    {
        if ((i % 100) != 99)
           if (s3.pop() == 'h') cout << "*";
           else cout << "x";
        else
           if (s3.pop() == 'h') cout << "*" << endl;
           else cout << "x" << endl;
    }
    
    cout << endl << endl;
    return EXIT_SUCCESS;
}
Вроде бы она в таком случае ( stack s1('A',85), s2('B',85), s3('C',85) ) должна выделить 16 + 85 или 8 + 85, но нет ведь....

http://www.cyberforum.ru/attachment....1&d=1307466054
Миниатюры
И снова malloc...  
Evg
Эксперт CАвтор FAQ
17537 / 5775 / 370
Регистрация: 30.03.2009
Сообщений: 15,904
Записей в блоге: 26
07.06.2011, 22:57     И снова malloc... #4
Цитата Сообщение от tes Посмотреть сообщение
Сколько malloc "по умолчанию" выделяет не совсем понятно...
Чтобы не думать о том, что там по умолчанию, надо работать правильно и не задумываться о таких вопросах. Т.е. выделять памяти столько, сколько надо, а не в количестве 0 байт.

Цитата Сообщение от tes Посмотреть сообщение
должна выделить 16 + 85 или 8 + 85
Наверное я не так выразился. Память, возвращаемая malloc'ом, всегда должна быть выровнена на 8 байт (или 16, но пусть будет 8). Это означает, что после того, как ты выделил 1 байт, то последующий вызов malloc'а пропустит 7 байт, чтобы следующий адрес был так же кратен 8 байтам. В итоге те 7 байт останутся неиспользоваными. Но при работе с указателем от первого вызова в эти ненужные 7 байт ты можешь нормально обращаться и программа не упадёт (хотя номинально код будет ошибочным). Ну и в таком предположении malloc всегда как бы выделяет количество байт памяти, округлённое до кратности 8 (с округлением в большую сторону). Т.е. если в malloc подать значения от 1 до 8, то всё равно как бы будет выделено 8 байт (выделено будет столько, сколько нужно плюс неиспользуемый хвост). Если подать значение от 9 до 16, то будет выделено 16 байт и т.п.

Всё, что написано выше - я объяснял причину того, почему твой некорректный код работал нормально и не падал. На i386 оно работает так, на другой архитектуре может работать по-другому. Поэтому неправильная работа с динамической памятью опасна тем, что код может работать на одной машине и ломаться на другой

Можешь ещё немного тут почитать: http://www.cyberforum.ru/cpp-experts...ml#post1671703

Что касается твоего кода, то он уже почти правильный. Только в 35 строке надо сравнивать не с max_size, а со значением pam, которое ты подал в конструктор (понятно, что его надо сохранить в экземпляре класса)
Kastaneda
Форумчанин
Эксперт С++
4511 / 2853 / 227
Регистрация: 12.12.2009
Сообщений: 7,249
Записей в блоге: 1
Завершенные тесты: 1
07.06.2011, 23:33     И снова malloc... #5
Цитата Сообщение от Evg Посмотреть сообщение
чтобы следующий адрес был так же кратен 8 байтам
А с чем это связанно? Я читал просто про 2 байта (т.е. чтоб адрес был кратен 2).
Evg
Эксперт CАвтор FAQ
17537 / 5775 / 370
Регистрация: 30.03.2009
Сообщений: 15,904
Записей в блоге: 26
07.06.2011, 23:40     И снова malloc... #6
Цитата Сообщение от Kastaneda Посмотреть сообщение
А с чем это связанно? Я читал просто про 2 байта (т.е. чтоб адрес был кратен 2).
Указатель, возвращаемый malloc'ом должен быть приводим к указателю на любой базовый класс. Другими словами, результат malloc'а должен быть выровнен на максимальное из выравниваний среди базовых типов (по сути на выравнивание long double'а). Это как минимум. На i386 дополнительно есть какие-то магические операции с памятью, которые требуют адреса, выровненного на 8 байт. Если я ничего не напутал

Про 2 байта, которые ты читал - это скорее всего ещё в старых книгах, где ещё DOS'овские соглашения были описаны.
OstapBender
583 / 521 / 35
Регистрация: 22.03.2011
Сообщений: 1,585
07.06.2011, 23:44     И снова malloc... #7
Evg, по-моему malloc(0) это UB и никакие правила тут не действуют...
Evg
Эксперт CАвтор FAQ
17537 / 5775 / 370
Регистрация: 30.03.2009
Сообщений: 15,904
Записей в блоге: 26
07.06.2011, 23:46     И снова malloc... #8
Цитата Сообщение от OstapBender Посмотреть сообщение
Evg, по-моему malloc(0) это UB и никакие правила тут не действуют...
А я что-то другое сказал?

Цитата Сообщение от Evg
Когда 0 подаётся в malloc, то во многих реализациях номинально выделяется 1 байт
ForEveR
В астрале
Эксперт С++
7970 / 4732 / 320
Регистрация: 24.06.2010
Сообщений: 10,541
Завершенные тесты: 3
07.06.2011, 23:46     И снова malloc... #9
malloc с классами? оригинально
Evg
Эксперт CАвтор FAQ
17537 / 5775 / 370
Регистрация: 30.03.2009
Сообщений: 15,904
Записей в блоге: 26
07.06.2011, 23:47     И снова malloc... #10
Цитата Сообщение от ForEveR Посмотреть сообщение
malloc с классами? оригинально
Когда человек учится и сам разбирается - это более чем нормально
OstapBender
583 / 521 / 35
Регистрация: 22.03.2011
Сообщений: 1,585
07.06.2011, 23:51     И снова malloc... #11
Ага, увидел
Evg
Эксперт CАвтор FAQ
17537 / 5775 / 370
Регистрация: 30.03.2009
Сообщений: 15,904
Записей в блоге: 26
08.06.2011, 00:05     И снова malloc... #12
Вот другая реализация malloc'а. Если в вызывать malloc(0), то будет возвращать ZEROSIZEPTR - это вообще получается некая константа, видимо такое значение возвращается из тех соображений, чтобы обращения по такому адресу вызывали слом программы. Там так же есть malloc_minsize - некий минимальный выделяемый кусок. В этой (да и в большинстве других реализаций) получается, что malloc'ать память маленькими кусочками - выходит очень неэффективно, а потому любая мало-мальски серьёзная программа содержит свой менеджер памяти, который строится поверх malloc'а
Kastaneda
08.06.2011, 10:09
  #13

Не по теме:

Цитата Сообщение от Evg Посмотреть сообщение
Указатель, возвращаемый malloc'ом должен быть приводим к указателю на любой базовый класс. Другими словами, результат malloc'а должен быть выровнен на максимальное из выравниваний среди базовых типов (по сути на выравнивание long double'а)
Точно, мог бы сам догаться)
Цитата Сообщение от Evg Посмотреть сообщение
Про 2 байта, которые ты читал - это скорее всего ещё в старых книгах, где ещё DOS'овские соглашения были описаны.
Да, это я когда асм под ДОС осваивал, тогда и читал.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.07.2011, 19:37     И снова malloc...
Еще ссылки по теме:

malloc vs new - C++
Доброго времени суток. Когда я для выделения памяти пользовался malloc/calloc и освобождал с помощью free, у меня вылетала ошибка: ...

new на malloc - C++
Измените выделение памяти на C - malloc,и почему у меня не открывает текстовый файл? #include &quot;stdafx.h&quot; #include &lt;string.h&gt; ...

Ошибка с malloc - C++
Задание: Написать программу, содержащую процедуры формирования и просмотра списка и подпрограмму проверки наличия в списке заданного...

malloc vs. calloc - C++
Когда стоит использовать malloc , а когда calloc?

Функция Malloc - C++
Помогите изучить функцию Malloc что она делает или дайте учебник где она описана! Начальный курс давно закончил, хорошо разбираюсь в...


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

Или воспользуйтесь поиском по форуму:
easybudda
Эксперт CЭксперт С++
9461 / 5474 / 927
Регистрация: 25.07.2009
Сообщений: 10,498
15.07.2011, 19:37     И снова malloc... #14
Цитата Сообщение от Evg Посмотреть сообщение
Когда 0 подаётся в malloc, то во многих реализациях номинально выделяется 1 байт. Далее malloc выделяет выровненную память, в слчае i386 она выравнивается на 16 байт (или на 8). Т.е. при вызове malloc(0) у тебя реально выделяется на машине 8 или 16 байт.
Интересно стало...
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
 
int main(void){
    char * p;
    
    if ( ! ( p = malloc(0) ) ){
        fprintf(stderr, "Nicht gemacht, kaput!\n");
        exit(1);
    }
    
    printf("p has %d bytes allocated.\n", malloc_usable_size(p));
    
    free(p);
    exit(0);
}
Код
andrew@debnout:~/cpp/system$ gcc -o p0 p0.c 
andrew@debnout:~/cpp/system$ ./p0
p has 12 bytes allocated.
andrew@debnout:~/cpp/system$
Yandex
Объявления
15.07.2011, 19:37     И снова malloc...
Ответ Создать тему
Опции темы

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