Разница между сообщением и предварительным уменьшением значения указателя символа в функции c putchar

У меня есть следующий код на C (я использую tdm-gcc 4.9.1 и Netbeans 8.0.2):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char * pr(char * str);

int main(void)
{
    char * x;

    x = pr("Ho Ho Ho!");

    return 0;
}

//*************************************

char * pr(char * str)
{
    char * pc;

    pc = str;

    while (* pc)
    {
        putchar(* pc++);
        printf(" %d %d\n", pc, str);
    }

    printf("\n");
    printf(" %d %d\n", pc, str);  
    printf("\n");

    do 
    {
        putchar(* pc--); // alternate case: * --pc
        printf(" %d %d\n", pc, str);
    } while (pc - str);

    return (pc);
}

В цикле do-while, когда аргумент внутри функции putchar

* pc--

У меня напечатан следующий результат (1-й столбец печатает строку «Хо-хо-хо!», по одному символу за раз, 2-й столбец печатает адрес указателя на char pc, тогда как 3-й столбец печатает адрес указателя на char str :

H 4206629 4206628
o 4206630 4206628
  4206631 4206628
H 4206632 4206628
o 4206633 4206628
  4206634 4206628
H 4206635 4206628
o 4206636 4206628
! 4206637 4206628

 4206637 4206628

 4206636 4206628
! 4206635 4206628
o 4206634 4206628
H 4206633 4206628
  4206632 4206628
o 4206631 4206628
H 4206630 4206628
  4206629 4206628
o 4206628 4206628

or

Ho Ho Ho!!oH oH o

Когда аргумент внутри функции putchar

* --pc

Соответствующий результат

H 4206629 4206628
o 4206630 4206628
  4206631 4206628
H 4206632 4206628
o 4206633 4206628
  4206634 4206628
H 4206635 4206628
o 4206636 4206628
! 4206637 4206628

 4206637 4206628

! 4206636 4206628
o 4206635 4206628
H 4206634 4206628
  4206633 4206628
o 4206632 4206628
H 4206631 4206628
  4206630 4206628
o 4206629 4206628
H 4206628 4206628

or

Ho Ho Ho!!oH oH oH

Мой вопрос заключается в следующем: в чем разница между постфиксным и префиксным оператором декремента в отношении вывода функции putchar внутри цикла do-while?

Любая обратная связь будет принята с благодарностью.


person Urovoros Ofis    schedule 25.09.2015    source источник
comment
Не имеет отношения к вашему вопросу, но если вы хотите напечатать указатель с printf, вы следует использовать формат "%p".   -  person Some programmer dude    schedule 25.09.2015
comment
Выведите адреса типа: printf(" %p %p\n", (void*) pc, (void*) str); иначе вы получите UB   -  person Giorgi Moniava    schedule 25.09.2015


Ответы (1)


Ответ на ваш вопрос содержится в названиях: префикс делает что-то до, а постфикс что-то делает после.

Короче:

  • Инкремент/декремент префикса выполняет инкремент/декремент before, давая вам результат этого инкремента/декремента.
  • Инкремент/декремент постфикса дает вам старое значение, а затем выполняет инкремент/декремент.

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


Допустим, у вас есть строка

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

затем делать

*++p

увеличит указатель p (чтобы он указывал на символ 'e' в строке), а затем разыменует этот указатель, дав вам символ 'e'.

Если вы затем сделаете

*p--

затем указатель сначала разыменовывается, и вы получаете символ 'e' (снова), а затем указатель уменьшается и снова указывает на первый символ.


Используя ваш новый пример в комментарии, оператор putchar(*++string); эквивалентен

string = string + 1;
putchar(*string);

А оператор putchar(*string++); эквивалентен

char *compiler_generated_temporary_variable = string;
string = string + 1;
putchar(*compiler_generated_temporary_variable);

Обратите внимание на порядок, в котором выполняется приращение.

person Some programmer dude    schedule 25.09.2015
comment
Спасибо за ответ. Я новичок в C, поэтому я использую спецификатор %d для печати указателей, чтобы легче отслеживать процесс уменьшения. Я понимаю, как работают префикс и постфикс, но я не понимаю, как они влияют на результат функции putchar, которую я упомянул в своем вопросе. В случае префикса ! символ соответствует адресу 4206636, тогда как в постфиксном аналоге указатель уменьшается до адреса 4206636, как и ожидалось, но ! символ печатается рядом с адресом 4206635. - person Urovoros Ofis; 25.09.2015
comment
Этот поток - stackoverflow.com/questions/5209602/ - дает некоторое представление, но проблема сбивает с толку, особенно учитывая нерешенный приоритет задействованных операторов в упомянутой настройке. - person Urovoros Ofis; 31.10.2018
comment
@UrovorosOfis Как я уже объяснял в своем ответе, *++string изменит указатель first перед разыменованием. И *string++ изменит указатель after. Обновленный ответ с пояснениями к вашему последнему примеру. - person Some programmer dude; 31.10.2018
comment
если бы я должен был напечатать строку I am I с помощью функции, использующей putchar(*string++), я бы получил I am I. Но с putchar(*++string) я получил бы I. Почему опущен только первый символ? - person Urovoros Ofis; 31.10.2018
comment
@UrovorosOfis Опять же, приращение префикса изменяет указатель перед разыменованием, поэтому он пропускает первый символ. Вы даже не удосужились прочитать мой ответ, особенно последнее обновление? - person Some programmer dude; 31.10.2018
comment
Хорошо, теперь я понимаю, что меня беспокоило, так это приоритет оператора (en.cppreference.com/ w/c/language/operator_precedence) постфикса (++) по сравнению с оператором разыменования (*) в *string++ - person Urovoros Ofis; 31.10.2018
comment
@UrovorosOfis Ну хорошо. Тогда извините за грубость, и мне, наверное, стоило поднять этот вопрос раньше. - person Some programmer dude; 31.10.2018