В чем разница между const int*, const int * const и int const *?

Я всегда путаюсь, как использовать const int*, const int * const, а также int const * правильно. Существует ли набор правил, определяющих, что вы можете и не можете делать?

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

23 ответа

Решение

Прочитайте его в обратном направлении (как управляется по часовой стрелке / правилу спирали):

  • int* - указатель на int
  • int const * - указатель на const int
  • int * const - константный указатель на int
  • int const * const константный указатель на const int

Теперь первый const может быть на любой стороне типа так:

  • const int * == int const *
  • const int * const == int const * const

Если вы хотите сойти с ума, вы можете сделать что-то вроде этого:

  • int ** - указатель на указатель на int
  • int ** const - константный указатель на указатель на int
  • int * const * - указатель на константный указатель на int
  • int const ** - указатель на указатель на const int
  • int * const * const - константный указатель на константный указатель на int
  • ...

И чтобы убедиться, что мы ясно понимаем значение const

const int* foo;
int *const bar; //note, you actually need to set the pointer 
                //here because you can't change it later ;)

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

bar постоянный или фиксированный указатель на значение, которое можно изменить. Это как ссылка без лишнего синтаксического сахара. Из-за этого факта обычно вы используете ссылку, где вы бы использовали T* const указатель, если вам не нужно разрешить NULL указатели.

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

вот демо:

указатель на int

const указатель на int const

указатель на int const

указатель на const int

константный указатель на int

Я думаю, что все уже здесь ответили, но я просто хочу добавить, что вы должны остерегаться typedefs! Они НЕ просто текстовые замены.

Например:

typedef char *ASTRING;
const ASTRING astring;

Тип astring является char * constне const char *, Это одна из причин, по которой я всегда склонен const справа от типа, и никогда в начале.

Как почти все отметили:

В чем разница между const X* p , X* const p а также const X* const p ?

Вы должны прочитать объявления указателя справа налево.

  • const X* p означает "p указывает на постоянный X": объект X нельзя изменить с помощью p.

  • X* const p означает "p является константным указателем на X, который не является константным": вы не можете изменить сам указатель p, но вы можете изменить X-объект через p.

  • const X* const p означает "p является константным указателем на X, который является константой": вы не можете изменить сам указатель p, а также не можете изменить объект X с помощью p.

  1. Постоянная ссылка:

    Ссылка на переменную (здесь int), которая является постоянной. Мы передаем переменную в основном как ссылку, потому что ссылки меньше по размеру, чем фактическое значение, но есть побочный эффект, и это потому, что это похоже на псевдоним для фактической переменной. Мы можем случайно изменить основную переменную через наш полный доступ к псевдониму, поэтому мы устанавливаем ее постоянной, чтобы предотвратить этот побочный эффект.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
    
  2. Постоянные указатели

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

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
    
  3. Указатель на постоянную

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

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Постоянный указатель на постоянную

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

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
    

Этот вопрос показывает, почему мне нравится делать вещи так, как я упомянул в своем вопросе , const после type id приемлемо?

Короче говоря, я считаю, что самый простой способ запомнить правило - это то, что "const" идет после того, к чему оно относится. Итак, в вашем вопросе "int const *" означает, что int является константой, а "int * const" будет означать, что указатель является константой.

Если кто-то решит поместить его на передний план (например, "const int *"), в качестве особого исключения в этом случае он применяется к предмету после него.

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

Общее правило таково, что const Ключевое слово относится к тому, что ему предшествует. Исключение, старт const относится к тому, что следует.

  • const int* такой же как int const* и означает "указатель на константу int".
  • const int* const такой же как int const* const и означает "постоянный указатель на константу int".

Редактировать: Для того, что можно и чего нельзя делать, если этого ответа недостаточно, не могли бы вы быть более точным относительно того, что вы хотите?

Простое использование const

Самое простое использование - объявить именованную константу. Для этого нужно объявить константу так, как если бы она была переменной, но перед ней добавить "const". Нужно немедленно инициализировать его в конструкторе, потому что, конечно, нельзя установить значение позже, так как это изменило бы его. Например,

const int Constant1=96; 

создаст целочисленную константу, не названную по имени "Constant1", со значением 96.

Такие константы полезны для параметров, которые используются в программе, но их не нужно менять после компиляции программы. Он имеет преимущество перед программистами перед командой препроцессора C '#define' в том, что он понимается и используется самим компилятором, а не просто подставляется препроцессором в текст программы до достижения основного компилятора, поэтому сообщения об ошибках гораздо более полезны,

Он также работает с указателями, но нужно быть осторожным, когда 'const' определяет, является ли указатель или то, на что он указывает, постоянным или и тем, и другим. Например,

const int * Constant2 

объявляет, что Constant2 является переменным указателем на постоянное целое число и

int const * Constant2

альтернативный синтаксис, который делает то же самое, тогда как

int * const Constant3

объявляет, что Constant3 является постоянным указателем на целое число переменной и

int const * const Constant4

объявляет, что Constant4 является постоянным указателем на постоянное целое число. По сути, "const" относится к тому, что находится непосредственно слева от него (кроме случаев, когда там ничего нет, в этом случае оно применяется к тому, что непосредственно справа от него).

ссылка: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

Это просто, но сложно. Обратите внимание, что мы можем поменять местами const классификатор с любым типом данных (int, char, float, так далее.).

Давайте посмотрим на приведенные ниже примеры.


const int *p ==> *p только для чтения [p указатель на постоянное целое число]

int const *p ==> *p только для чтения [p указатель на постоянное целое число]


int *p const ==> Неверное утверждение. Компилятор выдает синтаксическую ошибку.

int *const p ==> p только для чтения [p постоянный указатель на целое число. Как указатель p здесь только для чтения, объявление и определение должны быть в одном месте.


const int *p const ==> Неверное утверждение. Компилятор выдает синтаксическую ошибку.

const int const *p ==> *p только для чтения

const int *const p1 ==> *p а также p только для чтения [p постоянный указатель на постоянное целое число]. Как указатель p здесь только для чтения, объявление и определение должны быть в одном месте.


int const *p const ==> Неверное утверждение. Компилятор выдает синтаксическую ошибку.

int const int *p ==> Неверное утверждение. Компилятор выдает синтаксическую ошибку.

int const const *p ==> *p только для чтения и эквивалентно int const *p

int const *const p ==> *p а также p только для чтения [p постоянный указатель на постоянное целое число]. Как указатель p здесь только для чтения, объявление и определение должны быть в одном месте.

У меня были те же сомнения, что и у вас, пока я не наткнулся на эту книгу Гуру С ++ Скотта Мейерса. Обратитесь к третьему пункту в этой книге, где он подробно рассказывает об использовании const,

Просто следуйте этому совету

  1. Если слово const слева от звездочки появляется то, на что указывает постоянная
  2. Если слово const справа от звездочки появляется, сам указатель постоянный
  3. Если const появляется с обеих сторон, оба постоянны

Для меня позиция const то есть, отображается ли он влево или вправо или влево и вправо относительно * помогает мне понять фактическое значение.

  1. const слева от * указывает, что объект, на который указывает указатель, является const объект.

  2. const справа от * указывает, что указатель является const указатель.

Следующая таблица взята из Stanford CS106L Standard C++ Programming Laboratory Reader.

Легко запомнить:

Если константа перед *, то значение будет постоянным.

Если константа стоит после *, то адрес постоянный.

если const доступны как до, так и после *, то и значение, и адрес постоянны.

например

  1. int * const var; // здесь адрес постоянный.

  2. int const * var; // здесь значение постоянное.

  3. int const * const var; // и значение, и адрес постоянны.

Синтаксис объявления C и C++ неоднократно описывался разработчиками как неудачный эксперимент.

Вместо этого давайте назовем тип "указатель на Type "; Я позвоню Ptr_:

template< class Type >
using Ptr_ = Type*;

Сейчас Ptr_<char> это указатель на char,

Ptr_<const char> это указатель на const char,

А также const Ptr_<const char> это const указатель на const char,

Там.

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

  • Вы часто передаете большие аргументы, такие как строки, как TYPE const & что предотвращает изменение или копирование объекта. Пример:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Но TYPE & const бессмысленно, потому что ссылки всегда постоянны.

  • Вы всегда должны маркировать методы класса, которые не изменяют класс как constв противном случае вы не можете вызвать метод из TYPE const & ссылка. Пример:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Есть общие ситуации, когда и возвращаемое значение, и метод должны быть постоянными. Пример:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

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

  • В результате часто приходится создавать как константный, так и неконстантный метод с использованием константной перегрузки. Например, если вы определите T const& operator[] (unsigned i) const;тогда вы, вероятно, также захотите неконстантную версию, представленную:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

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

Я нарисовал изображение ниже, чтобы объяснить это, может быть, полезно.

int const vа также const int vидентичны.

Константа с int с обеих сторон сделает указатель на константу int.

const int *ptr=&i;

или же

int const *ptr=&i;

const после ' * ' сделает константный указатель на int.

int *const ptr=&i;

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

 const int *ptr1=&i, *ptr2=&j;

В этом случае все являются указателями на постоянное целое число, а ptr2 является постоянным указателем на постоянное целое число. Но ptr1 не является постоянным указателем.

int const *ptr1=&i, *const ptr2=&j;
  • если constэто слева от*, это относится к значению (неважно, const int или int const)
  • если constнаходится справа от*, это относится к самому указателю
  • это может быть и то и другое одновременно

Важный момент: const int *p не означает, что значение, о котором вы говорите, является постоянным!!. Это означает, что вы не можете изменить его с помощью этого указателя (то есть вы не можете назначить $*p = ...`). Само значение может быть изменено другими способами. Например

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

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

В основном это касается второй строки: лучшие практики, назначения, параметры функций и т. Д.

Общая практика. Попробуй сделать все const что ты можешь. Или, говоря по-другому, сделай все const для начала, а затем удалить точно минимальный набор constНеобходимо, чтобы программа работала. Это будет большим подспорьем в достижении константности и поможет избежать появления незаметных ошибок, когда люди попытаются заняться вещами, которые они не должны изменять.

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

Что приводит очень аккуратно в назначениях. Вы можете назначить что-то, только если это неконстантно. Если вы хотите назначить что-то, что является постоянным, см. Выше. Помните, что в декларациях int const *foo; а также int * const bar; разные вещи const - другие ответы здесь освещают этот вопрос превосходно, поэтому я не буду вдаваться в подробности.

Параметры функции:

Передать по значению: например void func(int param) Вас не волнует, так или иначе, на вызывающем сайте. Можно привести аргумент, что есть варианты использования для объявления функции как void func(int const param) но это не влияет на вызывающего, только на саму функцию, поскольку любое значение, которое передается, не может быть изменено функцией во время вызова.

Передать по ссылке: например void func(int &param) Теперь это имеет значение. Как только что объявил func разрешено менять paramи любой вызывающий сайт должен быть готов справиться с последствиями. Изменение декларации на void func(int const &param) меняет договор и гарантирует, что func теперь не может измениться param, то есть то, что передано, это то, что вернется. Как уже отмечали другие, это очень полезно для дешевой передачи большого объекта, который вы не хотите менять. Передача ссылки намного дешевле, чем передача большого объекта по значению.

Передать по указателю: например void func(int *param) а также void func(int const *param) Эти два в значительной степени синонимичны с их ссылочными аналогами, с оговоркой, что вызываемая функция теперь должна проверить nullptr если какая-либо другая договорная гарантия не гарантирует func что он никогда не получит nullptr в param,

Часть мнения на эту тему. Доказать правильность в таком случае адски сложно, просто чертовски легко ошибиться. Так что не рискуйте, и всегда проверяйте параметры указателя на nullptr, Вы избавите себя от боли и страданий, и вам будет трудно найти ошибки в долгосрочной перспективе. А что касается стоимости проверки, то она очень дешевая, и в случаях, когда статический анализ, встроенный в компилятор, может ее контролировать, оптимизатор все равно ее исключит. Включите генерацию временного кода канала для MSVC или WOPR (я думаю) для GCC, и вы получите всю программу, то есть даже в вызовах функций, которые пересекают границу модуля исходного кода.

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

Никто не упомянул систему, лежащую в основе объявлений, на которую Керниган и Ритчи указали в своей книге C:

Объявления имитируют выражения.

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

Объявления имитируют выражения.

Объявления содержат те же операторы, что и выражения, в которых объявленный идентификатор может появиться позже, с тем же приоритетом, что и в выражениях. Вот почему «правило спирали по часовой стрелке» неверно: порядок вычислений строго определяется приоритетами операторов, при полном игнорировании левого, правого или направления вращения.

Вот несколько примеров в порядке возрастания сложности:

  • int i;: когда используется как есть, это выражение типа . Поэтому,i является внутр.
  • int *p;: когда разыменовывается с помощью , выражение имеет тип . Следовательно, это указатель на int.
  • const int *p;: когда разыменовывается с помощью , выражение имеет тип . Следовательно, это указатель на const int.
  • int *const p;: константа. Если это постоянное выражение разыменовано с помощью , выражение имеет тип . Следовательно, это константный указатель на int.
  • const int *const p;: константа. Если это постоянное выражение разыменовано с помощью*, выражение имеет типconst int. Поэтому,pявляется константным указателем на const int.

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

  • int a[3];: когда мы применяем оператор индексации массива к , результатом являетсяint. Следовательно, это массив int.
  • int *a[3];: Здесь оператор индексирования имеет более высокий приоритет, поэтому мы применяем его первым: Когда мы применяем оператор индексирования массива к , результатом являетсяint *. Следовательно, это массив указателей на int. Это не редкость.
  • int (*a)[3];: Здесь приоритет оператора переопределяется круглыми скобками, точно так же, как и в любом выражении. Следовательно, мы сначала разыменовываем . Теперь мы знаем, что это указатель на какой-то тип. , разыменованный указатель, является выражением этого типа. Когда мы применяем оператор индексации массива к , мы получаем простое целое число, что означает, что*aпредставляет собой массив из трех целых чисел, иaявляется указателем на этот массив. Это довольно редко встречается за пределами шаблонов C++, поэтому приоритеты операторов не подходят для этого случая. Обратите внимание, что использование такого указателя является моделью для его объявления:int i = (*a)[1];. Скобки обязательны для разыменования в первую очередь.
  • int (*a)[3][2];: ничто не мешает кому-либо иметь указатели на многомерные массивы, один случай, когда совет по круговой спирали по часовой стрелке становится очевидной ерундой.

В реальной жизни иногда встречаются указатели на функции. Нам также нужны круглые скобки, потому что оператор вызова функции (в C++, простое синтаксическое правило в C) имеет более высокий приоритет, чем разыменованиеoperator*(), опять же потому, что функции чаще возвращают указатели, чем указатели на функции:

  • int *f();: Сначала вызов функции, поэтомуfявляется функцией. Вызов должен быть разыменован, чтобы получить int, поэтому возвращаемое значение является указателем на int. Использование:int i = *f();.

  • int (*fp)();: Скобки изменяют порядок применения оператора. Поскольку мы должны сначала разыменовать, мы знаем, что это указатель на что-то. Поскольку мы можем применить оператор вызова функции к*fpмы знаем (в C), что это указатель на функцию; в C++ мы знаем только то, для чегоoperator()()определено. Поскольку вызов не принимает параметров и возвращает целое число,fpв C++ является указателем на функцию с такой сигнатурой. (В C пустой список параметров означает, что о параметрах ничего не известно, но будущие спецификации C могут запретить это устаревшее использование.)

  • int *(*fp)();: Конечно, мы можем возвращать указатели на int из функции, на которую указывает.

  • int (*(*fp)())[3];: сначала разыменовывается, следовательно, указатель; применить оператор вызова функции next, следовательно, указатель на функцию; снова разыменовать возвращаемое значение, следовательно, указатель на функцию, возвращающую указатель; примените к этому оператор индексации : указатель на функцию, возвращающую указатель на массив. Результатом является int, следовательно, указатель на функцию, возвращающую указатель на массив целых чисел.

    Все круглые скобки необходимы: как уже говорилось, мы должны отдавать приоритет разыменованию указателя функции с помощью(*fp) прежде чем что-либо еще произойдет. Очевидно, нам нужен вызов функции; а поскольку функция возвращает указатель на массив (а не на его первый элемент!), мы должны разыменовать его, прежде чем сможем его проиндексировать. Я признаю, что написал тестовую программу, чтобы проверить это, потому что я не был уверен, даже с помощью этого надежного метода ;-). Вот:

      #include <iostream>
using namespace std;

int (*f())[3]
{
  static int arr[3] = {1,2,3};
  return &arr;
}

int (*(*fp)())[3] = &f;

int main()
{
  for(int i=0; i<3; i++)
  {
    cout << (*(*fp)())[i] << endl;
  }
}

Обратите внимание, как красиво объявление имитирует выражение!

  1. const int* - указатель на константу int объект.

Вы можете изменить значение указателя; вы не можете изменить значениеint объект, на который указывает указатель.


  1. const int * const - постоянный указатель на константу int объект.

Вы не можете изменить ни значение указателя, ни значение int объект, на который указывает указатель.


  1. int const * - указатель на константу int объект.

Это утверждение эквивалентно 1. const int* - Вы можете изменить значение указателя, но не можете изменить значение int объект, на который указывает указатель.


Собственно, есть 4 вариант:

  1. int * const - постоянный указатель на int объект.

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


Если вы хотите определить определенный тип конструкции C или C++, вы можете использовать правило по часовой стрелке / спирали, разработанное Дэвидом Андерсоном; но не путать с Правилом Андерсона, сформулированным Россом Дж. Андерсоном, которое представляет собой нечто совершенно особенное.

Просто ради полноты для C, следуя другим объяснениям, не уверен для C++.

  • pp - указатель на указатель
  • р - указатель
  • данные - вещь указанная, в примерах x
  • полужирный - переменная только для чтения

Указатель

  • р данные - int *p;
  • р данные - int const *p;
  • р данные - int * const p;
  • р данные - int const * const p;

Указатель на указатель

  1. pp p data - int **pp;
  2. pp p data - int ** const pp;
  3. pp p data - int * const *pp;
  4. pp p data - int const **pp;
  5. pp p data - int * const * const pp;
  6. pp p data - int const ** const pp;
  7. pp p data - int const * const *pp;
  8. pp p data - int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

N-уровни разыменования

Просто продолжай, но пусть человечество отлучит тебя.

 int x = 10;
 int *p = &x;
 int **pp = &p;
 int ***ppp = &pp;
 int ****pppp = &ppp;

 printf("%d \n", ****pppp);

простая мнемоника:

type указатель <- * -> пуансон name


Мне нравится думать о int *iкак объявление "разыменования есть"; в этом смысле, const int *i означает "дереф i является const int", пока int *const i означает "deref of const i является int".

(единственная опасность подобного мышления заключается в том, что это может привести к предпочтению int const *i стиль объявления, который люди могут ненавидеть / запрещать)

Многие люди ответили правильно, я просто хорошо организую здесь и добавлю дополнительную информацию, которая отсутствует в данных ответах.

Const - это ключевое слово в языке C, также известное как квалификатор. Константа может применяться к объявлению любой переменной, чтобы указать, что ее значение не изменится.

      const int a=3,b;

a=4;  // give error
b=5;  // give error as b is also const int 

you have to intialize while declaring itself as no way to assign
it afterwards.

Как читать ?

просто читайте справа налево, каждое утверждение работает плавно

3 главные вещи

      type a.    p is ptr to const int

type b.    p is const ptr to int 
 
type c.    p is const ptr to const int

[Ошибка]

      if * comes before int 

Два типа

      1. const int *

2. const const int *

мы смотрим сначала

Основной тип 1. const int *

способов расставить 3 предмета в 3 местах 3! = 6

я. * в начале

      *const int p      [Error]
*int const p      [Error]

II. const в начале

      const int *p      type a. p is ptr to const int 
const *int p      [Error]

iii. int в начале

      int const *p      type a. 
int * const p     type b. p is const ptr to int

Основной тип 2. const const int*

способы расставить 4 предмета в 4 местах, в которых 2 одинаковые 4! / 2! = 12

я. * в начале

      * int const const p     [Error]
* const int const p     [Error]
* const const int p     [Error]
 

II. int в начале

      int const const *p      type a. p is ptr to const int
int const * const p     type c. p is const ptr to const int
int * const const p     type b. p is const ptr to int

iii. const в начале

      const const int *p     type a.
const const * int p    [Error]

const int const *p      type a.
const int * const p     type c.

const * int const p    [Error]
const * const int p    [Error]

сжимая все в одном

наберите "А. p - это ptr для const int (5)

      const int *p
int const *p

int const const *p
const const int  *p
const int  const *p

тип b. p - это const ptr для int (2)

      int * const p
int * const const p;

тип c. p равно const ptr в const int (2)

      int const * const p
const int * const p

просто небольшой расчет

      1. const int * p        total arrangemets (6)   [Errors] (3)
2. const const int * p  total arrangemets (12)  [Errors] (6)

немного экстра

int const * p, p2;

      here p is ptr to const int  (type a.) 
but p2 is just const int please note that it is not ptr

int * const p, p2;

      similarly 
here p is const ptr to int  (type b.)   
but p2 is just int not even cost int

int const * const p, p2;

      here p is const ptr to const int  (type c.)
but p2 is just const int. 

Законченный

Другие вопросы по тегам