도움이 되었으면하는 자세한 설명이 있습니다. 가장 간단하게 설명 할 수있는 프로그램부터 시작하겠습니다.
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)++
(괄호에서 명확하게하는 데 필요한*ptr++
)