답변:
의 값은 증분 이전 s++의 원래 값으로 s, 증분은 다음 시퀀스 포인트 전의 지정되지 않은 시간에 발생합니다.
따라서 *s++및*(s++) 동일 : 그들은 모두의 원래 값을 역 참조 s. 또 다른 동등한 표현은 *(0, s++)마음이 희미하지 않은 것이 아니라 다음과 같습니다.0[s++]
그러나 함수는 type size_t을 사용해야합니다 .i 과 반환 유형 합니다.
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
다음은 루프 당 단일 증분이있는 잠재적으로 더 효율적인 버전입니다.
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
두 번째 단락의 이상한 표현에 대해 궁금해하는 사람들을 위해 :
0, s++,왼쪽 부분을 평가 한 다음 오른쪽 부분을 평가 하는 쉼표 연산자의 인스턴스입니다 . 그 후(0, s++) 와 같습니다 (s++).
0[s++]동등 (s++)[0]하고 *(0 + s++)또는 *(s++ + 0)같은 단순화 된 *(s++). 표현식에서 포인터와 색인 표현식을 전치하는 []것은 흔하지 않거나 특히 유용하지는 않지만 C 표준을 준수합니다.
간단한 문자열 "a"로이 함수를 호출한다고 가정 해 봅시다. 그런 다음 while 루프에서 s가 증가하므로 s의 값은 0이고 i도 0입니다.
이 예 s에서 'a'in을 가리 킵니다 "a". 그런 다음 증분되고 i증분됩니다. 이제 s널 종료자를 가리키고 iis 1입니다. 따라서 다음에 루프를 통과하면 *(s++)is '\0'( 0)이므로 루프가 종료되고 현재의 값 i( 1)이 반환됩니다.
일반적으로 루프는 문자열의 각 문자에 대해 한 번 실행 된 다음 널 종료 자에서 중지되므로 문자 수를 계산합니다.
s 보유한 것으로 평가합니다 . 당신이 묘사하는 것은 (실제로 하나의 카운트보다 작고 빈 문자열을 전달하면 UB를 호출하는) 동작입니다. ++s
완벽하게 이해됩니다.
int str_len(const char* s) {
int i = 0;
while(*(s++)) { //<-- increments the pointer to char till the end of the string
//till it finds '\0', that is, if s = "a" then s is 'a'
// followed by '\0' so it increments one time
i++; //counts the number of times the pointer moves forward
}
return i;
}
"하지만
s대괄호 안에 있습니다. 그것이 내가 먼저 증가 할 것이라고 생각한 이유입니다."
그렇기 때문에 포인터가 문자가 아닌 증분되는 이유입니다.이 경우 포인터가 아니라 (*s)++문자가 증분됩니다. 역 참조는 이제 포인터 자체가 아니라 포인터가 참조하는 값으로 작업하고 있음을 의미합니다.
두 연산자의 우선 순위는 같지만 오른쪽에서 왼쪽으로의 연관성이 있으므로 *s++대괄호없이 간단히 포인터를 사용할 수도 있습니다 .
사후 증분 연산자는 피연산자의 값을 1 씩 증가 시키지만 표현식의 값은 증분 연산 이전의 피연산자의 원래 값입니다.
전달 된 인수가 str_len()입니다 "a". 에서 str_len(), 포인터는 s문자열의 첫 번째 문자를 가리키고 있습니다 "a". 에서 while루프 :
while(*(s++)) {
.....
.....
가 있지만 s증가하지만 될 값 s의 표현은 첫 번째 문자에 포인터가 증가하기 전에 가리키는 문자에 대한 포인터 일 것이다 'a'. 포인터 s가 역 참조 되면 character가 제공됩니다 'a'. 다음 반복에서 s포인터는 널 문자 인 다음 문자를 가리 킵니다 \0. s역 참조 되면 0루프가 종료됩니다. 그 참고 s이제 문자열의 NULL 문자 과거 하나 개의 요소를 가리키는 것입니다 "a".
, s++일어날 일과 나쁜 일을 치워라:)