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

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

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

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

07.06.2011, 16:33. Просмотров 1688. Ответов 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);, у меня всё проходит нормально? Почему УМВР? ЧЯДН? Может кто нибудь прояснить ситуацию?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.06.2011, 16:33
Здравствуйте! Я подобрал для вас темы с ответами на вопрос И снова malloc... (C++):

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

Как сделать чтобы таймер дойдя до 0 стартовал снова и снова? - C++
Здравствуйте :) Как сделать чтобы таймер дойдя до 0 стартовал снова и снова? TimerSec = 59; TimerMin = 6; for(int i = TimerSec;...

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

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

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

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

13
Evg
Эксперт CАвтор FAQ
17936 / 6164 / 409
Регистрация: 30.03.2009
Сообщений: 16,925
Записей в блоге: 27
07.06.2011, 17:06 #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 секунд
А... понял
2
tes
0 / 0 / 0
Регистрация: 19.01.2011
Сообщений: 3
07.06.2011, 21:04  [ТС] #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
0
Миниатюры
И снова malloc...  
Evg
Эксперт CАвтор FAQ
17936 / 6164 / 409
Регистрация: 30.03.2009
Сообщений: 16,925
Записей в блоге: 27
07.06.2011, 22:57 #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, которое ты подал в конструктор (понятно, что его надо сохранить в экземпляре класса)
2
Kastaneda
Форумчанин
Эксперт С++
4655 / 2863 / 228
Регистрация: 12.12.2009
Сообщений: 7,274
Записей в блоге: 2
Завершенные тесты: 1
07.06.2011, 23:33 #5
Цитата Сообщение от Evg Посмотреть сообщение
чтобы следующий адрес был так же кратен 8 байтам
А с чем это связанно? Я читал просто про 2 байта (т.е. чтоб адрес был кратен 2).
0
Evg
Эксперт CАвтор FAQ
17936 / 6164 / 409
Регистрация: 30.03.2009
Сообщений: 16,925
Записей в блоге: 27
07.06.2011, 23:40 #6
Цитата Сообщение от Kastaneda Посмотреть сообщение
А с чем это связанно? Я читал просто про 2 байта (т.е. чтоб адрес был кратен 2).
Указатель, возвращаемый malloc'ом должен быть приводим к указателю на любой базовый класс. Другими словами, результат malloc'а должен быть выровнен на максимальное из выравниваний среди базовых типов (по сути на выравнивание long double'а). Это как минимум. На i386 дополнительно есть какие-то магические операции с памятью, которые требуют адреса, выровненного на 8 байт. Если я ничего не напутал

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

Цитата Сообщение от Evg
Когда 0 подаётся в malloc, то во многих реализациях номинально выделяется 1 байт
0
ForEveR
В астрале
Эксперт С++
7978 / 4737 / 321
Регистрация: 24.06.2010
Сообщений: 10,543
Завершенные тесты: 3
07.06.2011, 23:46 #9
malloc с классами? оригинально
0
Evg
Эксперт CАвтор FAQ
17936 / 6164 / 409
Регистрация: 30.03.2009
Сообщений: 16,925
Записей в блоге: 27
07.06.2011, 23:47 #10
Цитата Сообщение от ForEveR Посмотреть сообщение
malloc с классами? оригинально
Когда человек учится и сам разбирается - это более чем нормально
0
OstapBender
583 / 522 / 35
Регистрация: 22.03.2011
Сообщений: 1,585
07.06.2011, 23:51 #11
Ага, увидел
0
Evg
Эксперт CАвтор FAQ
17936 / 6164 / 409
Регистрация: 30.03.2009
Сообщений: 16,925
Записей в блоге: 27
08.06.2011, 00:05 #12
Вот другая реализация malloc'а. Если в вызывать malloc(0), то будет возвращать ZEROSIZEPTR - это вообще получается некая константа, видимо такое значение возвращается из тех соображений, чтобы обращения по такому адресу вызывали слом программы. Там так же есть malloc_minsize - некий минимальный выделяемый кусок. В этой (да и в большинстве других реализаций) получается, что malloc'ать память маленькими кусочками - выходит очень неэффективно, а потому любая мало-мальски серьёзная программа содержит свой менеджер памяти, который строится поверх malloc'а
1
Kastaneda
08.06.2011, 10:09
  #13

Не по теме:

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

0
easybudda
Модератор
Эксперт CЭксперт С++
9663 / 5613 / 952
Регистрация: 25.07.2009
Сообщений: 10,776
15.07.2011, 19:37 #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$
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.07.2011, 19:37
Привет! Вот еще темы с ответами:

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
14
Yandex
Объявления
15.07.2011, 19:37
Ответ Создать тему
Опции темы

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