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

Как происходит процесс выделения памяти в стеке и куче - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 4.94
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 14:46     Как происходит процесс выделения памяти в стеке и куче #1
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
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include "disc.h"
void main()
{
  SetConsoleCP(1251);
  SetConsoleOutputCP(1251);
  
  Disc d1,d2[2];
  Disc *d3,*d4;
  d3=new Disc;
  int kol=0,n;
  clrscr();
  kol++;
  printf("%i)",kol);
  printf("\nВведите название дисциплины -> ");
  gets(d1.namedisc);
  printf("Введите имя перподавателя -> ");
  gets(d1.teacher_name);
  printf("Введите название группы -> ");
  gets(d1.name_group);
  printf("Введите кол-во часов на изуч. дисциплины-> ");
  scanf("%i",&d1.hours);
  fflush(stdin);
  
  for (int i=0; i<1; i++)
  {
    clrscr();
    kol++;
    printf("%i)",kol);
    printf("\nВведите название дисциплины -> ");
    gets(d2[i].namedisc);
    printf("Введите имя перподавателя -> ");
    gets(d2[i].teacher_name);
    printf("Введите название группы -> ");
    gets(d2[i].name_group);
    printf("Введите кол-во часов на изуч. дисциплины-> ");
    scanf("%i",&d2[i].hours);
    fflush(stdin);
  }
 
  clrscr();
  kol++;
  printf("%i)",kol);
  printf("\nВведите название дисциплины -> ");
  gets(d3->namedisc);
  printf("Введите имя перподавателя -> ");
  gets(d3->teacher_name);
  printf("Введите название группы -> ");
  gets(d3->name_group);
  printf("Введите кол-во часов на изуч. дисциплины-> ");
  scanf("%i",&d3->hours);
  fflush(stdin);
 
  printf ("\n Введите кол-во записей-> ");
  scanf ("%i",&n);
  d4=new Disc [n];
  fflush(stdin);
  for (int i=0; i<n; i++)
  {
    clrscr();
    kol++;
    printf("%i)",kol);
    printf("\nВведите название дисциплины -> ");
    gets(d4[i].namedisc);
    printf("Введите имя перподавателя -> ");
    gets(d4[i].teacher_name);
    printf("Введите название группы -> ");
    gets(d4[i].name_group);
    printf("Введите кол-во часов на изуч. дисциплины-> ");
    scanf("%i",&d4[i].hours);
    fflush(stdin);
  }
  clrscr();
  kol=0;
  printf("\n------------------------------------------------------------");
  printf("\n|№|Название дисциплины |Имя преподавателя   |Имя группы|Час|");
  printf("\n------------------------------------------------------------");
  kol++;
  printf("\n|%1i|%20s|%20s|%10s|%3i|",kol,d1.namedisc,d1.teacher_name,d1.name_group,d1.hours);
  for (int i=0; i<1; i++)
    printf("\n|%1i|%20s|%20s|%10s|%3i|",kol+i+1,d2[i].namedisc,d2[i].teacher_name,d2[i].name_group,d2[i].hours);
  kol+=3;
   printf("\n|%1i|%20s|%20s|%10s|%3i|",kol,d3->namedisc,d3->teacher_name,d3->name_group,d3->hours);
  for (int i=0; i<n; i++)
    printf("\n|%1i|%20s|%20s|%10s|%3i|",kol+i+1,d4[i].namedisc,d4[i].teacher_name,d4[i].name_group,d4[i].hours);
  kol+=2;  
  printf("\n------------------------------------------------------------");
  getch();
  delete d3;
  delete []d4;
}
C++
1
2
3
4
5
6
7
8
class Disc
{
  public:
  char namedisc[20];
  char teacher_name[20];
  char name_group[10];
  int hours;
};
Тут я просто вывожу в табличке свой класс, просто 4 способами, через переменную, массив, указатель и дин.массив. Вопрос вот выделении памяти под объекты класса (d1,d2[i],*d3,*d4);
писал sizeof для каждого объекта и получил что
d1=56 байта (тут вроде 3 chara 20+20+10+ 1 int=4 байтам=54 байта, куда выделяются еще 2 байта?)
d2=112 байта (ну тут понятно, что записей в массиве 2, 56+56=112)
d3=4 байта (тут 4 байта при записи sizeof(d3)-т.е. на каждое поле класса, их всего 4 выделяется по 1 байту?)
(а если написать sizeof(*d3) то будет снова 56 байт
d4=4 байта (тут аналогично)
Объясните пожалуйста, как происходит процесс выделения памяти в стеке и куче, ну и про кол-во байтов на объекты класса.
Все это делаю в C++ Builder 6
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
16.01.2014, 14:46     Как происходит процесс выделения памяти в стеке и куче
Посмотрите здесь:

Потоки и выделение памяти в куче C++
C++ Расположение данных в стеке и в куче
Нужно перевести из С++ в C строку с выделением памяти в куче C++
C++ Указатели (Выделение памяти в куче)
C++ Не могу понять где объект в куче или в стеке !
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kventin_zhuk
БНТУ ФИТР
 Аватар для kventin_zhuk
214 / 154 / 15
Регистрация: 26.12.2012
Сообщений: 382
16.01.2014, 14:55     Как происходит процесс выделения памяти в стеке и куче #2
Lers, В стеке память выделяется сама когда вы объявляете локальную переменнную. Когда проиходит выход за блок, в котором она объявлена, память сама освобождается.

В куче же вы сами намеренно выделяете память(операторы new delete). Следовательно и контроль за освобождением памяти лежит на вас.

d1 действительно будет весить 56 байт. В компиляторе задается размер выравнивания. кратно скольки байтам должен быть размер. В вашем случае наверное выравнивание по 4 байта.

d3 и d4 весят 4 байта. Это размер указателя.
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 15:03  [ТС]     Как происходит процесс выделения памяти в стеке и куче #3
т.е. в стеке нету упоминаний про d3 и d4?
Можно подробнее что за размер выравнивания и почему в моем случае 4 байта, а не 2 байта, т.к. 3 chara 20+20+10+ 1 int=4 байтам=54 байта?
kventin_zhuk
БНТУ ФИТР
 Аватар для kventin_zhuk
214 / 154 / 15
Регистрация: 26.12.2012
Сообщений: 382
16.01.2014, 15:10     Как происходит процесс выделения памяти в стеке и куче #4
Lers, сами указатели которые, d3 и d4 объявлены в стеке. Но вот память, которую вы будете выделять с помощью их будет в куче.

http://msdn.microsoft.com/ru-ru/library/xh3e3fd0.aspx

Здесь можно почитать про выравнивание и узнать как его изменить
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 15:14  [ТС]     Как происходит процесс выделения памяти в стеке и куче #5
3 chara 20+20+10+ 1 int=4 байтам=54 байта и +2 байта на выравнивание, я правильно понял?

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


т.е. в стеке лежит адреса данных на которые ссылается указатель, а в куче лежат сами данные?)
P.S. сорр за кучу вопросов)
kventin_zhuk
БНТУ ФИТР
 Аватар для kventin_zhuk
214 / 154 / 15
Регистрация: 26.12.2012
Сообщений: 382
16.01.2014, 15:21     Как происходит процесс выделения памяти в стеке и куче #6
Lers, Да. По ссылке выше - вы можете поменять параметр на 1 байт. И будет ровно 54. Но эта штука очень интересно работает. Я например ставлю выравнивание больше чем нужно - напрмер по 16 байт. А компилятор все равно диктует свой меньший размер. А в меньшую сторону работает Видимо так ему хочется

Да - сам указатель будет в стеке и будет содержать адрес блока памяти в куче.
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 15:26  [ТС]     Как происходит процесс выделения памяти в стеке и куче #7
Спасибо.
Еще вопрос)))
При вводе через указатель d3 допустим этого поля
C++
1
gets(d3->namedisc);
можно поменять на
C++
1
gets((*d3).namedisc);
Как это работает? Т.е. так стрелку заменили на точку, то обращаемся мы к полям класса, статически, и (*d3) это данные указателя d3, которые хранятся в куче, а звездочка нужна т.к. нам нужны данные в куче, а не их адреса?
Аналогично
C++
1
gets(d1.namedisc);
C++
1
gets((&d1)->namedisc);
Тут не могу объяснить почему так)
kventin_zhuk
БНТУ ФИТР
 Аватар для kventin_zhuk
214 / 154 / 15
Регистрация: 26.12.2012
Сообщений: 382
16.01.2014, 15:42     Как происходит процесс выделения памяти в стеке и куче #8
Lers, Стрелка - доступ к полю или методу структуры/класса черз указатель. Указатель это адрес. Придумана она исколючительно для того чтобы сделать код красивее. Согласитесь, что о красоте первой и второй записи спорить не стоит. Точка работает с сконструированным объектом, а указатель содержит всего-навсего адрес. => прежде чем использовать точку нужно разыменовать указатель

C++
1
(*d3).namedisc;
Скобки здесь потому что приоритет точки выше чем у разыменования. Приоритет операций можно посмотреть здесь:
http://ru.cppreference.com/w/cpp/lan...tor_precedence

C++
1
(&d1)->namedisc;
d1 располагается в стеке - но здесь мы используем ->. Чтобы использовать выбор элемента по адресу нам слева нужен адрес, вот мы и получаем адрес объекта операцией взятия адреса (&). С приоритетом аналогично.

Добавлено через 2 минуты
Вывод, к которому я вел все это время:

-> и . не означает что первый объект должен располагаться в куче а второй в стеке.
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 15:46  [ТС]     Как происходит процесс выделения памяти в стеке и куче #9
Попробую подвести итог, поправьте если не правильно понял.
C++
1
(*d3).namedisc;
т.к. изначально была стрелка и d3 использовался как указатель на адрес данных в куче, при замене стрелки на точку, работа с указателем не доступна т.к. обращаемся в стек, и звездочка нужна для разыменование указателя, т.к. нам нужны значения данных из стека.
Про приоритеты понятно.
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,057
16.01.2014, 15:56     Как происходит процесс выделения памяти в стеке и куче #10
Lers,
Не забивай пока себе голову
просто запомни что локальные переменные располагаются в одном месте (чаще всего это стек, но не факт, есть безстековые процессоры)
выделение памяти в другом месте( куча)
глобальные и статические переменные в третьем
если хочешь со всем этим серьезно разбираться нужно опускаться до уровня ассемблера и архитектуры процессора
вот похожая тема
Что почитать про распределение памяти?
тебе пока нужно разобраться с указателями( и со ссылками) а это не зависит где лежит переменная
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
16.01.2014, 16:17     Как происходит процесс выделения памяти в стеке и куче #11
Цитата Сообщение от Lers Посмотреть сообщение
т.к. изначально была стрелка и d3 использовался как указатель на адрес данных в куче, при замене стрелки на точку, работа с указателем не доступна т.к. обращаемся в стек, и звездочка нужна для разыменование указателя, т.к. нам нужны значения данных из стека.
Указатель - это переменная, в которой содержится адрес. Этот адрес может быть любым (стековым, кучи, статической памяти). Чтобы получить доступ к полю объекта через указатель на него (или через адрес объекта), используют -> (d3 ->namedisc, (&d1) ->namedisc), чтобы получить доступ к полю объекта через сам объект, используют точку (d1.namedisc). Чтобы получить объект через указатель на объект, используют операцию разыменования * : ((*d3).namedisc, т.е., разыменовали указатель - получили объект, потом через точку получили доступ к полю объекта)
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
16.01.2014, 16:18     Как происходит процесс выделения памяти в стеке и куче #12
Цитата Сообщение от Lers Посмотреть сообщение
т.к. изначально была стрелка и d3 использовался как указатель на адрес данных в куче, при замене стрелки на точку, работа с указателем не доступна т.к. обращаемся в стек, и звездочка нужна для разыменование указателя, т.к. нам нужны значения данных из стека.
неправильно поняли, ознакомьтесь теперь ещё с понятием "ссылка"
ValeryS
Модератор
6377 / 4843 / 442
Регистрация: 14.02.2011
Сообщений: 16,057
16.01.2014, 16:28     Как происходит процесс выделения памяти в стеке и куче #13
тут еще нужно отметить что слово "стек" в Си используется в двух понятиях
1 Стек как организация данных "Последний пришел-первый ушел"
2 стек место где лежат локальные переменные, называется так видимо из за того что данные лежат в области памяти выделенной процессором под стек программы и обращение к ним идет из регистра ESI(80x86)
оба эти понятия ничего общего друг с другом не имеют
и может правильно называть не "стековые переменные" а "автоматические переменные " которые лежат в "автоматической памяти"
По крайней мере я такие термины встречал в переводной литературе
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 17:10  [ТС]     Как происходит процесс выделения памяти в стеке и куче #14
Спасибо всем за пояснения, буду переваривать

Добавлено через 9 минут
Цитата Сообщение от alsav22 Посмотреть сообщение
Указатель - это переменная, в которой содержится адрес. Этот адрес может быть любым (стековым, кучи, статической памяти). Чтобы получить доступ к полю объекта через указатель на него (или через адрес объекта), используют -> (d3 ->namedisc, (&d1) ->namedisc), чтобы получить доступ к полю объекта через сам объект, используют точку (d1.namedisc). Чтобы получить объект через указатель на объект, используют операцию разыменования * : ((*d3).namedisc, т.е., разыменовали указатель - получили объект, потом через точку получили доступ к полю объекта)
правильно ли я понял, когда я использую d1.namedisc то я обращаюсь к полю через объект, а когда меняю на (&d1->namedisc) то обращаюсь к полю через адрес объекта?
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
16.01.2014, 17:20     Как происходит процесс выделения памяти в стеке и куче #15
Цитата Сообщение от Lers Посмотреть сообщение
правильно ли я понял, когда я использую d1.namedisc то я обращаюсь к полю через объект, а когда меняю на (&d1->namedisc) то обращаюсь к полю через адрес объекта?
Правильно, но только так:
C++
1
(&d1) ->namedisc;
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 18:20  [ТС]     Как происходит процесс выделения памяти в стеке и куче #16
Еще вопрос возник, в моем варианте программы, в стеке хранятся данные объекты d1,d2 и адреса на объекта указателей *d3, *d4.
В куче храниться только данные объектов d3,d4 или чего еще?
Где хранятся адреса объектов d1,d2? Тоже в стеке?
т.е. когда вот такая запись gets((&d1)->namedisc); то я обращаюсь в стек за адресом объекта
а когда такая (*d3).namedisc; то я обращаюсь в кучу за объектом?

P.S. извиняюсь за неугомонность
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
16.01.2014, 18:54     Как происходит процесс выделения памяти в стеке и куче #17
Цитата Сообщение от Lers Посмотреть сообщение
Где хранятся адреса объектов d1,d2? Тоже в стеке?
Нигде. При определении переменной под неё выделяется память, адрес которой связан с именем данной переменной (именованная область памяти). Для локальных переменных d1, d2, d3(указатель), d4(указатель) память выделяется на стеке, на этапе компиляции, и адреса этой памяти связаны с именами этих переменных. Чтобы получиь эти адреса, нужно применить к именам переменных операцию взятия адреса: &. В динамческой памяти, память под переменные выделяется неименованная (выделяется в процессе работы программы). Поэтому доступ к таким переменным возможен только через адреса (указатели).
Цитата Сообщение от Lers Посмотреть сообщение
т.е. когда вот такая запись gets((&d1)->namedisc); то я обращаюсь в стек за адресом объекта
Обращаетесь к полю объекта, через его адрес на стеке.
Цитата Сообщение от Lers Посмотреть сообщение
а когда такая (*d3).namedisc; то я обращаюсь в кучу за объектом?
Обращаетесь к полю объекта, через объект, получаемый разыменованием указателя на объект.
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 19:04  [ТС]     Как происходит процесс выделения памяти в стеке и куче #18
alsav22, (*d3).namedisc; Обращаюсь к полю объекта, через объект, получаемый разыменованием указателя на объект, это я понял, а обращаюсь я же в стек?
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
16.01.2014, 19:21     Как происходит процесс выделения памяти в стеке и куче #19
Цитата Сообщение от Lers Посмотреть сообщение
В куче храниться только данные объектов d3,d4 или чего еще?
Нельзя сказать, что в куче хранятся объекты d3, d4, т.к. объекты в куче неименованные. В указателях d3, d4 хранятся адреса объектов в куче.

Добавлено через 9 минут
Цитата Сообщение от Lers Посмотреть сообщение
(*d3).namedisc; Обращаюсь к полю объекта, через объект, получаемый разыменованием указателя на объект, это я понял, а обращаюсь я же в стек?
Чтобы получить адрес объекта, да (указатель же на стеке создан). А для получения поля объекта - обращаетесь в кучу (там же сам неименовынный объект находится, по адресу, взятому из указателя). Вообще, как не пиши, просто имя объекта или указатель на объект, всё, в конечном счёте, сводится к адресам. В одних случаях имя объекта - адрес, в других случаях значение указателя адрес. Вот такая запись: (*d3).namedisc - некое извращение. В результате всё равно будет получен адрес в куче. Если уж d3 указатель, то нужно использовать синтаксис указателя: d3 ->namedisc, чтобы не было лишней путаницы.

Добавлено через 7 минут
Вот это тоже - некое извращение:
C++
1
(&d1) ->namedisc;
Адрес берётся только для того, чтобы обратиться к полю через оператор косвенной адресации.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.01.2014, 19:32     Как происходит процесс выделения памяти в стеке и куче
Еще ссылки по теме:

Динамическое выделение памяти. Ошибки в куче C++
C++ Как выделяется память на стеке и на куче? Когда нужна ручная очистка?
Как написать программу для динамического выделения памяти с использованием new C++

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

Или воспользуйтесь поиском по форуму:
Lers
12 / 12 / 3
Регистрация: 27.05.2012
Сообщений: 202
16.01.2014, 19:32  [ТС]     Как происходит процесс выделения памяти в стеке и куче #20
alsav22, это не моя прихоть так извращаться
Спасибо большое за помощь!
Yandex
Объявления
16.01.2014, 19:32     Как происходит процесс выделения памяти в стеке и куче
Ответ Создать тему
Опции темы

Текущее время: 00:58. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru