Почему мы используем "type * var" вместо "type & var" при определении указателя? - PullRequest
5 голосов
/ 30 июня 2009

Я относительно новичок в C ++ (около года опыта, вкл и выкл). Мне интересно, что привело к решению type * name в качестве синтаксиса для определения указателей. Мне кажется, что синтаксис должен быть type & name, так как символ & используется везде в коде для ссылки на адрес памяти переменной. Итак, чтобы использовать традиционный пример int указателей:

int a = 1;
int * b = &a;

станет

int a = 1;
int & b = &a

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

Спасибо, -S

Ответы [ 6 ]

7 голосов
/ 30 июня 2009

C ++ принимает синтаксис C. Как показано в « Разработка языка C » (Деннис Ритчи), C использует * для указателей в объявлениях типов, потому что было решено, что синтаксис типов должен следовать за использованием.

Для каждого объекта [составного типа] уже был способ упомянуть базовый объект: индексировать массив, вызывать функцию, использовать оператор косвенного обращения [*] для указателя. Аналогичные рассуждения привели к объявлению синтаксиса для имен, отражающих синтаксис выражения, в котором обычно появляются имена. Таким образом,

int i, *pi, **ppi;

объявлять целое число, указатель на целое число, указатель на указатель на целое число. Синтаксис этих объявлений отражает наблюдение, что все i, * pi и ** ppi дают тип int при использовании в выражении.

Вот более сложный пример:

int *(*foo)[4][];

Это объявление означает, что выражение *(*foo)[4][0] имеет тип int, и из этого (и этот [] имеет более высокий приоритет, чем унарный *) вы можете декодировать тип: foo - указатель на массив размера 4 массива указателей на целые.

Этот синтаксис был принят в C ++ для совместимости с C. Кроме того, не забывайте, что в C ++ есть использование для объявлений & in.

int & b = a;

Приведенная выше строка означает ссылочную переменную, ссылающуюся на другую переменную типа int. Разница между ссылкой и указателем примерно состоит в том, что ссылки инициализируются только, и вы не можете изменить, куда они указывают, и, наконец, они всегда разыменовываются автоматически.

int x = 5, y = 10;
int& r = x;

int sum = r + y; // you do not need to say '*r' automatically dereferenced.

r = y; // WRONG, 'r' can only have one thing pointing at during its life, only at its infancy ;)
4 голосов
/ 30 июня 2009

Я думаю, что Деннис Ричи ответил на это в Развитие языка C :

Для каждого объекта такого сложного типа, уже был способ упомянуть базовый объект: индекс массив, вызовите функцию, используйте оператор косвенного обращения по указателю. Аналогичные рассуждения привели к Синтаксис объявления для зеркального отображения имен что из синтаксиса выражения, в котором имена обычно появляются. Таким образом,

int i, *pi, **ppi;

объявить целое число, указатель на целое число, указатель на указатель на целое число. Синтаксис этих декларации отражают наблюдение что я, * Пи, и ** ППИ все дают Тип int при использовании в выражении. Аналогичным образом,

int f(), *f(), (*f)();

объявить функцию, возвращающую целое число, функция, возвращающая указатель на целое число, указатель на функция, возвращающая целое число;

int *api[10], (*pai)[10];

объявить массив указателей на целые числа и указатель на массив целые числа. Во всех этих случаях объявление переменной напоминает его использование в выражении, тип которого это тот, который назван во главе декларация.

Таким образом, мы используем type * var для объявления указателя, потому что это позволяет объявлению отражать использование (разыменование) указателя.

В этой статье Ритчи также рассказывает, что в «NB», расширенной версии языка программирования «B», он использовал int pointer[] для объявления указателя на int, в отличие от int array[10] для объявления массив int с.

3 голосов
/ 30 июня 2009

Если вы визуальный мыслитель, это может помочь представить звездочку в виде черной дыры , ведущей к значению данных. Следовательно, это указатель.

Амперсанд - это противоположный конец дыры, представьте себе распутанную звездочку или космический корабль, колеблющийся в хаотичном курсе, когда пилот преодолевает переход, выходящий из черной дыры.

Я помню, что был очень смущен тем, что C ++ перегружал значение амперсанда, чтобы дать нам ссылки. В своей отчаянной попытке избежать использования дополнительных символов, что было оправдано международной аудиторией, использующей C и известными проблемами с ограничениями клавиатуры, они добавили основной источник путаницы.

Одна вещь, которая может помочь в C ++, это думать о ссылках как о предварительно подготовленных разыменованных указателях . Вместо использования & someVariable при передаче аргумента вы уже использовали конечный амперсанд при определении someVariable. Опять же, это может еще больше сбить вас с толку!

Одной из моих ненавистей к домашним животным, которую я был недоволен, когда ее обнародовали в примерах Apple Objective-C, является стиль макета int *someIntPointer вместо int* someIntPointer

ИМХО, сохранение звездочки с переменной является старомодным подходом C, подчеркивающим механику того, как вы определяете переменную, над ее типом данных.

Тип данных someIntPointer является буквально указателем на целое число, и объявление должно отражать это. Это приводит к требованию, чтобы вы объявляли одну переменную на строку, чтобы избежать тонких ошибок, таких как:

int* a, b;  // b is a straight int, was that our intention?

int  *a, *b;  // old-style C declaring two pointers

int* a;
int* b;  // b is another pointer to an int

В то время как люди утверждают, что способность объявлять смешанные указатели и значения в одной строке, намеренно, является мощной функцией, я видел, что это приводит к тонким ошибкам и путанице.

1 голос
/ 30 июня 2009

Вместо того, чтобы читать int* b как «b - указатель на int», читайте его как int *b: «* b - это int». Тогда у вас есть & как анти- *: * b - это int. Адрес *b равен &*b или просто b.

1 голос
/ 30 июня 2009

Ваш второй пример не является допустимым кодом C, только кодом C ++. Разница в том, что один является указателем, а другой - ссылкой.

В правой части '&' всегда означает адрес-оф. В определении он указывает, что переменная является ссылкой.

В правой части '*' всегда означает значение по адресу. В определении это указывает, что переменная является указателем.

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

0 голосов
/ 30 июня 2009

Я думаю, что ответ вполне может быть «потому что именно так K & R и сделал».

Понижение дураков. Объясните, почему я не прав.

K & R - это те, кто решил, каким был синтаксис C для объявления указателей.

Это не int & x; вместо int * x; потому что таким образом язык был определен парнями, которые его придумали - K & R.

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