Инициализация указателя и два указателя, указывающих на один и тот же адрес

Я пытаюсь лучше понять указатели. У меня есть этот кусок кода:

char theString[MAX] = "All your base are belong to us";
char *i = theString;
char *j = theString;
printf("%p\n", &theString);
printf("%p\n", &i);
printf("%p\n", &j);

Когда я запускаю свою программу, я всегда получаю три отдельных адреса. Я понимаю, что адреса памяти меняются каждый раз при компиляции и не являются статичными; но, поскольку я установил i и j на адрес первого символа в «theString», я бы предположил, что это будет один и тот же адрес?

Любая помощь приветствуется, спасибо.

то, что вы хотите, возможно, напечатать printf("%p\n", i); printf("%p\n", j);? Таким образом, вы получаете одинаковые адреса для трех.

gagiuntoli 08.04.2019 23:16
i и j являются переменными с одинаковым содержанием, но расположены в разных местах.
Thomas Jager 08.04.2019 23:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
403
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

&j и &i - это адреса указателей, а не объекта, на который они ссылаются.

printf("%p\n", (void *)i);
printf("%p\n", (void *)&j);

Так же, как int a = 3; и int b = 3;, вы не ожидаете, что &a будет таким же, как &b

Ответ принят как подходящий

When I run my program I always get three separate addresses.

Вы распечатали адреса трех разных вещей: i, j и theString. Если вы напечатаете значенияi и j, вы обнаружите, что они оба указывают на theString. Оператор &принимает адрес г. сами переменные i и j.

Вот ваши операторы печати, измененные для отображения переменных в обоих направлениях:

printf("With &:%p\tWithout &:%p\n", &theString, theString);
printf("With &:%p\tWithout &:%p\n", &i, i);
printf("With &:%p\tWithout &:%p\n", &j, j);

И вывод:

With &:0x7ffeefbfee20   Without &:0x7ffeefbfee20
With &:0x7ffeefbfee08   Without &:0x7ffeefbfee20
With &:0x7ffeefbfee00   Without &:0x7ffeefbfee20

Это показывает, что у вас есть три разные переменные-указатели, которые указывают на одну и ту же ячейку памяти.

Попробуй это:

printf("Address of theString = %p, value of theString = %s\n", (void *) theString, theString);
printf("Address of i = %p, value of i = %p\n", (void *) &i, (void *) i );
printf("Address of j = %p, value of j = %p\n", (void *) &j, (void *) j );

theString, i и j — это отдельные объекты в памяти, поэтому все они будут иметь разные адреса. i и j будут иметь один и тот же стоимость, который является адресом theString.

Некоторые примечания:

  • За исключением случаев, когда это операнд оператора sizeof или унарного оператора & или строковый литерал, используемый для инициализации массива символов в объявлении, выражение типа «N-элементный массив T» будет преобразован («распад») в выражение типа «указатель на T», а значением выражения будет адрес первого элемента. Таким образом, в первом выражении printf вам не нужен оператор &, чтобы получить адрес theString. Оба выражения theString и &theString будут оцениваться по адресу первого элемента массива, но типы выражений будут разными (char * и char (*)[MAX]).

  • Спецификатор преобразования %p ожидает, что соответствующий аргумент будет иметь тип void *. Это единственное место в C, где вам нужно явно привести выражение указателя к void *.

  • Типы i и j — это char *, поэтому типы выражения&i и &j — это char **.

РЕДАКТИРОВАТЬ

Я взял ваши декларации и прогнал их через мою собственную утилиту дампа памяти:

#include "dumper.h"

#define MAX 32

int main( void )
{
  char theString[MAX+1] = "All your base are belong to us";
  char *i = theString;
  char *j = theString;

  char *names[] = {"theString", "i", "j" };
  void *addrs[] = {theString, &i, &j};
  size_t sizes[] = { sizeof theString, sizeof i, sizeof j };

  dumper( names, addrs, sizes, 3, stdout );

  return 0;
}

И вот результат:

       Item         Address   00   01   02   03
       ----         -------   --   --   --   --
  theString  0x7ffee727fa90   41   6c   6c   20    All.
             0x7ffee727fa94   79   6f   75   72    your
             0x7ffee727fa98   20   62   61   73    .bas
             0x7ffee727fa9c   65   20   61   72    e.ar
             0x7ffee727faa0   65   20   62   65    e.be
             0x7ffee727faa4   6c   6f   6e   67    long
             0x7ffee727faa8   20   74   6f   20    .to.
             0x7ffee727faac   75   73   00   00    us..
             0x7ffee727fab0   00   00   00   00    ....

          i  0x7ffee727fa20   90   fa   27   e7    ..'.
             0x7ffee727fa24   fe   7f   00   00    ....

          j  0x7ffee727fa18   90   fa   27   e7    ..'.
             0x7ffee727fa1c   fe   7f   00   00    ....

x86 имеет обратный порядок байтов, поэтому многобайтовые значения необходимо читать справа налево, снизу вверх. Вы увидите, что i и j содержат один и тот же стоимость (0x7ffee727fa90), который является адресом первого элемента theString.

i and j are char pointers , nothing but variables in short and like every variable they have their own locations and hence, their own addresses.

These variables hold the address of theString and hence both point to the same address

When you print &i and &j , it prints out the address of i and j in memory and hence, you get different addresses. But they hold the address of the same variable

Your code prints out the address of the array theString , pointer i address and pointer j address.


char theString[MAX] = "All your base are belong to us";
char *i = theString;
char *j = theString;
printf("%p\n", &theString);
printf("%p\n", &i);
printf("%p\n", &j);

касательно:

printf("%p\n", &theString);  

В C ссылка на имя массива деградирует до адреса первого байта массива, поэтому нет необходимости использовать оператор «адрес». Компилятор будет жаловаться на:

: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘char (*)[##]’ [-Wformat=] 

где '##' - количество элементов в массиве

Обратите внимание, что i и j указывают на строку, у которой есть собственная память. Поэтому они имеют разную стоимость. Но значения i, j и theString будут одинаковыми, что указывает на массив символов.

printf("%p\n", theString);
printf("%p\n", i);
printf("%p\n", j);

Выход:

0x8efeefbfee50
0x8efeefbfee50
0x8efeefbfee50

Другие вопросы по теме