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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 36, средняя оценка - 4.69
The_Immortal
1552 / 488 / 8
Регистрация: 04.04.2009
Сообщений: 1,891
#1

Понимание адреса, ссылки и указателя - C++

30.05.2012, 11:31. Просмотров 5018. Ответов 103
Метки нет (Все метки)

Гм... Конечно, стремно создавать подобную тему, однако, уж очень захотелось понять все это дело. Правда сколько раз ни пытался - не удавалось ни разу, возможно, потому что пытался разобраться самостоятельно (хотя, наверное, многие это постигают именно так). Но вот моя очередная попытка, которую решил так сказать обнародовать Поэтому очень рассчитываю на вашу помощь и поддержку.

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

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
// расположение переменных в памяти
#include <cstdio.h>
#include <cstlib.h>
#include <iostream.h>
 
using namespace std;
 
int main(int intArgc, char* pszArgs[])
{
int end;
int n;
long l;
float f;
double d;
 
// Вывод в шестнадцатеричном виде
cout.setf (ios::hex);
cout.unsetf (ios::hex);
 
// выводить адреса переменных
// по очереди, чтобы показать размер
// каждой переменной
cout << "--- = " << &end << "\n";
cout << "&n = " << &n << "\n";
cout << "&l = " << &l << "\n";
cout << "&f = " << &f << "\n";
cout << "&d = " << &d << "\n";
 
system ("PAUSE");
return 0;
}
Результат:

C++
1
2
3
4
5
--- = 0x22ff6c
&n  = 0x22ff68
&l  = 0x22ff64
&f  = 0x22ff60
&d  = 0x22ff58
А теперь цитата из книги:
Обратите внимание на то, что переменная n располагается ровно в 4 байтах от переменной end (---). Переменная l располагается еще на 4 байта ниже, а переменная типа double занимает 8 байт. Для каждой переменной выделяется память, необходимая для ее типа.
Для каждой переменной выделяется память, необходимая для ее типа.
Это мне известно. Но вот что меня занесло в тупик:

Разница, скажем, между 0x22ff6c и 0x22ff68 действительно 4. Но 4 чего - байта? А разве 4 в десятичной системе не 4? А в двоичной это разве не 100? Откуда тут 4 байта? Я понимаю, что там должно быть 4 байта, но не получается осознать, что 1 hex-единица у нас вдруг байт. Или это не так?

В общем, на таком банальном я запутался

Спасайте...
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.05.2012, 11:31
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Понимание адреса, ссылки и указателя (C++):

Изменение адреса указателя - C++
Здравствуйте. Обращаюсь к форуму по следующему вопросу: как можно изменить значение указателя? То есть, есть следующий код: ...

Динамическое указание адреса указателя - C++
мне нужно сделать int * a=(int*)0x123ff; cout&lt;&lt;a; динамически. Кто нибудь знает как это сделать?

Использование ссылки и указателя - C++
Доброго времени суток! Возник такой вопрос, есть код: #include &lt;iostream&gt; #include &lt;cmath&gt; using namespace std; int main() ...

Получение адреса объекта после обнуления указателя на этот объект - C++
Добрый вечер уважаемые программисты. Интересует следующий вопрос. Есть ли способ получить адрес объекта, после того, как указатель на него...

Передача ссылки и указателя в функцию - C++
передал ссылку в одну функцию - нормально, передал в другую - выводит неверное значение, тоже самое с указателем. Как можно это исправить?

Возвращение ссылки или указателя на закрытый элемент класса. - C++
Всех уважаемых форуман. поздравляю с наступившим новым годом и прошу ответить на такой вопрос. Почему до сих пор современный C++ не...

103
dimcoder
Полярный
466 / 439 / 68
Регистрация: 11.09.2011
Сообщений: 1,138
30.05.2012, 12:01 #2
Цитата Сообщение от The_Immortal Посмотреть сообщение
Но 4 чего - байта?
Да.
Может так нагляднее будет:
--- = 0x22ff6c = 2 293 612
&n = 0x22ff68 = 2 293 608
&l = 0x22ff64 = 2 293 604
&f = 0x22ff60 = 2 293 600
&d = 0x22ff58 = 2 293 592
Вот вам и разница байтов.
2
The_Immortal
1552 / 488 / 8
Регистрация: 04.04.2009
Сообщений: 1,891
30.05.2012, 12:48  [ТС] #3
dimcoder,

Цитата Сообщение от dimcoder Посмотреть сообщение
2 293 612
Это байты?

В смысле 1 (Dec) = 1 байт?
0
dimcoder
Полярный
466 / 439 / 68
Регистрация: 11.09.2011
Сообщений: 1,138
31.05.2012, 08:37 #4
Цитата Сообщение от The_Immortal Посмотреть сообщение
Это байты?
Да, байты.
1
zss
Модератор
Эксперт С++
6578 / 6140 / 2022
Регистрация: 18.12.2011
Сообщений: 15,997
Завершенные тесты: 1
31.05.2012, 11:00 #5
В теме обсуждается понятие адреса переменной.
А в заголовке еще анонсирована ссылка и указатель.
Вопрос: зачем?

Кстати, сколько байт занимает переменная можно определить с помощью
sizeof(тип):
C++
1
2
int si=sizeof(int);
int sd=sizeof(double);
2
Deviaphan
Делаю внезапно и красиво
Эксперт С++
1306 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
31.05.2012, 11:05 #6
Цитата Сообщение от The_Immortal Посмотреть сообщение
Обратите внимание на то, что переменная n располагается ровно в 4 байтах от переменной en
А вот этим строкам лучше не верь. В зависимости от параметров компиляции, может быть изменено не только выравнивание, но и порядок переменных.

Объёмы данных измеряются в байтах и их производных (КБ, МБ, ГБ...), про биты забудь. Биты используются только при передаче данных через сеть. На локальной машине битов нет. Даже используя битовые операции, ты работаешь с байтами.

Вместо &end напиши ((unsigned)&end) и адрес выведется в десятичной системе, чтобы вопросов у тебя не возникало лишних.
2
The_Immortal
1552 / 488 / 8
Регистрация: 04.04.2009
Сообщений: 1,891
31.05.2012, 11:17  [ТС] #7
zss, адрес - неотъемлемая часть указателя и ссылки Но я до них еще дойду, т.к. с этим у меня вообще полная каша.

Ребят, а подскажите, пожалуйста, почему

1) Объявляем переменные в таком порядке:

C++
1
2
3
4
5
int end;
int n;
long l;
float f;
double d;
Компилятор идет сверху-вниз.

А адреса назначаются в обратном:

C++
1
2
3
4
5
--- = 0x22ff6c = 2 293 612
&n  = 0x22ff68 = 2 293 608
&l  = 0x22ff64 = 2 293 604
&f  = 0x22ff60 = 2 293 600
&d  = 0x22ff58 = 2 293 592
Т.е. сначала был присвоен адрес переменной d (... 592), потом f (... 600) и т.д.

2) 0x22ff - это какой-то магический префикс? Почему адрес объявленных переменных всегда (ну может не всегда, но зачастую) начинается именно с него?

Добавлено через 8 минут
Цитата Сообщение от Deviaphan Посмотреть сообщение
Биты используются только при передаче данных через сеть.
Хм... Запомню, спасибо. Просто я всегда считал, что и на локальной машине атомной структурой являются биты.
0
Toshkarik
1147 / 864 / 51
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
31.05.2012, 11:23 #8
Deviaphan просто имел ввиду не физическое наличие, а реальное использование, то есть по сути процессор работает с машинным словом, а не с каждым битом в отдельности. По поводу адресов - Вам так же уже сказали, что зависит от реализации компилятора, и что переменные не обязаны идти в каком то порядке и вообще находится рядом.
1
zss
Модератор
Эксперт С++
6578 / 6140 / 2022
Регистрация: 18.12.2011
Сообщений: 15,997
Завершенные тесты: 1
31.05.2012, 11:28 #9
Цитата Сообщение от The_Immortal Посмотреть сообщение
А адреса назначаются в обратном:
Потому, что локальные переменные заводятся в стеке.
1
The_Immortal
1552 / 488 / 8
Регистрация: 04.04.2009
Сообщений: 1,891
31.05.2012, 11:35  [ТС] #10
Toshkarik,

Цитата Сообщение от Deviaphan Посмотреть сообщение
В зависимости от параметров компиляции, может быть изменено не только выравнивание, но и порядок переменных.
Цитата Сообщение от Toshkarik Посмотреть сообщение
зависит от реализации компилятора, и что переменные не обязаны идти в каком то порядке и вообще находится радом.
Да, ребят, это я понял.
Также в книге об этом написано:

Стандарт C++ не требует от компилятора последовательного "беспросветного" размещения переменных в памяти. Dev-C++ может разместить переменные в памяти и по-другому.
Но мой Dev-C++ их разместил аналогичным образом:

C++
1
2
3
4
5
--- = 2293620
&n  = 2293616
&l  = 2293612
&f  = 2293608
&d  = 2293600
Я не пытаюсь с вами спорить и утверждать, что на всех Dev-C++ всегда будет такое "беспросветное" размещение переменных.
Просто хочу понять каким образом (в данном локальном случае) действует компилятор. Почему объявление переменных происходит сверху-вниз, а размещение этих переменных снизу вверх?

Разве при объявлении переменной не происходит моментального размещения этой переменной в памяти ну и соответствующего присвоения адреса?

Добавлено через 2 минуты
Цитата Сообщение от zss Посмотреть сообщение
Потому, что локальные переменные заводятся в стеке.
Отлично... В книге почему-то об этом не пишут =/

Пойду гуглить по этому поводу
0
Deviaphan
Делаю внезапно и красиво
Эксперт С++
1306 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
31.05.2012, 11:41 #11
Цитата Сообщение от The_Immortal Посмотреть сообщение
А адреса назначаются в обратном
Потому что память в стеке используется начиная с верхних адресов.
0
Toshkarik
1147 / 864 / 51
Регистрация: 03.08.2011
Сообщений: 2,404
Завершенные тесты: 1
31.05.2012, 11:41 #12
Вы можете забегать вперед, так как вопрос о классах памяти может обсуждаться дальше в книги.
0
Лжец
31 / 31 / 3
Регистрация: 13.12.2011
Сообщений: 106
31.05.2012, 11:49 #13
0x22ff - это какой-то магический префикс? Почему адрес объявленных переменных всегда (ну может не всегда, но зачастую) начинается именно с него?
22ff - это уже адрес. Префикс, если можно так сказать, это 0x (или 0Х) - он означает, что данное число (адрес) выведено в 16-ричной системе счисления. Своего рода подсказка.

Почему объявление переменных происходит сверху-вниз, а размещение этих переменных снизу вверх?
Тебе же уже ответили, данные помещаются в стек. "И последний станет первым".

Разве при объявлении переменной не происходит моментального размещения этой переменной в памяти?
Она помещается на вершину стека, после чего по мере объявления и добавления других переменных в стек, она "смещается" вниз по стеку. Если слово "смещается" смущает (потому что никакого "смещения" не происходит), есть стандартный пример для понимания, это "стопка тарелок": когда ты ее складываешь, то кладешь одну тарелку на другую - примерно так же происходит и в стеке.
1
The_Immortal
1552 / 488 / 8
Регистрация: 04.04.2009
Сообщений: 1,891
31.05.2012, 12:04  [ТС] #14
Toshkarik,

Цитата Сообщение от Toshkarik Посмотреть сообщение
Вы можете забегать вперед, так как вопрос о классах памяти может обсуждаться дальше в книги.
Возможно. Но я пробежался по книге и ничего такого не нашел Правда, наверное, книга моя - "C++ для чайников" вряд ли предусматривает рассмотрение подобных вопросов .


Лжец,

Цитата Сообщение от Лжец Посмотреть сообщение
22ff - это уже адрес
Под "префиксом" я имел как раз-таки начало этого адреса. Про "0x" я в курсе. Интересует почему объявление начинается с "22ff"? Это также зависит от компилятора? Если не трудно, кто-нибудь мог бы выложить какие адреса назначаются локальным переменным такого же типа как у меня в начальном примере (кто НЕ юзает Dev-C++).



Deviaphan,

Цитата Сообщение от Deviaphan Посмотреть сообщение
Потому что память в стеке используется начиная с верхних адресов.
Лжец,

Цитата Сообщение от Лжец Посмотреть сообщение
Она помещается на вершину стека, после чего по мере объявления и добавления других переменных в стек, она "смещается" вниз по стеку.

Мм.. Кажется начинаю понимать. После объявлении переменных в стеке вот такая картина:

d
f
l
n
end
Ну и присвоение адресов происходит сверху-вниз. Таким образом d получает адрес: (... i), f получает адрес: (... i+8) и т.д. // в моем "беспросветном" случае

Я правильно понял?
0
Deviaphan
Делаю внезапно и красиво
Эксперт С++
1306 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
31.05.2012, 12:14 #15
Цитата Сообщение от The_Immortal Посмотреть сообщение
Интересует почему объявление начинается с "22ff"?
Просто совпадение. Хотя и есть "предпочтительные" адреса для загрузки модулей, но не стоит об этом думать. Это просто совпадение.)


Цитата Сообщение от The_Immortal Посмотреть сообщение
d получает адрес: (... i), f получает адрес: (... i+8) и т.д.
d помещается по адресу: вершина стека минус sizeof(d). Этот адрес становится новой вершиной
f помещается по адресу: вершина стека - sizeof(f). Этот адрес становится новой вершиной стека.

Здесь под стеком нужно понимать не контейнер, а тупо выделенный блок памяти. Никаких итераторов и операций нету. Т.е. это не std::stack, а системный стек. Всё, что он собой представляет, это указатель на вершину стека.
1
31.05.2012, 12:14
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
31.05.2012, 12:14
Привет! Вот еще темы с ответами:

Ссылки и адреса - C++
Вот, где лучше всего использовать адреса и ссылки? Просто не много не понятня для чего это все. Вот например эту запись int mas; int*...

Адресное пространство, адреса, ссылки - C++
Добрый вечер. Я новичок в программировании и стал недавно читать туториалы по ссылкам. В общем, прилагаю цитату с одного сайта: ...

Как снять константность ссылки для передачи в функцию адреса - C++
Здравствуйте. Есть функция с сигнатурой: void func(const tm &amp; _tm); В теле функции надо вызвать: time_t _mkgmtime( struct tm*...

При передачи указателя на обьект ошибка,а при передаче ссылки на указатель нет. Почему? - C++
Hi All! class SomeObj { public: int x; }


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

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

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