Адрес стека и кучи в C ++ - PullRequest
8 голосов
/ 20 августа 2010

Исправление:

Я перепутал концепцию адреса указателя и адреса, на который указывает указатель, поэтому следующий код был изменен. И теперь он печатает, что я хочу, переменные 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 в приведенном выше примере) находятся в стеке. Но, похоже, это не так в моем примере. Это зависит от разных компиляторов, или я не так понимаю?

Большое спасибо всем вам.

Ответы [ 8 ]

14 голосов
/ 20 августа 2010

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

Для вашего примера N, l и m предположительно находятся где-то в разделе данных вашего исполняемого файла.Как видите, у них похожие адреса.Все остальные переменные, которые вы выводите, находятся в стеке - их адреса также похожи друг на друга.Некоторые из них являются указателями, указывающими на объекты, выделенные из кучи, но ни одна из ваших распечаток не показала бы это.

3 голосов
/ 20 августа 2010

Ваше понимание верно.

  • локальные переменные размещены в стеке.
  • динамически размещаемые объекты размещаются в куче.

Хотя в вашем примере вы последовательно используете адрес локальной переменной.
Пример: выведите d, а не адрес d. Поскольку d является локальной переменной (поэтому адрес аналогичен c), но это переменная-указатель, которая указывает на динамически размещенный объект (that is on the heap).

То, как компилятор реализует стек и кучу, будет меняться.

В современных ОС стек и куча могут даже совместно использовать одну и ту же область (т. Е. Вы можете реализовать стек, выделяя куски в куче).

2 голосов
/ 20 августа 2010

Единственные, кто не «вместе» в вашем примере, это l, m и N.Это две статики и одна глобальная, поэтому они точно не размещены в стеке.Они не из кучи, скорее всего, из сегмента .data вашего модуля.Единственный из кучи должен быть адрес, на который указывает b, но вы печатаете адрес самого b, а не того, на что он указывает.

2 голосов
/ 20 августа 2010

Если вы хотите напечатать адрес того, на что указывает d (в данном случае это указывает на объект в куче), выполните

  cout << "d: " << d << endl;

, который выведет значение указателя,и значение указателя является адресом объекта, на который он указывает.

Ваш код имел

   cout << "&d: " << &d << endl;

Это печатает адрес d, как вы определили d внутриГлавное, это будет в стеке, вы печатаете адрес вашего указателя.Там есть сам указатель, и объект, на который он указывает, это две отдельные вещи с отдельными адресами.

0 голосов
/ 20 августа 2010

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

0 голосов
/ 20 августа 2010

Вы не можете зависеть от того, как разные компиляторы делают вещи одинаково. Почти для каждого фрагмента кода вы будете писать, что различие между стеком и кучей не имеет смысла. Не беспокойся об этом.

0 голосов
/ 20 августа 2010

Статические переменные находятся в сегменте данных.Также вы смешиваете адрес указателя и его значение.Например, a:

a является локальной переменной типа A * в стеке.& a также дает адрес, на котором проживает актуально (в стеке).Значение a является адресом объекта кучи типа A;

0 голосов
/ 20 августа 2010

Различие между этими двумя формами, с точки зрения чистого C ++, заключается только в том, как управляется время жизни объектов.

Отсюда, хорошее чтение

...