Исправление:
Я перепутал с концепцией адреса указателя и адреса, на который указывает указатель, поэтому следующий код был изменен. И теперь он печатает, что я хочу, переменные a, c, i, j, k, p находятся в стеке, а переменные b, d находятся в куче. Статические и глобальные переменные находятся в другом сегменте. Большое спасибо всем вам!
Ну, Я знаю, что эти две концепции глубоко обсуждены ... но у меня все еще есть вопросы для следующего кода:
#include <iostream>
using namespace std;
class A {
};
int N = 10;
void f(int p) {
int j = 1;
float k = 2.0;
A c;
A* d = new A();
static int l = 23;
static int m = 24;
cout << "&c: " << &c << endl;
cout << "&d: " << d << endl;
cout << "&j: " << &j << endl;
cout << "&k: " << &k << endl;
cout << "&l: " << &l << endl;
cout << "&m: " << &m << endl;
cout << "&p: " << &p << endl;
}
int main() {
int i = 0;
A* a;
A* b = new A();
cout << "&a: " << &a << endl;
cout << "&b: " << b << endl;
cout << "&i: " << &i << endl;
cout << "&N: " << &N << endl;
f(10);
return 0;
}
Мой результат:
&a: 0x28ff20
&b: 0x7c2990
&i: 0x28ff1c
&N: 0x443000
&c: 0x28fef3
&d: 0x7c0f00
&j: 0x28feec
&k: 0x28fee8
&l: 0x443004
&m: 0x443008
&p: 0x28ff00
Это довольно интересно, потому что кроме глобальной переменной N и двух статических переменных в функции f, которые равны l и m, адреса всех остальных переменных кажутся вместе. (Примечание: код и результаты были изменены и не соответствуют тому, что здесь сказано.)
Я много искал о стеке и куче. Здравый смысл заключается в том, что, если объект создается «новым», то он находится в куче. А локальные переменные (такие как j и k в приведенном выше примере) находятся в стеке. Но, похоже, это не так в моем примере. Зависит ли это от разных компиляторов, или мое понимание неверно?
Большое спасибо всем вам.
Ваше понимание неверно. Например, b
является указателем - если вы хотите получить адрес объекта, созданного с помощью new
, вам нужно вывести b
, а не & b.
. b
- это локальная переменная, поэтому она сама (находится по адресу & b
) находится в стеке.
Для вашего примера, N
, l
и m
предположительно где-то в разделе данных вашего исполняемого файла. Как видите, у них похожие адреса. Все остальные переменные, которые вы распечатываете, находятся в стеке - их адреса также похожи друг на друга. Некоторые из них являются указателями на объекты, выделенные из кучи, но ни одна из ваших распечаток этого не покажет.
Если вы хотите вывести адрес того, на что указывает d
(в данном случае он указывает на объект на куче), сделайте
cout << "d: " << d << endl;
Это выведет значение указателя, а значение указателя - это адрес объекта, на который он указывает.
Ваш код имел
cout << "&d: " << &d << endl;
Это печатает адрес d
, так как вы определили d
внутри main, он будет на стеке, вы печатаете адрес указателя. Есть сам указатель и объект, на который он указывает, это две отдельные вещи, с отдельными адресами.
Ваше понимание правильное.
Хотя в своем примере вы последовательно берете адрес локальной переменной.
Пример: выведите d
, а не адрес d
. Так как d
является локальной переменной (поэтому адрес похож на c
), но это переменная-указатель, которая указывает на динамически выделенный объект (который находится на куче)
.
То, как компилятор реализует стек и кучу, может быть разным.
В современных ОС стек и куча могут даже разделять одну и ту же область (т.е. вы можете реализовать стек, выделяя куски в куче).
Единственные, которые не «вместе» в вашем примере, это l
, m
и N
. Это две статические и одна глобальная, поэтому они точно не размещаются в стеке. Они тоже не из кучи, скорее всего, они из сегмента .data вашего модуля. Единственным адресом из кучи должен быть адрес, на который указывает b
, но вы печатаете адрес самого b
, а не того, на что он указывает.
Можно с уверенностью предположить, что что-либо об относительных адресах вещей в стеке относительно тех, что в куче, ни, если на то пошло, относительные адреса любых указателей, которые не все получены из одного и того же массива или выделены (через malloc, calloc и т. д.) блоком. Я даже не уверен, что указатели должны быть ранжируемыми.
Различие между этими двумя формами, с точки зрения чистого C++, связано только с тем, как управляется время жизни объектов.
Статические переменные находятся в сегменте данных. Также вы смешиваете адрес указателя и его значение. Например, a:
a - это локальная переменная типа A* на стеке. &a также дает адрес, по которому a находится на самом деле (на стеке). Значение a - это адрес объекта кучи типа A;
Вы не можете полагаться на то, что различные компиляторы делают все одинаково. Почти для каждого куска кода, который вы напишете, различия между стеком и кучей не имеют смысла. Не беспокойтесь об этом.