Что инициализирует указатель?

Одна вещь, которая меня всегда путала, указатель на характер. После долгих четырех лет я снова задерживаюсь.

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

 #include  #include  int main() { char* charPtr="I cant understand why"; int* intPtr=60; printf("%d\n", intPtr); //displays 60 printf("%p\n", intPtr); // displays the hex value of 60 printf("%s\n", charPtr); // displays the wh0le string printf("%p\n", charPtr); // displays the start address of the string return 0; 

}

Затем указатель int , как он может принять значение 60 и где он хранится?

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

почему эти случаи

  *intptr = 60 ; // should be setting the pointee's value to 60 intptr = 60 ; // sets the address 

ошибка компиляции

  int* intPtr=60; 

прокрасться, не получив адрес (или 60 принято в качестве адреса, если да, то почему это неприемлемо не в первом случае) адресата!

Наверное, я здесь что-то не хватает, но эй! Угадай, что ? они сказали мне искать в СО!

EDIT: Дать адрес, на который указывает указатель char на указатель int, также не вызывает ошибок!

 int8_t* intPtr= (int8_t*)0x80485c8 ; // works without casting too ! I guess addresses are acceptable. 

Разыменовывая это, вы получите значение, эквивалентное первому I строки. Это хорошая практика или существует какое-либо другое объяснение этому, если исключить их распределение по размеру байтового бита, например, int может содержать символ и т. Д.?

Как указал hmjd, «синтаксис инициализации» – проблема! У меня нет проблем с написанием собственного кода, но возникает проблема при изменении кода пользователя!

В C строковый литерал, такой как «Я не могу понять, почему», хранится как массив char , так что память доступна в течение всего времени работы программы (все адреса вытягиваются из airа и не предназначены для представления каких-либо конкретная платформа или архитектура):

 Item Address 0x00 0x01 0x02 0x03 ----- ------- ---- ---- ---- ---- "I..." 0x00080000 'I' ' ' 'c' 'a' 0x00008004 'n' ''' 't' ' ' 0x00008008 'u' 'n' 'd' 'e' 0x0000800C 'r' 's' 't' 'a' 0x00008010 'n' 'd' ' ' 'w' 0x00008014 'h' 'y' 0x00 0x?? 

Строковый литерал также является выражением массива , и в большинстве контекстов выражение типа «N-element array of T » будет преобразовано в тип «указатель на T », а его значение будет адресом первого элемента массива (исключения состоят в том, что выражение массива является операндом операторов sizeof или унарных & или является строковым литералом, используемым для инициализации массива в объявлении).

Поэтому, когда вы пишете

 char* charPtr = "I can't understand why"; 

вы копируете адрес строкового литерала в charPtr :

 Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- charPtr 0xffbe4000 0x00 0x08 0x00 0x00 

Обратите внимание, что если бы декларация была

 char str[] = "I can't understand why"; 

str был бы выделен как массив char достаточно длинный для хранения строки, и содержимое строки было бы скопировано на нее:

 Item Address 0x00 0x01 0x02 0x03 ----- ------- ---- ---- ---- ---- str 0xffbe4000 'I' ' ' 'c' 'a' 0xffbe4004 'n' ''' 't' ' ' 0xffbe4008 'u' 'n' 'd' 'e' 0xffbe400C 'r' 's' 't' 'a' 0xffbe4010 'n' 'd' ' ' 'w' 0xffbe4014 'h' 'y' 0x00 0x?? 

Когда вы пишете

 int* intPtr = 60; 

вы инициализируете значение указателя на 60, не устанавливая его для указания на анонимное целое число со значением 60:

 Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- intPtr 0xffbe4004 0x00 0x00 0x00 0x3C 

Адрес 60, скорее всего, не является допустимым адресом, поэтому попытка разыменования intPtr , скорее всего, приведет к неопределенному поведению.

Если бы вы написали что-то вроде

 int x = 60; int *intPtr = &x; 

то у вас будет такая ситуация:

 Item Address 0x00 0x01 0x02 0x03 ---- ------- ---- ---- ---- ---- x 0xffbe4004 0x00 0x00 0x00 0x3C intPtr 0xffbe4008 0xff 0xbe 0x40 0x04 

В этом случае значение intPtr является адресом x .

Наконец, обратите внимание, что инициализация и назначение – это не одно и то же.

 T *x = value; 

не разыгрывает x и не присваивает value результату; он присваивает value непосредственно x . Тип value рассматривается как T * . Обратите внимание, что вы должны получать предупреждения

 int *intPtr = 60; 

по строкам «создание указателя из целого без литья».

Как мы можем напрямую обращаться к содержимому адресата, когда он указывает на ничего или он похож на указатель символов, хранит ненужные файлы?

Я думаю, что путаница – синтаксис инициализации. Это:

 char* charPtr="I cant understand why"; 

не charPtr . Это эквивалентно:

 char* charPtr; charPtr = "I cant understand why"; 

Оба fragmentа кода сохраняют адрес строкового литерала "I cant understand why" для charPtr . Нет разыменования указателя, указывающего на то, что ничего не происходит. Переменная указателя любого типа может хранить только адрес.

Это:

 int* intPtr=60; 

сохраняет адрес 60 в intPtr : нет назначения int или отсрочки. На данный момент нет переменной int . Компилятор должен был выпустить предупреждение в этой строке. Любая попытка intPtr к intPtr скорее всего вызовет сбой.

Когда вы пишете:

  char* charPtr = "I can't understand why"; 

Это означает, что базовый адрес строки «Я не могу понять, почему» назначается

charPtr, потому что строковый литерал также является указателем на эту строку.

Его можно рассматривать как:

понятие строки, хранящейся в массиве символов

Это означает, что в charPtr сохраняется базовый адрес всей строки. Теперь это то, что вы сделали в своем коде.

  char *charPtr="i cant understand why"; 

Добавляем к этому, если вы печатаете утверждения типа:

 printf("%c","i cant understand why"[0]);//prints i printf("%c","i cant understand why"[2]);//prints c 

Эти два printf оправдывают мои представления о том, что строка «я не могу понять, почему» сама является указателем на массив символов, в котором хранится строка.

Ваш intPtr инициализируется, intPtr на абсолютный адрес памяти 60 . Здесь нет бэк-магазина.

Поскольку вы не разыгрываете сам указатель, вы никогда не пытаетесь прочитать адрес 60 который, вероятно, приведет к сбою вашей программы в зависимости от среды.

Вместо этого вы передаете значение указателя в printf которое принимает почти что угодно, как аргументы, и интерпретирует значения, указанные вами в строке формата. В вашем случае он будет интерпретировать адрес указателя вместо значения указателя. Адрес равен 60 чтобы он отображался. Если бы вы использовали *intPtr вместо этого он, вероятно, разбился бы.