Выражения-указатели: * ptr ++, * ++ ptr и ++ * ptr


128

Недавно я столкнулся с этой проблемой, которую сам не могу понять.

Что ДЕЙСТВИТЕЛЬНО означают эти три выражения ?

*ptr++
*++ptr
++*ptr

Я пробовал Ричи. Но, к сожалению, не смог уследить за тем, что он рассказал об этих трех операциях.

Я знаю, что все они выполняются для увеличения указателя / значения, на которое указывает. Я также могу предположить, что может быть много вещей о приоритете и порядке оценки. Как один сначала увеличивает указатель, а затем извлекает содержимое этого указателя, один просто извлекает контент, а затем увеличивает указатель и т.д. и т.д. Как вы можете видеть, у меня нет четкого понимания их фактических операций, которые я хотел бы очистить как можно скорее. Но я действительно теряюсь, когда получаю возможность применять их в программах. Например:

int main()
{
    const char *p = "Hello";
    while(*p++)
         printf("%c",*p);
    return 0;
}

дает мне этот результат:

ello

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


6
Вы пропустили четвертый: (*ptr)++(круглые скобки необходимы для устранения неоднозначности *ptr++)
user4815162342

15
Потому что вы увеличили указатель перед его печатью. Вы хотели while (* p) и printf ("% c", * p ++);
dcaswell

Отличные вопросы для собеседования. Ограниченное практическое использование. Я бы хотел, чтобы у C не было этих указателей :)
Химаншу

5
@Himanshu Если это запекло вашу собеседника, попробуйте следующее: Имейте глобальный указатель char* p, указывающий на действительную завершенную строку уникальных символов. Тогда есть функция , fn(char ch)которая печатает какch параметр и текущий символ , на который указывает p. Теперь вызовите fn(*p++);Q: Печатает ли один и fnтот же символ дважды ? Вы будете удивлены, сколько профессоров неправильно задают этот вопрос.
WhozCraig

1
поскольку p указывает на строковый литерал, который вы должны написатьconst char* p = "Hello";
hetepeperfan

Ответы:


275

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

int main()
{
    const char *p = "Hello";
    while(*p++)
        printf("%c",*p);
    return 0;
}

Первое утверждение:

const char* p = "Hello";

объявляется pкак указатель на char. Когда мы говорим «указатель на объект char», что это означает? Это означает, что значение pявляется адресом a char; pсообщает нам, где в памяти есть место для храненияchar .

Оператор также инициализируется, pчтобы указать на первый символ в строковом литерале "Hello". Ради этого упражнения, важно понять , pкак указывает не на всю строку, но только на первый символ, 'H'. В конце концов, pэто указатель на одну char, а не на всю строку. Значение p- это адрес 'H'в"Hello" .

Затем вы настраиваете цикл:

while (*p++)

Что означает условие цикла *p++? Здесь работают три вещи, которые делают это озадачивающим (по крайней мере, до тех пор, пока не начнется знакомство):

  1. Приоритет двух операторов, постфикса ++и косвенного обращения*
  2. Значение выражения приращения постфикса
  3. Побочный эффект выражения приращения постфикса

1. Приоритет . Быстрый взгляд на таблицу приоритетов операторов покажет вам, что приращение постфикса имеет более высокий приоритет (16), чем разыменование / косвенное обращение (15). Это означает , что комплексное выражение *p++собирается быть сгруппированы следующим образом: *(p++). Другими словами, *часть будет применена к стоимости p++части. Итак, давайте p++сначала возьмем часть.

2. Значение постфиксного выражения . Значение p++- это значение p до приращения . Если у вас есть:

int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);

вывод будет:

7
8

потому что i++оценивается iдо приращения. Аналогично p++будет оцениваться текущее значение p. Как известно, текущее значение p- это адрес 'H'.

Итак, теперь p++часть *p++была оценена; это текущее значение p. Затем *происходит часть. *(current value of p)означает: получить доступ к значению по адресу p. Мы знаем, что значение по этому адресу равно 'H'. Таким образом, выражение *p++оценивается как 'H'.

Вы говорите, подождите минутку. Если *p++оценивается как 'H', почему это не 'H'печатается в приведенном выше коде? Вот тут и проявляются побочные эффекты .

3. Побочные эффекты выражения Postfix . Постфикс ++имеет значение текущего операнда, но имеет побочный эффект увеличения этого операнда. А? Взгляните еще раз на этот intкод:

int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);

Как отмечалось ранее, результат будет следующим:

7
8

Когда i++оценивается в первом printf(), он оценивает до 7. Но стандартные гарантии C , что в какой - то момент перед вторым printf()начинает выполнение команд, побочный эффект от ++оператора будет иметь место. То есть до того, как printf()произойдет второе , iбудет увеличено в результате действия ++оператора в первом printf(). Это, кстати, одна из немногих гарантий, которые стандарт дает о времени появления побочных эффектов.

Тогда в вашем коде, когда выражение *p++оценивается, оно оценивается как 'H'. Но к тому времени, когда вы дойдете до этого:

printf ("%c", *p)

этот неприятный побочный эффект произошел. pбыл увеличен. Вау! Он больше не указует на 'H', но один символ прошлым 'H': к 'e', других слова. Это объясняет ваш нелепый результат:

ello

Отсюда хор полезных (и точных) предложений в других ответах: чтобы распечатать полученное произношение, "Hello"а не его копию кокни, вам нужно что-то вроде

while (*p)
    printf ("%c", *p++);

Вот и все. А как насчет остальных? Вы спрашиваете о значении этих слов:

*ptr++
*++ptr
++*ptr

Мы только что говорили о первом, поэтому давайте посмотрим на вторую: *++ptr .

В нашем предыдущем объяснении мы видели, что у постфиксного приращения p++есть определенный приоритет , значение и побочный эффект . Приращение префикса ++pимеет тот же побочный эффект, что и его постфиксный аналог: он увеличивает свой операнд на 1. Однако у него другой приоритет и другое значение .

Приращение префикса имеет более низкий приоритет, чем постфикс; он имеет приоритет 15. Другими словами, он имеет тот же приоритет, что и оператор разыменования / косвенного обращения *. В таком выражении, как

*++ptr

не имеет значения приоритет: два оператора идентичны по приоритету. Таким образом, вступает в силу ассоциативность . Приращение префикса и оператор косвенного обращения имеют право-левую ассоциативность. Из-за этой ассоциативности операнд ptrбудет сгруппирован с самым правым оператором ++перед оператором, расположенным левее *,. Другими словами, выражение будет сгруппировано *(++ptr). Итак, как и в случае, *ptr++но по другой причине, здесь тоже *часть будет применяться к значению++ptr части.

Так что это за ценность? Значение выражения приращения префикса - это значение операнда после приращения . Это сильно отличает его от постфиксного оператора приращения. Допустим, у вас есть:

int i = 7;
printf ("%d\n", ++i);
printf ("%d\n", i);

Результатом будет:

8
8

... отличается от того, что мы видели с оператором postfix. Аналогично, если у вас есть:

const char* p = "Hello";
printf ("%c ", *p);    // note space in format string
printf ("%c ", *++p);  // value of ++p is p after the increment
printf ("%c ", *p++);  // value of p++ is p before the increment
printf ("%c ", *p);    // value of p has been incremented as a side effect of p++

вывод будет:

H e e l                // good dog

Вы понимаете почему?

Теперь мы переходим к третьему выражению вы спросили о, ++*ptr. На самом деле это самая сложная из всех. Оба оператора имеют одинаковый приоритет и ассоциативность справа и слева. Это означает, что выражение будет сгруппировано ++(*ptr). ++Часть будет применяться к значению *ptrчасти.

Итак, если у нас есть:

char q[] = "Hello";
char* p = q;
printf ("%c", ++*p);

удивительно эгоистичный результат будет:

I

Какой?! Итак, *pчасть будет оценивать 'H'. Затем ++вступает в игру, и в этот момент он будет применен к 'H', а не к указателю! Что происходит, когда вы добавляете 1 к 'H'? Вы получите 1 плюс значение ASCII 'H'72; вы получаете 73. Представьте , что , как char, и вы получите charсо значением ASCII 73: 'I'.

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

(*ptr)++ 

Это тоже интересно. Если у вас есть:

char q[] = "Hello";
char* p = q;
printf ("%c", (*p)++);
printf ("%c\n", *p);

он даст вам такой восторженный результат:

HI

В чем дело? Опять же, это вопрос приоритета , значения выражения и побочных эффектов . Из-за скобок *pчасть рассматривается как основное выражение. Первичные выражения важнее всего остального; они оцениваются первыми. И *p, как известно, оценивает 'H'. Остальная часть выражения, ++часть, применяется к этому значению. Итак, в этом случае (*p)++становится 'H'++.

В чем ценность 'H'++? Если вы сказали 'I', вы забыли (уже!) Наше обсуждение значения и побочного эффекта с постфиксным приращением. Помните, 'H'++оценивает текущее значение 'H' . Итак, это сначала printf()будет напечатано 'H'. Затем, как побочный эффект , это 'H'значение будет увеличено до 'I'. Второй printf()печатает это 'I'. И тебе радостное приветствие.

Хорошо, но в последних двух случаях зачем мне

char q[] = "Hello";
char* p = q;

Почему я не могу просто что-то вроде

/*const*/ char* p = "Hello";
printf ("%c", ++*p);   // attempting to change string literal!

Потому "Hello"что это строковый литерал. Если вы попытаетесь ++*p, вы попытаетесь изменить 'H'в строке на 'I', создав всю строку "Iello". В C строковые литералы доступны только для чтения; попытка изменить их вызывает неопределенное поведение. "Iello"также не определено в английском языке, но это просто совпадение.

И наоборот, у вас не может быть

char p[] = "Hello";
printf ("%c", *++p);  // attempting to modify value of array identifier!

Почему нет? Потому что в данном случае pэто массив. Массив не является изменяемым l-значением; вы не можете изменить положение pточек с помощью пре- или пост-инкремента или декремента, потому что имя массива работает так, как будто это постоянный указатель. (На самом деле это не так; это просто удобный способ взглянуть на это.)

Подводя итог, вот три вещи, о которых вы спрашивали:

*ptr++   // effectively dereferences the pointer, then increments the pointer
*++ptr   // effectively increments the pointer, then dereferences the pointer
++*ptr   // effectively dereferences the pointer, then increments dereferenced value

И вот четвертый, не менее интересный, чем остальные три:

(*ptr)++ // effectively forces a dereference, then increments dereferenced value

Первый и второй вызовут сбой, если ptrна самом деле это идентификатор массива. Третий и четвертый будут аварийно завершены, если будут указывать ptrна строковый литерал.

Вот и все. Надеюсь, теперь все кристально. Вы были прекрасной публикой, и я буду здесь всю неделю.


22
Перед тем, как зайти на этот форум, я просмотрел 3 книги «С», которые у меня есть. Я также попробовал несколько известных онлайн-руководств. Но ни один из них не подходит к вашему объяснению (особенно то, как вы все это собрали). Вы не только ответили на вопрос, который я задал, но и обсудили намного больше вещей на низовом уровне. На самом деле, сегодня вы научили меня многому, чего мне не хватало раньше. Я не мог не переключить свой принятый ответ. :) Еще раз спасибо.
размещено

26
+1 Думаю, это лучший длинный ответ, который я читал на SO. Думаю, каждый может многому научиться из этого ответа.
Шафик Ягмур

9
Вы, сэр, должны написать книгу о С.
Диллон Бертон

1
Какой красивый ответ на хороший вопрос! Молодец @verbose!
benka 02

7
@verbose вам , сэр, жил до вашего имени .. :)
sleeping_dragon

44

Допустим, ptrуказывает на i-й элемент массива arr.

  1. *ptr++вычисляет arr[i]и устанавливает, ptrчтобы указать на (i + 1) -й элемент arr. Это эквивалентно *(ptr++).

  2. *++ptrустанавливает, ptrчтобы указать на (i + 1) -й элемент arrи вычисляет значение arr[i+1]. Это эквивалентно *(++ptr).

  3. ++*ptrувеличивается arr[i]на единицу и оценивается в увеличенное значение; указатель ptrостается нетронутым. Это эквивалентно ++(*ptr).

Есть еще один, но для его написания понадобятся круглые скобки:

  1. (*ptr)++увеличивается arr[i]на единицу и оценивается до своего значения перед увеличением; указатель ptrснова остается нетронутым.

В остальном вы сможете разобраться сами; на него также ответил @Jaguar.


13

*ptr++ : post increment a pointer ptr

*++ptr : Pre Increment a pointer ptr

++*ptr : preincrement the value at ptr location

Прочтите здесь об операторах пре-инкремента и пост-инкремента.


Это даст Helloкак результат

int main()
{
    const char *p = "Hello";
    while(*p)
         printf("%c",*p++);//Increment the pointer here 
    return 0;
}

@ Nik-Lz Да, результат будетHello
Jainendra

7

Состояние вашего цикла плохое:

while(*p++)
    printf("%c",*p);

Такой же как

while(*p)
{
    p++;
    printf("%c",*p);
}

А это неправильно, это должно быть:

while(*p)
{
    printf("%c",*p);
    p++;
} 

*ptr++то же самое *(ptr++), что и:

const char  *ptr = "example";
char  value;

value = *ptr;
++ptr;
printf("%c", value); // will print 'e'

*++ptrто же самое *(++ptr), что и:

const char  *ptr = "example";
char  value;

++ptr;
value = *ptr;
printf("%c", value); // will print 'x'

++*ptrто же самое ++(*ptr), что и:

const char  *ptr = "example";
char  value;

value = *ptr;
++value;
printf("%c", value); // will print 'f' ('e' + 1)

Абсолютно согласен с первой частью ответа. Во второй части инициализация указателей (на целые числа!) Целыми числами сбивает с толку тех, кто пытается понять использование указателей.
Nickie

4

Вы правы относительно приоритета, обратите внимание, что *имеет приоритет над приращением префикса, но не над приращением постфикса. Вот как эти поломки:

*ptr++ - переход слева направо, разыменование указателя, а затем увеличение значения указателя (не то, на что он указывает, из-за приоритета постфикса над разыменованием)

*++ptr - увеличить указатель, а затем разыменовать его, это потому, что префикс и разыменование имеют одинаковый приоритет и поэтому они оцениваются в порядке справа налево

++*ptr- аналогично приведенному выше с точки зрения приоритета, снова идя справа налево, чтобы разыменовать указатель, а затем увеличить то, на что указывает указатель. Обратите внимание, что в вашем случае это приведет к неопределенному поведению, потому что вы пытаетесь изменить переменную только для чтения ( char* p = "Hello";).


3

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

 v = *ptr++

средства

 temp = ptr;
 ptr  = ptr + 1
 v    = *temp;

В то время как

 v = *++ptr

средства

 ptr = ptr + 1
 v   = *ptr

Важно понимать, что пост-инкремент (и пост-декремент) означает

 temp = ptr       // Temp created here!!!
 ptr  = ptr + 1   // or - 1 if decrement)
 v    = *temp     // Temp destroyed here!!!

Почему это имеет значение? Что ж, в C это не так важно. В C ++ же ptrможет быть сложный тип, такой как итератор. Например

 for (std::set<int>::iterator it = someSet.begin(); it != someSet.end(); it++)

В этом случае, поскольку itэто сложный тип, it++могут возникнуть побочные эффекты из-за tempсоздания. Конечно, если вам повезет, компилятор попытается выбросить ненужный код, но если конструктор или деструктор итератора что-то сделает, он it++покажет эти эффекты при создании temp.

Я пытаюсь сказать вкратце: « Напиши, что имеешь в виду» . Если вы имеете в виду инкремент ptr, то ++ptrне пишите ptr++. Если вы имеете в виду temp = ptr, ptr += 1, tempто напишитеptr++


0
*ptr++    // 1

Это то же самое, что:

    tmp = *ptr;
    ptr++;

Таким образом, значение объекта, на который указывает, ptrизвлекается, а затем ptrувеличивается.

*++ptr    // 2

Это то же самое, что:

    ++ptr;
    tmp = *ptr;

Таким образом, указатель ptrувеличивается, затем ptrсчитывается объект, на который указывает .

++*ptr    // 3

Это то же самое, что:

    ++(*ptr);

Таким образом, объект, на который указывает, ptrувеличивается; ptrсам по себе неизменен.


0

постфикс и префикс имеют более высокий приоритет, чем разыменование, поэтому

* ptr ++ здесь post increment ptr, а затем указание на новое значение ptr

* ++ ptr здесь Pre Increment кулак, затем указывающий на новое значение ptr

++ * ptr здесь сначала получает значение ptr, указывающее на и увеличивающее это значение vlaue


1
Это неверно. Postfix имеет более высокий приоритет, но префикс имеет тот же приоритет, что и разыменование.
подробный

0

Выражения указателя: * ptr ++, * ++ ptr и ++ * ptr:

Примечание : указатели должны быть инициализированы и иметь действительный адрес. Потому что в ОЗУ, помимо нашей программы (a.out), одновременно работает намного больше программ, т.е. если вы попытаетесь получить доступ к некоторой памяти, которая не была зарезервирована для вас, ОС будет через ошибку сегментации.

Прежде чем объяснять это, давайте рассмотрим простой пример?

#include<stdio.h>
int main()
{
        int num = 300;
        int *ptr;//uninitialized pointer.. must be initialized
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr = *ptr + 1;//*ptr means value/data on the address.. so here value gets incremented
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        /** observe here that "num" got changed but manually we didn't change, it got modified by pointer **/
        ptr = ptr + 1;//ptr means address.. so here address got incremented
        /**     char pointer gets incremented by 1 bytes
          Integer pointer gets incremented by 4 bytes
         **/
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

проанализируйте вывод вышеуказанного кода, я надеюсь, вы получили вывод вышеуказанного кода. Из приведенного выше кода ясно одно: имя указателя ( ptr ) означает, что мы говорим об адресе, а * ptr означает, что мы говорим о значении / данных.

СЛУЧАЙ 1 : * ptr ++, * ++ ptr, * (ptr ++) и * (++ ptr):

Вышеупомянутые все 4 синтаксиса во всем похожи, address gets incrementedно то, как увеличивается адрес, отличается.

Примечание : для решения любого выражения узнайте, сколько операторов в выражении, затем выясните приоритеты операторов. Если несколько операторов имеют одинаковый приоритет, затем проверяют порядок эволюции или ассоциативности, который может быть справа (R) налево (L) или слева направо.

* ptr ++ : здесь есть 2 оператора, а именно de-reference (*) и ++ (приращение). Оба имеют одинаковый приоритет, затем проверяют ассоциативность, которая является R к L. Итак, начинайте решение справа налево, какие бы операторы ни появлялись раньше.

* ptr ++ : первый ++ появился при решении от R до L, поэтому адрес увеличивается, но увеличивается его пост.

* ++ ptr : То же, что и первый, здесь также адрес увеличивается, но до его увеличения.

* (ptr ++) : Здесь есть 3 оператора, среди которых grouping () имеет наивысший приоритет. Итак, первый ptr ++ решен, т.е. адрес увеличивается, но публикуется.

* (++ ptr) : То же, что и в предыдущем случае, здесь также адрес увеличивается, но предварительно.

СЛУЧАЙ 2 : ++ * ptr, ++ (* ptr), (* ptr) ++:

Вышеупомянутые все 4 синтаксиса похожи, все значение / данные увеличиваются, но то, как значение изменяется, отличается.

++ * ptr : first * возник при решении от R до L, поэтому значение изменяется, но его предварительное приращение.

++ (* ptr) : То же, что и в предыдущем случае, значение изменяется.

(* ptr) ++ : Здесь есть 3 оператора, среди них grouping () с наивысшим приоритетом, есть Inside () * ptr, поэтому сначала решается * ptr, т.е. значение увеличивается, но post.

Примечание : ++ * ptr и * ptr = * ptr + 1 одинаковы, в обоих случаях значение изменяется. ++ * ptr: используется только 1 инструкция (INC), значение изменяется за один раз. * ptr = * ptr + 1: здесь первое значение увеличивается (INC), а затем присваивается (MOV).

Чтобы понять все вышеупомянутые разные синтаксисы приращения указателя, рассмотрим простой код:

#include<stdio.h>
int main()
{
        int num = 300;
        int *ptr;
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//address changed(post increment), value remains un-changed
//      *++ptr;//address changed(post increment), value remains un-changed
//      *(ptr)++;//address changed(post increment), value remains un-changed
//      *(++ptr);//address changed(post increment), value remains un-changed

//      ++*ptr;//value changed(pre increment), address remains un-changed
//      (*ptr)++;//value changed(pre increment), address remains un-changed
//      ++(*ptr);//value changed(post increment), address remains un-changed

        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

В приведенном выше коде попробуйте комментировать / не комментировать комментарии и анализировать результаты.

Указатели как константы : не существует способов сделать указатели постоянными, некоторые из них я здесь упоминаю.

1) Const INT * р OR ИНТ сопз * р : Здесь valueесть константа , адрес не постоянен т.е. где р указывает? Какой-то адрес? Какова стоимость по этому адресу? Какая-то ценность, верно? Это значение является постоянным, вы не можете изменить это значение, но куда указывает указатель? Какой-то адрес верно? Он также может указывать на другой адрес.

Чтобы понять это, давайте рассмотрим код ниже:

#include<stdio.h>
int main()
{
        int num = 300;
        const int *ptr;//constant value, address is modifible
        ptr = &num;
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//
//      *++ptr;//possible bcz you are trying to change address which is possible
//      *(ptr)++;//possible
//      *(++ptr);//possible

//      ++*ptr;//not possible bcz you trying to change value which is not allowed
//      (*ptr)++;//not possible
//      ++(*ptr);//not possible

        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

Попробуйте проанализировать вывод вышеуказанного кода

2) int const * p : он называется ' **constant pointe**r' ie address is constant but value is not constant. Здесь вам не разрешено изменять адрес, но вы можете изменить значение.

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

Чтобы понять это, давайте проверим простой код.

#include<stdio.h>
int main()
{
        int x = 300;
        int* const p;
        p = &x;
        printf("x = %d p =%p and *p = %d\n",num,p,*p);
}

В приведенном выше коде, если вы заметили, что нет ++ * p или * p ++. Итак, вы можете подумать, что это простой случай, потому что мы не меняем адрес или значение, но это приведет к ошибке. Зачем ? Причину я упоминаю в комментариях.

#include<stdio.h>
int main()
{
        int x = 300;
        /** constant pointer must initialize while decaring itself **/
        int* const p;//constant pointer i.e its pointing to some address(here its pointing to garbage), it should point to same address(i.e garbage ad
dress only 
        p = &x;// but here what we are doing ? we are changing address. we are making p to point to address of x instead of garbage address.
        printf("x = %d p =%p and *p = %d\n",num,p,*p);
}

Так каково же решение этой проблемы?

     int* const p = &x;

Чтобы узнать больше об этом случае, рассмотрим пример ниже.

#include<stdio.h>
int main()
{
        int num = 300;
        int *const ptr = &num;//constant value, address is modifible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//not possible
//      *++ptr;//not possible bcz you are trying to change address which is not possible
//      *(ptr)++;//not possible
//      *(++ptr);//not possible

//      ++*ptr;// possible bcz you trying to change value which is allowed
//      (*ptr)++;// possible
//      ++(*ptr);// possible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

3) const int * const p : здесь и адрес, и значение постоянны .

Чтобы понять это, давайте проверим код ниже

#include<stdio.h>
int main()
{
        int num = 300;
        const int* const ptr = &num;//constant value,constant address 
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
        *ptr++;//not possible
        ++*ptr;//not possible
        printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}

-1
const char *p = "Hello";   

*p means "Hello"
          ^
          | 
          p

*p++ means "Hello"
             ^
             | 
             p

*++p means "Hello"
            ^
            |     (WHILE THE STATEMENT IS EXECUTED)
            p

*++p means "Hello"
             ^
             |     (AFTER THE STATEMENT IS EXECUTED)
             p

++*pозначает, что вы пытаетесь увеличить значение ASCII, для *pкоторого

   is "Hello"
       ^
       | 
       p

вы не можете увеличивать значение, потому что это константа, поэтому вы получите ошибку

что касается вашего цикла while, цикл выполняется до тех пор, пока не *p++достигнет конца строки, где есть '\0'символ (NULL).

Теперь, поскольку *p++пропускается первый символ, вы получите результат, начиная со второго символа.

Следующий код ничего не выведет, потому что цикл while имеет '\0'

const char *p = "Hello";
    while('\0') 
         printf("%c",*p);

Следующий код даст вам тот же результат, что и следующий код, то есть ello.

const char *p = "Hello";
    while(*++p)
         printf("%c",*p);

...................................

const char *p = "Hello";
    while(*p++)
         printf("%c",*p);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.