최근에 나는 혼자서 이해할 수없는이 문제를 발견했다.
이 세 가지 표현은 정말로 무엇을 의미합니까?
*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
“라고하면 무슨 뜻입니까? 의 값이 p
a의 주소임을 의미합니다 char
. p
메모리에서 char
.
문은 또한 p
문자열 리터럴의 첫 번째 문자를 가리 키도록 초기화 됩니다 "Hello"
. 이 연습 p
을 위해 전체 문자열이 아니라 첫 번째 문자 인을 가리키는 것으로 이해 하는 것이 중요합니다 'H'
. 결국 , 전체 문자열이 아닌 p
하나에 대한 포인터 char
입니다. 의 값 p
의 주소이다 'H'
에서 "Hello"
.
그런 다음 루프를 설정합니다.
while (*p++)
루프 조건 *p++
은 무엇을 의미합니까? (적어도 친숙 함이 시작될 때까지)이 혼란스러운 세 가지가 여기서 작동합니다.
- 두 연산자의 우선 순위, 접미사
++
및 간접*
- 접미사 증가 식의 값
- 접미사 증분 식의 부작용
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
문자열 리터럴을 가리키는 경우 충돌합니다 .
거기에 있습니다. 이제 모든 것이 수정 이길 바랍니다. 당신은 훌륭한 청중이었고 저는 일주일 내내 여기있을 것입니다.
답변
ptr
array의 i 번째 요소를 가리킨다 고 가정 arr
합니다.
-
*ptr++
의 (i + 1) 번째 요소로 평가되고 이를 가리 키도록arr[i]
설정ptr
합니다arr
. 그것은 동일합니다*(ptr++)
. -
*++ptr
ptr
의 (i + 1) 번째 요소를 가리 키도록 설정arr
하고로 평가됩니다arr[i+1]
. 그것은 동일합니다*(++ptr)
. -
++*ptr
1 씩 증가arr[i]
하고 증가 된 가치로 평가됩니다. 포인터ptr
는 그대로 유지됩니다. 그것은 동일합니다++(*ptr)
.
또한 하나 더 있지만 작성하려면 괄호가 필요합니다.
(*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
그 자체는 변하지 않습니다.