포인터 표현식 : * ptr ++, * ++ ptr 및 ++ * ptr 그것들이 모두 포인터 / 가리키는

최근에 나는 혼자서 이해할 수없는이 문제를 발견했다.

이 세 가지 표현은 정말로 무엇을 의미합니까?

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

나는 Ritchie를 시도했다. 그러나 불행히도 그가이 세 가지 작전에 대해 말한 것을 따를 수 없었습니다.

나는 그것들이 모두 포인터 / 가리키는 값을 증가시키기 위해 수행된다는 것을 알고 있습니다. 평가의 우선 순위와 순서에 대해 많은 것들이있을 수 있습니다. 포인터를 먼저 증가시킨 다음 해당 포인터의 내용을 가져오고, 단순히 내용을 가져온 다음 포인터 등을 증가시킵니다. 보시다시피 실제 작업 에 대한 명확한 이해가 없습니다. 가능한 한 빨리 정리하십시오. 하지만 프로그램에 적용 할 기회가 생기면 정말 길을 잃었습니다. 예를 들면 :

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

이 출력을 제공합니다.

ello

그러나 나의 기대는 그것이 인쇄 될 것이라는 것이었다 Hello. 마지막 요청 하나-주어진 코드 스 니펫에서 각 표현식이 작동하는 방식에 대한 예제를 제공하십시오. 대부분의 경우 이론의 단순한 단락 만이 내 머리 위로 날아갑니다.



답변

도움이 되었으면하는 자세한 설명이 있습니다. 가장 간단하게 설명 할 수있는 프로그램부터 시작하겠습니다.

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

첫 번째 진술 :

const char* p = "Hello";

p대한 포인터로 선언 합니다 char. “pointer to a char“라고하면 무슨 뜻입니까? 의 값이 pa의 주소임을 의미합니다 char. p메모리에서 char.

문은 또한 p문자열 리터럴의 첫 번째 문자를 가리 키도록 초기화 됩니다 "Hello". 이 연습 p을 위해 전체 문자열이 아니라 첫 번째 문자 인을 가리키는 것으로 이해 하는 것이 중요합니다 'H'. 결국 , 전체 문자열이 아닌 p하나에 대한 포인터 char입니다. 의 값 p의 주소이다 'H'에서 "Hello".

그런 다음 루프를 설정합니다.

while (*p++)

루프 조건 *p++은 무엇을 의미합니까? (적어도 친숙 함이 시작될 때까지)이 혼란스러운 세 가지가 여기서 작동합니다.

  1. 두 연산자의 우선 순위, 접미사 ++및 간접*
  2. 접미사 증가 식의 값
  3. 접미사 증분 식의 부작용

1. 우선 순위 . 연산자에 대한 우선 순위 표를 간략히 살펴보면 후위 증분이 역 참조 / 간접 (15)보다 우선 순위 (16)가 더 높다는 것을 알 수 있습니다. 이것은 복잡한 표현식 *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. 후위 표현 부작용 . 접미사 ++는 현재 피연산자 의 을 갖지만 해당 피연산자를 증가 시키는 부작용 이 있습니다. 어? 해당 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..

이전 설명에서 postfix 증분 p++에는 특정 우선 순위 , 부작용 이 있다는 것을 알았습니다 . 접두사 증분 ++p은 접미사 대응 와 동일한 부작용 이 있습니다. 피연산자를 1 씩 증분합니다. 그러나 우선 순위 이 다릅니다 .

접두사 증가는 접미사보다 우선 순위가 낮습니다. 즉, 역 참조 / 간접 연산자와 동일한 우선 순위를 갖습니다 *. 같은 표현에서

*++ptr

중요한 것은 우선 순위가 아닙니다. 두 연산자는 우선 순위가 동일합니다. 따라서 연관성이 시작됩니다. 접두사 증가와 간접 연산자는 오른쪽-왼쪽 연관성을 갖습니다. 이러한 연관성 때문에 피연산자 ptr는 가장 ++왼쪽에 있는 연산자 앞에 가장 오른쪽에있는 연산자와 함께 그룹화됩니다 *. 즉, 표현식이 그룹화됩니다 *(++ptr). 따라서 *ptr++다른 이유에서 와 마찬가지로 여기서도 *부품이 부품의 값에 적용됩니다 ++ptr.

그렇다면 그 가치는 무엇입니까? 접두사 증분 식의 값은 증분 이후의 피연산자 값입니다 . 이것은 접미사 증가 연산자와는 매우 다른 짐승입니다. 다음이 있다고 가정 해 보겠습니다.

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

출력은 다음과 같습니다.

8
8

… 우리가 접미사 연산자로 본 것과는 다릅니다. 마찬가지로 다음이있는 경우 :

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을 얻습니다.이를으로 나타내면 ASCII 값 73 : char을 얻습니다 .char'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로 변경 하여 전체 문자열을 만듭니다. C에서 문자열 리터럴은 읽기 전용입니다. 수정하려고하면 정의되지 않은 동작이 호출됩니다. 영어에서도 정의되지 않았지만 우연의 일치입니다.'H''I'"Iello""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문자열 리터럴을 가리키는 경우 충돌합니다 .

거기에 있습니다. 이제 모든 것이 수정 이길 바랍니다. 당신은 훌륭한 청중이었고 저는 일주일 내내 여기있을 것입니다.


답변

ptrarray의 i 번째 요소를 가리킨다 고 가정 arr합니다.

  1. *ptr++의 (i + 1) 번째 요소로 평가되고 이를 가리 키도록 arr[i]설정 ptr합니다 arr. 그것은 동일합니다 *(ptr++).

  2. *++ptrptr의 (i + 1) 번째 요소를 가리 키도록 설정 arr하고로 평가됩니다 arr[i+1]. 그것은 동일합니다 *(++ptr).

  3. ++*ptr1 씩 증가 arr[i]하고 증가 된 가치로 평가됩니다. 포인터 ptr는 그대로 유지됩니다. 그것은 동일합니다 ++(*ptr).

또한 하나 더 있지만 작성하려면 괄호가 필요합니다.

  1. (*ptr)++1 씩 증가 arr[i]하고 증가 하기 전에 그 값으로 평가됩니다. 포인터 ptr는 다시 그대로 유지됩니다.

나머지는 스스로 알아낼 수 있습니다. @Jaguar도 답변했습니다.


답변

*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;
}


답변

루프의 상태가 나쁩니다.

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)


답변

우선 순위에 관해서는 *은 접두사 증가보다 우선하지만 접미사 증가에는 우선하지 않습니다. 이러한 분류 방법은 다음과 같습니다.

*ptr++ -왼쪽에서 오른쪽으로 이동하여 포인터를 역 참조한 다음 포인터 값을 증가시킵니다 (접미사가 역 참조보다 우선하기 때문에 가리키는 값이 아님).

*++ptr -포인터를 증가시킨 다음 역 참조하십시오. 이것은 접두사와 역 참조가 동일한 우선 순위를 가지기 때문에 오른쪽에서 왼쪽 순서로 평가되기 때문입니다.

++*ptr-우선 순위 측면에서 위와 비슷합니다. 다시 오른쪽에서 왼쪽으로 이동하여 포인터를 역 참조한 다음 포인터가 가리키는 것을 증가시킵니다. 귀하의 경우 읽기 전용 변수 ( char* p = "Hello";) 를 수정하려고하기 때문에 정의되지 않은 동작이 발생 합니다.


답변

다른 답변은 정확하지만 뭔가 빠진 것 같기 때문에 내 테이크를 추가 할 것입니다.

 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.

내가 말하려는 것의 부족은 Write What You Mean 입니다. 당신은 평균 경우 증가 PTR 다음 쓰기 ++ptr없습니다 ptr++. 당신이 의미 temp = ptr, ptr += 1, temp한다면ptr++


답변

*ptr++    // 1

이것은 다음과 같습니다.

    tmp = *ptr;
    ptr++;

따라서가 가리키는 객체의 값 ptr이 검색된 다음 ptr증가합니다.

*++ptr    // 2

이것은 다음과 같습니다.

    ++ptr;
    tmp = *ptr;

따라서 포인터 ptr가 증가하고 ptr가 가리키는 객체를 읽습니다.

++*ptr    // 3

이것은 다음과 같습니다.

    ++(*ptr);

따라서가 가리키는 객체 ptr는 증가합니다. ptr그 자체는 변하지 않습니다.