2016-03-21 1 views
-4
int main(){ 
    char* str="Hello"; 
    // str: 0x4006db, *str++: l, str: 0x4006db, *str++: e, str: 0x4006db, *str++: H 
    printf("str: %p, *str++: %c, str: %p, *str++: %c, str: %p, *str++: %c\n", str, *str++, str, *str++, str, *str++); 
} 

Я надеюсь, что это не еще один глупый вопрос:Ценность полукокса PTR не изменяется после приращения ++

  1. Почему значение указателя ул не изменилась после того, как я увеличивается его *str++ ?

  2. Если значение str указателя не изменилось, каждый раз, когда я делаю *str++ я должен дать такое же значение, а не, leH.

  3. Почему появляется сообщение l, а не H?

Btw, я также посмотрел на стоимость &str, это то же самое до и после того, как я сделал *str++.

Любая помощь будет очень признательна. Благодаря

+1

У вас есть неопределенное поведение. –

+1

В 'str ++' ++ является POST-приращением. Таким образом, он передает '* str' в printf и только затем увеличивает 'str' (теперь он укажет на следующий символ). И параметры оцениваются справа налево. –

+1

«Надеюсь, это не другой глупый вопрос» - ну, к сожалению ... –

ответ

2

Вы вызывается неопределенное поведение по:

  1. Изменение строкового литерала.
  2. Печать указателя без литья до (void *).
  3. Изменение одного и того же объекта многократно между двумя точками последовательности.

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

Вызов одного неопределенное поведение является фатальным, что означает, что все от него работает должным образом, как вы хотите, чтобы уничтожить мир может случиться, и вы вызвали три :(

Смотрите также:

http://www.c-faq.com/expr/evalorder2.html

http://www.c-faq.com/expr/comma.html

0

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

/* 
* 36130330_main.c 
*/ 
#include <stdio.h> 
#include <string.h> 

unsigned int main 
    (
    unsigned int argc, 
    unsigned char *arg[] 
    ) 
{ 
    unsigned char *str="Hello"; 
    unsigned char *ptr_ucW0; 

    printf("\n"); 
    printf(" Set ptr_ucW0 = str\n"); 
    ptr_ucW0 = str; 
    printf(" Text   Address  Text    Value\n"); 
    printf(" str  :  %p  *str   :  %c\n", str, *str); 
    printf(" str + 1 :  %p  *(str + 1) :  %c\n", str + 1, *(str + 1)); 
    printf(" str + 2 :  %p  *(str + 2) :  %c\n", str + 2, *(str + 2)); 
    printf(" str + 3 :  %p  *(str + 3) :  %c\n", str + 3, *(str + 3)); 
    printf(" str + 4 :  %p  *(str + 4) :  %c\n", str + 4, *(str + 4)); 
    printf(" str + 5 :  %p  *(str + 5) :  %c\n", str + 5, *(str + 5)); 
    printf(" ptr_ucW0 :  %p  *ptr_ucW0 :  %c\n", ptr_ucW0, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0++ :  %c\n", ptr_ucW0++, *ptr_ucW0++); 
    printf(" ptr_ucW0 :  %p  *ptr_ucW0 :  %c\n", ptr_ucW0, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0++ :  %c\n", ptr_ucW0++, *ptr_ucW0++); 
    printf(" ptr_ucW0 :  %p  *ptr_ucW0 :  %c\n", ptr_ucW0, *ptr_ucW0); 
    printf("\n"); 
    printf(" Reset ptr_ucW0 = str\n"); 
    ptr_ucW0 = str; 
    printf(" Text   Address  Text    Value\n"); 
    printf(" ptr_ucW0 :  %p  *ptr_ucW0 :  %c\n", ptr_ucW0, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0 :  %c\n", ptr_ucW0++, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0 :  %c\n", ptr_ucW0++, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0 :  %c\n", ptr_ucW0++, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0 :  %c\n", ptr_ucW0++, *ptr_ucW0); 
    printf(" ptr_ucW0++:  %p  *ptr_ucW0 :  %c\n", ptr_ucW0++, *ptr_ucW0); 
} 
+0

Еще одна вещь, вы действительно не должны связываться с базовым адресом строки, в этом случае str. Это приведет только к плохим вещам. – SkyPirate

1

Стандарт C99 говорит в 6.5.2.2, 10:

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

Действительно, глядя на ассемблере мой VC2008 производства, эффект ++ был только видимой непосредственно перед вызова функции. Во время оценки аргументов он использовал оригинал str и поместил ++ во временную переменную.Поскольку порядок оценки не определен, компилятор мог бы использовать и другую стратегию.

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

Однако, поскольку перед вызовом функции есть точка последовательности, все операции ++ были внезапно видны в str перед вызовом функции.

Хороший пример неопределенного поведения (UB).

Смежные вопросы