В чем разница между указателем, установленным на значение, и указателем, установленным на адрес значения? - PullRequest
0 голосов
/ 08 июля 2019

У меня есть два вопроса, правда.Первый связан с взаимодействием указателя и переменной, а второй - с взаимодействием указателя и массива.Как лучше всего понять это?

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

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

Например:

int num = 5;
int * p;

p = num;  //This results in an error
p = # //This does not

Принимая во внимание, что:

int num[2] = {5, 10};

p = num;  //This does not result in an error
p = # //This does

В первой ситуации я получаю сообщение об ошибке, в котором «значение типа« int »нельзя присвоить объекту типа« int * »».

Во второй ситуации я получаю сообщение об ошибке, в котором «значение типа« int (*) [2] »нельзя присвоить объекту типа« int * »».

Почему это так?

РЕДАКТИРОВАТЬ: Я не считаю, что это дублирующий вопрос.Распад массива не отвечает на мой вопрос вообще, и вместо этого это связано с типами указателей, а не свойствами массивов.На этот вопрос уже был получен хороший ответ, но я хотел бы уточнить, что на мою проблему не ответил какой-либо вопрос, связанный с разрушением массива.

Ответы [ 2 ]

1 голос
/ 08 июля 2019

Переменная имеет ряд различных свойств.

Учитывая ваше определение переменной, которое я цитирую здесь

int num = 5;

его тип int, его имя num, оно инициализируется значением 5, а его адрес (например, расположение в памяти машины) равен &num.

Если бы я должен был определить вторую переменную сразу после

int q = 5

тогда эта переменная (например, num) будет иметь тип int и значение 5, но с другим именем q и другим адресом в памяти &q. Даже если они имеют одинаковое значение, адреса num и q различны. Это (помимо всего прочего) гарантирует, что присвоение q = 6 не изменит значения num.

Это идет дальше. Указатель в вашем образце

int * p;

означает, что p является указателем на int. Он имеет тип int *, поэтому его значением может быть адрес int. Итак, назначение

p = num;  //This results in an error

не работает, потому что p имеет тип int *, а num имеет тип int. Два типа различны, и int не может быть неявно преобразован в int *, поэтому назначение не допускается. Они разных типов. В реальном мире адрес улицы дома отличается от дома, даже если между ними есть связь.

Однако ваше назначение

p = # //This does not

работает, потому что p имеет тип int *, а &num является адресом int, поэтому также имеет тип int *.

Однако с массивами правила немного отличаются.

int num[2] = {5, 10};

p = num;  //This does not result in an error   
p = # //This does

Во-первых, num - это массив из двух int. У него есть имя num, но его тип int[2], и его значение фактически основано на паре int s 5 и 10.

При использовании в выражении num преобразуется в указатель на его первый элемент. Так

p = num;

эквивалентно

p = &num[0];

Преобразование num в &num[0] называется преобразованием «массив в указатель».

Второе задание, которое вы пробовали

p = # //This does 

отличается. В этом случае &num - это адрес массива num, а не адрес его первого элемента. Таким образом, &num имеет тип int (*)[2], который (в C ++) синтаксически означает «указатель на массив из двух int».

Тип p - int * (потому что именно так вы его определили), тогда как &num дает результат с типом int (*)[2]. Эти типы различны, поэтому назначение недопустимо.

Если вам нужна переменная, которая указывает на массив из двух int (в отличие от вашего p, который может указывать на первый элемент массива int), тогда определите

int num[2] = {5,10};
int (*q)[2];       //  q has type int (*)[2]

q = num;      // this will work

Тогда вы можете сделать, например;

std::cout << (*q)[0] << ' ' << (*q)[1] << '\n';

для печати значений 5 и 10. Это работает, потому что q указывает на массив, *q является (ссылкой) на массив num, поэтому (*q)[0] и (*q)[1] обращаются к num[0] и num[1] соответственно.

Обратите внимание, что круглые скобки () имеют решающее значение во всем приведенном выше обсуждении. *q[0] на самом деле (по правилам приоритета операторов и ассоциативности) эквивалентно *(q[0]), что весьма отличается от (*q)[0]. Я оставлю работу над тем, что *(q[0]) является (или не является) упражнением.

0 голосов
/ 08 июля 2019

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

Указатели - это тип данных в таких языках, как C и C ++, которые указывают на определенную «область памяти», указанную типом указателя, то есть только intуказатель может указывать на ячейку памяти int.

В первом примере

p = num

выдает ошибку, поскольку вы пытаетесь указать указатель на значение, но указатели не могут указывать на значенияно вместо этого только места памяти.Вот почему

p = &num 

работает.

Во втором примере

p = num

работает, потому что для массивов и структур в c и c ++ устанавливается указатель непосредственно наони автоматически указывают на первый адрес памяти, указанный массивом.Массивы сами по себе не являются специальными типами данных, а представляют собой последовательности значений сразу в памяти.Но

     p = &num

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

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