Я пытаюсь лучше понять указатели. У меня есть этот кусок кода:
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», я бы предположил, что это будет один и тот же адрес?
Любая помощь приветствуется, спасибо.
i
и j
являются переменными с одинаковым содержанием, но расположены в разных местах.
&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
то, что вы хотите, возможно, напечатать
printf("%p\n", i); printf("%p\n", j);
? Таким образом, вы получаете одинаковые адреса для трех.