回答:
の値s++
はの元の値でs
、インクリメントの前に、次のシーケンスポイントの前の不特定の時間にインクリメントが発生します。
したがって*s++
、と*(s++)
同等ですs
。どちらもの元の値を逆参照します。別の同等の表現は*(0, s++)
次のとおりであり、気の弱い人のためのものではありません。0[s++]
あなたの関数の型を使用する必要があることに注意してください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;
}
ループごとに1つの増分がある、より効率的なバージョンを次に示します。
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
2番目の段落の奇妙な表現について不思議に思う人のために:
0, s++
,
左部分を評価し、次にその値を構成する右部分を評価するコンマ演算子のインスタンスです。したがって、(0, s++)
と同等(s++)
です。
0[s++]
等価で(s++)[0]
且つ*(0 + s++)
又は*(s++ + 0)
どのように簡略化します*(s++)
。式でのポインタとインデックス式の転置は[]
あまり一般的ではなく、特に有用ではありませんが、C標準に準拠しています。
この関数を単純な文字列 "a"で呼び出すとしましょう。次に、whileループでsがインクリメントされるため、sの値は0であり、iも0です。
その例では、がをs
ポイントして'a'
い"a"
ます。次に、増分され、i
さらに増分されます。ここs
で、nullターミネーターをポイントし、i
です1
。したがって、ループの次の実行で*(s++)
は、is '\0'
(つまり0
)なので、ループが終了し、i
(that's 1
)の現在の値が返されます。
通常、ループは文字列内の各文字に対して1回実行され、その後NULLターミネーターで停止するため、このようにして文字がカウントされます。
s
保持されたものに評価されます。あなたが説明しているのは(実際には1つ少なくカウントされ、空の文字列が渡されると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
、インクリメントの前に指している文字へのポインタ、つまり最初の文字へのポインタになります。ポインタが逆参照されると、文字を与えます。次の反復では、ポインタはnull文字である次の文字を指しています。ときに逆参照され、それが与えるとループは終了となります。は、stringのnull文字を過ぎた1つの要素を指すことに注意してください。'a'
s
'a'
s
\0
s
0
s
"a"
, s++
悪いことが起こります:)