Адрес памяти C ++ - PullRequest
       8

Адрес памяти C ++

7 голосов
/ 27 июня 2019

Прошу прощения, если это повторный вопрос

Это мой код

#include "stdafx.h"
#include <stdio.h>
#include "iostream"
#include <stdlib.h>
using namespace std;

int main()
{
    char * name = "Hello";

    cout << "2" << endl;
    cout << "Address2 is " << &name <<  "   value at address is " << * (&name) << endl;
    cout << "Next address2 is " << &name + 1 << "   value at address is " << name + 1 << "  " << sizeof(char) << endl;

    cout << "3" << endl;
    cout << "Address3 is " << &name << "   value at address is " << name << endl;

    cout << "Next address3 is " << &name + sizeof name << "   value at address is " << name + sizeof name << endl;
    getchar();
}

и это вывод

  1. Address2 isЗначение 003EFAA4 по адресу: Привет // Мне легко понять

  2. Следующий адрес 2 - 003EFAA8 (Это то, где я пытаюсь понять. Мое пониманиеследующий адрес должен быть 003EFAA5, учитывая, что символ имеет 1 байт?

  3. вывод такой же, как 1

  4. Следующий адрес2 равен 003EFAB4 (Здесь я тоже пытаюсь понять. Насколько я понимаю, следующий адрес должен быть 003EFAA8, если адрес имени переменной - 003EFAA4, учитывая, что размер указателя на символ равен 4 байта?

Мое понимание памяти - это адреса, на которые ссылаются в байтах. Если это так, то почему в номере 3 выше он дает мне адрес, который на 4 байта дальше, а в номере 4 выше он дает мне следующий адрес, который равен 10дальше байтов?

Любое объяснение будет высоко оценено.Спасибо

Ответы [ 4 ]

10 голосов
/ 27 июня 2019

Следующий адрес2 - 003EFAA8 (Вот где я пытаюсь понять. Насколько я понимаю, следующий адрес должен быть 003EFAA5, учитывая, что символ имеет 1 байт?

Когда вы делаете &name + 1вы переходите к следующему адресу типа name. name это не char, а char*, а в вашей системе char* имеет размер 4. Вот почему он идет4 байта вперед, так как именно здесь может находиться следующий char*.

Следующий адрес2 - 003EFAB4 (Это то, где я тоже пытаюсь понять. Мое понимание - следующий адрес должен быть 003EFAA8, когдаадрес имени переменной - 003EFAA4, учитывая, что размер указателя символа равен 4 байта?

Это в основном то же самое, что происходит выше, но вместо перехода к следующему char*, вы идетек следующему элементу sizeof name, который в данном случае является четвертым элементом.

8 голосов
/ 27 июня 2019

&name относится к типу char**. Способ, которым работает арифметика указателя, если вы добавите к нему, он увеличится во много раз к размеру char* (потому что char** указывает на char*, и таким образом он будет указывать на следующее char*, если есть были массивом char*). Похоже, размер char* равен 4 в вашей системе. Так что если &name равно 003EFAA4, то &name + 1 равно 003EFAA8 (это 4 больше).

sizeof name равно 4, поэтому, если вы добавите это к &name, оно увеличится на 16. Следовательно, когда вы получаете 003EFAB4, это 0x10 (или 16) больше, чем 003EFAA4.

6 голосов
/ 27 июня 2019

Добро пожаловать в арифметику указателей.

char *name = "hello";

name - указатель на символ. В нем хранится адрес "hello" строкового литерала, т.е. адрес символа h (адрес массива равен (значению) адресу первого элемента массива). Обратите внимание, что строковые литералы неизменны, вы не можете их изменять. Поэтому лучше всего изменить тип на const char*.

&name

Это указатель на имя переменной. Не указатель на строковый литерал "hello", а указатель на указатель. 003EFAA4 является адресом переменной name. Переменная была размещена компилятором в стеке внутри функции main().

*(&name)

Правило *& (здесь) само собой. Так что *&name равно name. Это печатает значение указателя name, т.е. это указатель на "hello" строковый литерал, т.е. это указатель на символ h внутри "hello" строкового литерала. Не &name. Адрес h символа.

&name + 1

&name имеет тип char **, т.е. это как указатель на указатель на символ. Из арифметики указателей &name + 1 равно значению (uintptr_t)&name + 1 * sizeof(*&name). sizeof(*&name) это sizeof(name) это sizeof(char*), поэтому (uintptr_t)&name + sizeof(char*). В вашей архитектуре sizeof(char*) составляет 4 байта (32-битная система?), Поэтому указатель увеличивается на 4. Т.е. 003EFAA4 + 4 = 003EFAA8.

name + 1

name имеет тип char*. Из арифметики указателя name + 1 равно (uintptr_t)name + sizeof(*name). sizeof(*name) - это sizeof(char). sizeof(char) определено равным 1. Это печатает адрес e символ внутри "hello" строкового литерала.

&name + sizeof name

&name имеет тип char**, поэтому значение &name увеличивается sizeof(name) * sizeof(char*) times. As sizeof (имя) is equal to sizeof (char *) , this is sizeof (char *) * sizeof (char *) ie. 4 * 4 = 16` на вашем компьютере.

name + sizeof name

Это увеличивает значение указателя name на значение sizoef(name) * sizeof(char). sizeof(name) - это sizeof(char*) - 4 в вашей архитектуре, sizeof(char) - 1. Итак, name + sizeof name - это адрес символа o внутри "hello" строкового литерала, т.е. 003EFAA8.

@ edit переписать некоторые части

6 голосов
/ 27 июня 2019

У вас здесь слишком много уровней косвенности.

&name - это символ **, то есть указатель на символьный указатель. Это означает, что если вы +1, то вы добавляете размер указателя, а не размер символа. name - это уже символ *.

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

cout << "Next address2 is " << (void*)(name + 1)

с использованием приведений в стиле C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...