указатели и оператор инкремента

У меня есть следующий простой код:

#include<iostream>

const char str[]={'C','+','+'};

int main()
{ 
  const char *cp=str;                     
  std::cout<<*str<<std::endl;

  while (*cp++>0)  
    std::cout<<*cp;
} 

не могу понять, почему он печатает

C
++

Разве оператор постфиксного приращения не должен оценивать выражение, но возвращать значение без изменений? (Я дважды проверил приоритет операторов приращения, разыменования и отношения, и он должен работать)


person Luca    schedule 30.07.2015    source источник
comment
Какой результат вы ожидаете?   -  person Petr    schedule 30.07.2015
comment
Я думаю, что я разыменовываю cp, прежде чем он будет увеличен. Поэтому я ожидаю, что он напечатает всю строку.   -  person Luca    schedule 30.07.2015
comment
Вы печатаете '\0' в поток cout. Это UB, как указано некоторыми людьми в этом вопросе.   -  person Mohit Jain    schedule 30.07.2015
comment
Поэтому я ожидаю, что он напечатает всю строку. Он печатает всю строку, просто вставляет дополнительную новую строку (и \0)   -  person Aaron McDaid    schedule 30.07.2015
comment
нет, потому что первый вызов cout не зависит от второго вызова. Возможно, мой код недостаточно ясен. Но я нашел свою ошибку, так что все равно спасибо.   -  person Luca    schedule 30.07.2015


Ответы (4)


Ваша проблема здесь:

while (*cp++>0)  
    std::cout<<*cp;

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

т. е. вы в настоящее время тестируете 'C', затем увеличиваете значение независимо от результата, затем печатаете '+' через теперь увеличенный указатель. Если бы он повторял строковый литерал, этот код также увеличивался бы один раз после достижения 0, хотя вы не видите результата этого, потому что он пропускает печать (потому что он выполняет итерацию по созданному вручную массиву без ограничителя null, что на самом деле здесь он падает с конца и демонстрирует неопределенное поведение; это само по себе большая ошибка, вы не можете полагаться на то, что в конце будет ноль, если его там не было).

person Leushenko    schedule 30.07.2015
comment
вау, да, я понял, первое приращение происходит независимо от того, что происходит в состоянии while .. большое спасибо! - person Luca; 30.07.2015

Эта строка печатает: C и возврат каретки.

std::cout<<*str<<std::endl;

Затем вы зацикливаетесь на следующих символах, но нет конечного символа (например, переполнение буфера)
Вот исправленный код.

#include <iostream>

const char str[]={'C','+','+', '\0'};

int main()
{ 
    const char* cp = str;                     
    std::cout<< *str << std::endl;

    while (*cp++ > 0)  
    std::cout << *cp;

    return 0;
}

Этот код еще проще, если вы хотите отобразить "C++"

#include <iostream>

const char str[]={'C','+','+', '\0'};

int main()
{ 
    const char* cp = str;                     

    while (*cp > 0)
        std::cout << *cp++;

    std::cout << std::endl;

    return 0;
}
person Richard Dally    schedule 30.07.2015
comment
Еще проще: std::cout << str << '\n'; - person Konrad Rudolph; 30.07.2015

не должен ли оператор приращения постфикса оценивать выражение, но возвращать значение без изменений?

Нет, постфиксный оператор сначала возвращает значение операнда, только потом оно увеличивается на 1.

здесь,

while (*cp++>0)  
    std::cout<<*cp;

к тому времени, когда он достигает std::cout<<*cp;, значение cp увеличивается, и, следовательно, результат ++.

person Nishant    schedule 30.07.2015
comment
Это именно то, что сказал ОП. - person Konrad Rudolph; 30.07.2015
comment
возвращает значение без изменений?? В самом деле? - person Nishant; 30.07.2015
comment
@luca *cp++ › 0 сначала оценит выражение, *cp > 0 затем увеличит указатель cp++ - person Nishant; 30.07.2015
comment
Ну да: «сначала возвращает значение [затем увеличивает его]» и «возвращает значение без изменений» на самом деле синонимы. - person Konrad Rudolph; 30.07.2015
comment
неизменный означает, что на самом деле он никогда не меняется, что неверно. Я бы предпочел вернуть исходное значение. Это подчеркивает, что cp действительно меняется. - person Aaron McDaid; 30.07.2015
comment
@KonradRudolph Да, вот почему мой комментарий о том, что он увеличивается после оценки выражения из-за этого неизмененного слова. - person Nishant; 30.07.2015

В соответствии

while(*cp++>0)

Оператор постинкремента выполняется после того, как произойдет оценка.

то есть cp указывает на C во время первой оценки условия while.

So,

*cp => 'C' which is greater than 0.

Перед переходом к следующей строке (внутри цикла) выполняется оператор постинкремента, в результате чего cp указывает на первый +

После того, как + напечатано, снова выполняется условие while, на этот раз *cp возвращает '+'. начиная с '+' > 0 управление входит в цикл во второй раз.

Перед входом в цикл оператор постинкремента выполняется снова, заставляя cp указывать на второй «+», который печатается.

Теперь, пока условие выполняется в третий раз. Здесь *cp возвращает +. Таким образом, управление снова входит в цикл.

Перед входом в цикл постинкремент выполняется снова. На этот раз он указывает cp на следующий символ, то есть на \0.

Печатается \0, что не имеет значения в этом коде. Затем, когда условие while выполняется снова, *cp возвращает \0, что не > 0. Таким образом, условие не выполняется.

Редактировать. Увидел в комментариях, что вы хотели напечатать всю строку в одной строке. Измените цикл на:

while(*cp > 0)
    std:cout<<*cp++;
person Aswin Murugesh    schedule 30.07.2015