Размещение звездочки в объявлениях указателей

Недавно я решил, что мне просто нужно наконец изучить C / C ++, и есть одна вещь, которую я действительно не понимаю в указателях или, точнее, их определении.

Как насчет этих примеров:

  1. int* test;
  2. int *test;
  3. int * test;
  4. int* test,test2;
  5. int *test,test2;
  6. int * test,test2;

Теперь, насколько я понимаю, первые три случая все делают то же самое: Test не int, а указатель на один.

Второй набор примеров немного сложнее. В случае 4 оба теста и test2 будут указателями на int, тогда как в случае 5 только тест является указателем, тогда как test2 является «реальным» int. Как насчет случая 6? То же, что и в случае 5?

4, 5 и 6 – одно и то же, только тест – это указатель. Если вам нужны два указателя, вы должны использовать:

 int *test, *test2; 

Или, еще лучше (чтобы все было ясно):

 int* test; int* test2; 

Белое пространство вокруг звездочек не имеет значения. Все три означают одно и то же:

 int* test; int *test; int * test; 

« int *var1, var2 » – это злой синтаксис, который предназначен только для того, чтобы запутать людей и их следует избегать. Он расширяется до:

 int *var1; int var2; 

Используйте «Вращение по часовой стрелке», чтобы помочь разобрать объявления C / C ++;

Существует три простых шага:

  1. Начиная с неизвестного элемента, двигайтесь по спирали / по часовой стрелке; при встрече со следующими элементами заменяйте их соответствующими английскими инструкциями:

    [X] или [] : Array X size of … или Array undefined size of …

    (type1, type2) : функция передачи type1 и type2 возвращается …

    * : указатель (ы) для …

  2. Продолжайте делать это по спирали / по часовой стрелке до тех пор, пока все маркеры не будут закрыты.
  3. Всегда сначала разрешайте что-либо в скобках!

Кроме того, декларации должны быть в отдельных заявлениях, когда это возможно (что верно подавляющее большинство раз).

Многие рекомендации по кодированию рекомендуют вам указывать только одну переменную в строке . Это позволяет избежать какой-либо путаницы в вашем роде, прежде чем задавать этот вопрос. Большинство программистов на С ++, с которыми я работал, похоже, придерживаются этого.


Немного в стороне, которую я знаю, но что-то, что мне показалось полезным, – это прочитать декларации назад.

 int* test; // test is a pointer to an int 

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

 int* const test; // test is a const pointer to an int int const * test; // test is a pointer to a const int ... but many people write this as const int * test; // test is a pointer to an int that's const 

Как упоминалось выше, 4, 5 и 6 одинаковы. Часто люди используют эти примеры, чтобы аргумент, который * принадлежит переменной, а не типу. Хотя это проблема стиля, есть некоторые дебаты о том, следует ли думать и писать так:

 int* x; // "x is a pointer to int" 

или таким образом:

 int *x; // "*x is an int" 

FWIW Я нахожусь в первом лагере, но причина, по которой другие делают аргумент для второй формы, заключается в том, что она (в основном) решает эту конкретную проблему:

 int* x,y; // "x is a pointer to int, y is an int" 

который потенциально вводит в заблуждение; вместо этого вы

 int *x,y; // it's a little clearer what is going on here 

или если вам действительно нужны два указателя,

 int *x, *y; // two pointers 

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

 #include  std::add_pointer::type test, test2; 

В 4, 5 и 6 test всегда является указателем, а test2 не является указателем. Белое пространство (почти) никогда не бывает значительным в C ++.

Указатель является модификатором типа. Лучше всего прочитать их справа налево, чтобы лучше понять, как звездочка модифицирует тип. ‘int *’ может быть прочитан как «указатель на int». В нескольких объявлениях вы должны указать, что каждая переменная является указателем или будет создана как стандартная переменная.

1,2 и 3). Тест имеет тип (int *). Пробел не имеет значения.

4,5 и 6). Тест имеет тип (int *). Test2 имеет тип int. Опять пробелы несущественны.

Вы можете думать о 4, 5 и 6 следующим образом: объявить, что тип должен быть выполнен один раз, но если вы хотите объявить указатель на этот тип (добавив звездочку), вы должны сделать это для каждой переменной.

При объявлении переменной указателя я всегда добавляю пробел между переменной и звездочкой, даже если я объявляю более одного в строке. Не делая этого, я смущаю его для разыменования выражения почти каждый раз.

Обоснование в C состоит в том, что вы объявляете переменные так, как вы их используете. Например

 char *a[100]; 

говорит, что *a[42] будет char . И a[42] указатель на символ. И, таким образом, a представляет собой массив указателей на символы.

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

Я бы сказал, что первоначальная конвенция заключалась в том, чтобы поместить звезду в сторону имени указателя (правая часть декларации

  • на языке программирования C Деннисом М. Ричи звезды находятся на правой стороне декларации.

  • посмотрев исходный код linux на странице https://github.com/torvalds/linux/blob/master/init/main.c, мы видим, что звезда также находится на правой стороне.

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

Хорошее эмпирическое правило, многие люди, похоже, понимают эти понятия: В C ++ много семантического значения вызывается левым связыванием ключевых слов или идентификаторов.

Возьмем, к примеру:

 int const bla; 

Константа применяется к слову «int». То же самое со звездочками указателей, они применяются к ключевому слову слева от них. И имя фактической переменной? Да, это объявлено тем, что осталось от него.

Случаи 1, 2 и 3 одинаковы, они объявляют указатели на переменные int. Случаи 3, 4 и 5 совпадают, так как они объявляют один указатель и одну переменную int соответственно. Если вы хотите, объявите два указателя в одной строке (что вам не нужно), вам нужно поставить звездочку перед каждым именем переменной:

 int *test, *test2; 

Не существует правильного пути, указывающего, куда идет звездочка. int* test выглядит лучше, потому что нам легче представить, что добавление * в конец типа означает «указатель на» этого типа. Тем не менее, int *test имеет больше смысла, потому что вы можете работать с ним, как знак минуса в математике:

 -(-x) = x 

аналогично

 *(*test) = test 

Это всегда помогало мне. К сожалению, все дело в том, что иногда я использую int* test и иногда int *test .

  • Разница между char * str = "STRING" и char str = "STRING"?
  • Инициализация указателя в отдельной функции в C
  • Почему бы не использовать указатели для всего на C ++?
  • Использование стрелки (->) в C
  • Адрес массива
  • Можно ли программно определить размер массива C ++? А если нет, то почему?
  • Могу ли я взять адрес элемента «один конец прошлого» массива?
  • Псевдонимы, вызываемые разыменованием, нарушат правила строгого сглаживания
  • Что такое имя массива в c?
  • Можно ли выделить функцию внутри массива и вернуть ее с помощью ссылки?
  • Возвращаемый массив в функции
  • Давайте будем гением компьютера.