문자열의 문자 수를 계산하는 함수입니다.
int str_len(const char* s) {
int i = 0;
while(*(s++)) {
i++;
}
return i;
}
이것이 올바른 길이를 반환하는 이유는 무엇입니까?
간단한 String 으로이 함수를 호출한다고 가정 해 봅시다 "a"
. 그런 다음 s
while 루프에서 증가하므로 s
및 의 값 i
은 모두 0입니다.
답변
의 값은 증분 이전 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
널 종료자를 가리키고 i
is 1
입니다. 따라서 다음에 루프를 통과하면 *(s++)
is '\0'
( 0
)이므로 루프가 종료되고 현재의 값 i
( 1
)이 반환됩니다.
일반적으로 루프는 문자열의 각 문자에 대해 한 번 실행 된 다음 널 종료 자에서 중지되므로 문자 수를 계산합니다.
답변
완벽하게 이해됩니다.
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"
.