Правильный способ объявления переменных-указателей в C / C ++ [закрыто]

91

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

(a) char* p;

вместо того

(b) char *p;

Я использую (б). Что является рациональным за обозначением (а)? Обозначение (b) имеет для меня больше смысла, потому что указатель на символ не является самим типом. Вместо этого тип является символом, а переменная может быть указателем на символ.

char* c;

Похоже, что существует тип char * и переменная c этого типа. Но на самом деле это тип char, а * c (ячейка памяти, указанная c) относится к этому типу (char). Если вы объявляете сразу несколько переменных, это различие становится очевидным.

char* c, *d;

Это выглядит странно. И c, и d - это указатели одного типа, указывающие на символ. При этом следующий выглядит естественнее.

char *c, *d;

Спасибо.

Кида
источник
7
Что вы имеете в виду, указатель char - это не тип? Вы хотите сказать, что указатель - это не тип?
Бенджамин Линдли,
1
Я считаю, что это вопрос предпочтений, если вы не просматриваете конкретное руководство по стилю (например, ваша компания может иметь определенный стандарт кодирования, которому вы должны следовать). Я стараюсь смешивать вариант «б» с чем-то посередине. Иногда мне кажется char *t, что я не выгляжу должным образом, поэтому я могу это сделать char * t;. Однако я тоже часто видел char* t;.
RageD
1
Кроме того, ваше рассуждение «тип char и * c (ячейка памяти, указанная c) относится к этому типу (char)» , похоже, указывает на то, что объявляется char, хотя на самом деле его нет. Если к нему относиться как к такому, как это иногда делают новички, это наверняка приведет к нарушениям доступа к памяти.
Бенджамин Линдли,
1
Оба по-прежнему достаточно информативны, (b) показывает, что * p относится к типу, charи (a) показывает, что p является apointer to a char
Человек
1
Имея более чем десятилетний опыт работы в отрасли, сегодня это впервые возникло, и только при чтении статей других профессионалов отрасли. Таким образом, очевидно, что у меня никогда не было такого религиозного разговора по этому поводу, как с табуляцией v пробелами, комментариями по def или dec, или любой другой темой «хорошо, что не о чем спорить более важном» . Исходя из этого, я предпочел на столь позднем этапе своей карьеры использовать «char * p» чаще, чем нет. Да, пробел перед, пробел после. В основном, как я считаю, это уменьшает количество ошибок, поскольку делает более очевидным указатель.
Kit10,

Ответы:

102

Бьярне Страуструп сказал:

Выбор между "int * p;" и "int * p;" не о правильном и неправильном, а о стиле и акцентах. C подчеркнутые выражения; заявления часто считались не более чем необходимым злом. С другой стороны, C ++ делает большой упор на типы.

«Типичный программист на C» пишет «int * p;» и объясняет это «* p - это то, что такое int», подчеркивая синтаксис, и может указывать на грамматику объявления C (и C ++), чтобы аргументировать правильность стиля. В самом деле, * связывается с именем p в грамматике.

«Типичный программист на C ++» пишет «int * p;» и объясняет, что «p - указатель на тип int». Действительно, тип p - int *. Я явно предпочитаю этот акцент и считаю его важным для хорошего использования более продвинутых частей C ++.

Источник: http://www.stroustrup.com/bs_faq2.html#whitespace

Я бы порекомендовал последний стиль, потому что в ситуации, когда вы объявляете несколько указателей в одной строке (ваш 4-й пример), звездочка с переменной будет тем, к чему вы привыкли.

Блэк Джек
источник
34
Другие рекомендуют никогда не объявлять несколько объектов в одном объявлении. :-)
Bo Persson
5
Я подчеркиваю логику, лежащую в основе синтаксиса, поэтому я предпочитаю:, то int *pесть: при pразыменовании я получаю int. Тогда ,имеет смысл несколько объявлений, разделенных символом: int *p, *q, r(при разыменовании pили qя получаю int, при rссылке я получаю int). Также имеет смысл синтаксис указателя на функцию: int (*f)()(когда fразыменован и вызван, я получаю int). И это имеет смысл: int *p, (*f)().
Druesukker
2
Это помогло мне понять, что есть обоснованность и другой стороны аргументации. Поскольку я в основном программист высокого уровня, я подчеркиваю тип; и предпочитаю int*. Для меня int *p, (*f)()это не имеет особого смысла, но я могу видеть, как это будет с некоторыми людьми в некоторых ситуациях.
Assimilater
1
@Druesukker, я думаю, ваше утверждение имеет больше смысла, чем любое из вышеперечисленных.
Muntashir Akon
1
@Druesukker Но логика точно не работает void*(и вообще не работает для ссылок на C ++).
jamesdlin
57

Лично я предпочитаю размещать *вместе с остальными типами

char* p;  // p is a pointer to a char.

Люди будут спорить, «но затем char* p, q;вводят в заблуждение», на что я говорю: «Так что не делай этого».

икегами
источник
Очень хороший аргумент в пользу char * p; выбор :) Я не возражаю против любого из них, если не станет трудно читать пример, который вы показали, и в этом случае они не должны этого делать.
Хесус Рамос,
1
А когда нужно вывести значение? Вы делаете cout << *p;. Так почему бы не поставить звездочку перед p объявлением *p:? На мой взгляд, это было бы менее запутанно.
user1170330
13
@ user1170330, потому что в одном месте это часть определения типа, а в другом - оператор разыменования. Нет связи. Во всяком случае, хорошо, что они выглядят по-разному, ведь разные вещи должны выглядеть по-разному.
ikegami
33

Нет разницы, как писать. Но если вы хотите объявить два и более указателя в одной строке, лучше использовать вариант (б), потому что ясно, чего вы хотите. Смотри ниже:

int *a;
int* b;      // All is OK. `a` is pointer to int ant `b` is pointer to int
char *c, *d; // We declare two pointers to char. And we clearly see it.
char* e, f;  // We declare pointer `e` and variable `f` of char type.
             // Maybe here it is mistake, maybe not. 
// Better way of course is use typedef:
typedef char* PCHAR;
PCHAR g, h;  // Now `g` and `h` both are pointers.
// If we used define construction for PCHAR we'd get into problem too.
Джордж Гаал
источник
5
typedefне лучший способ "конечно". Некоторые люди могут предпочесть это, но это проблематично, если с вашим кодом работает несколько человек. Если бы я не привык PCHAR, я мог бы написать что-нибудь вроде PCHAR *p;, что было бы, char**а не то, что я собирался. В общем, если вы хотите char**, вам придется написать PCHAR*или определить новый тип, и тогда он просто станет глупым.
BlackJack
3
Если нужен какой-то сложный тип указателя, такой как указатель на функцию, очень хорошая идея сделать typedefs. В этом случае они значительно упрощают код. С другой стороны, использование PCHAR - это скорее синтетический пример, чем повседневная практика. Но он явно делает то, что вы хотите. а потом он просто начинает глупеть. Пожалуйста, направляйте все жалобы Страуструпу :-)
Джордж Гаал,
Если вы написали PCHAR * p для определения указателя на char, было бы очевидно, что вы не знаете, что делаете, и не читали тип def. Ответ по его мнению. У typedef есть еще одно преимущество; в C - простые способы сделать вещи непрозрачными. публично иметь символ, определенный как VOID ptr, в частном порядке type def - это что-то еще .... Я бы предпочел время от времени настраивать typedef, а затем настраивать все во всем коде, когда мы что-то меняем в одном из типов ... но C ++ 11 решает многие
проблемы
Для тех, кто пытается вернуться к игре с C ++ через пять лет после колледжа, это один из лучших ответов.
Panzercrisis
10

Компромисс

char * p;

K&R использует

char *p;

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

jnnnnn
источник
4
Я на собственном горьком опыте понял, что char * x, y не означает, что y является char *. Теперь я понимаю, почему K&R следует указанному стилю.
Рахул Кадукар
что такое K&R и почему важно то, что использует единственный источник кода? Пользуюсь char* p;. это вопрос стиля, а не условностей или правил. для меня более логично, что p имеет тип char*, поэтому, очевидно, * должен быть с типом.
FalcoGer
@FalcoGer Я добавил ссылку на K&R. Неважно, какой единственный источник кода использует. Ваша команда может рассердиться на вас, если вы не будете следовать их стандартам, потому что вы заставляете их усерднее работать над пониманием вашего кода. В наши дни я надеюсь, что команды все clang-formatравно используют .
jnnnnn
2

Это все вопрос предпочтений, лично в проектах, в которых я вижу символ char *, я обычно объявляю несколько указателей в отдельных строках. Нет настоящего «правильного» способа сделать это, и все зависит от предпочтений. Некоторые говорят, что легче читать (а), в то время как другие говорят, что (б) легче объявить больше переменных одного типа в одной строке.

Я считаю, что (b) встречается чаще, и в некоторых случаях я видел

char * a;

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

Хесус Рамос
источник