ここで、inDivを呼び出してc
、文字列内の文字を検索できますdivs
。次に例を示します。
inDiv('x', "is there an x character in here somewhere?') will return 1
inDiv('x', "ahhh... not this time') will return 0
それを介して作業する:
int inDiv(char c, char * divs)
{
char * p_divs = divs; // remember which character we're considering
char tmp;
while(tmp = *p_divs++) // copy that character into tmp, and move p_divs to the next character
// but if tmp is then 0/false, break out of the while loop
if (tmp == c) return 1; // if tmp is the character we're searching for, return "1" meaning found
return 0; // must be here because tmp == 0 indicating end-of-string - return "0" meaning not-found
}
reverse
コールサイトを見ることで、次のことを推測できます。
int main()
{
char source[MAS_SIZE], dest[MAS_SIZE], divs[MAS_SIZE];
printf("String : ");
gets(source);
printf("Dividers : ");
gets(divs);
reverse(source, dest, divs);
printf("Reversed string : %s", dest);
gets()
標準入力から文字配列に読み取るために呼び出されsource
、divs
->これらの入力がに提供されていることがわかりますreverse()
。方法dest
は印刷されます、それは明らかに。の文字列の反転の宛先であることを意味しますsource
。この段階では、の関連性についての洞察はありませんdivs
。
ソースを見てみましょう...
void reverse(char * source, char * dest, char * divs)
{
*dest = '\0'; //what does this pointer do?
int source_len = strlen(source); //what is source
if (source_len == 0) return;
char* p_source = source + source_len - 1;
char* p_dest = dest;
while(p_source >= source)
{
while((p_source >= source) && (inDiv(*p_source, divs))) p_source--;
ここで*dest = '\0'
は、NUL文字を文字配列に書き込みます。これは文字dest
列の終わりの位置をエンコードする通常の番兵の値です。最初の文字に入力*dest
すると、宛先をクリアする必要があります。source
反転するテキスト入力は、その中の文字数にstrlen()
設定されることがわかっています。source_len
文字がない場合は、return
実行する作業がなく、出力はすでにNULで終了しているためです。それ以外の場合は、新しいポインタp_source
が作成され、source + source_len - 1
->に初期化されます。これは、ソース内の最後の非NUL文字を指していることを意味します。 p_dest
デスティネーションバッファの先頭にあるNUL文字を指します。
次に、ループは次のように言います。-while (p_source >= source)
これを行うには、最初は何でもするp_source
必要があります-これは、最後の文字を指す>= source
ものとして意味があり、バッファ内の最初の文字アドレスです。比較は、それらが交差するまで、一方または両方をもう一方に向かって移動することを意味します-毎回いくつかの作業を行います。これにより、次のことが可能になります。p_source
source
while((p_source >= source) && (inDiv(*p_source, divs))) p_source--;
これは今見たのと同じテストですが、今回はp_source
文字列の先頭に向かって後方に移動しているだけですが、これinDiv(*p_source, divs)
も当てはまります...つまり、の文字は文字列*p_source
内の文字の1つですdivs
。つまり、基本的には、文字列の先頭を通過するまで後方に移動します(ただし、Michael Burrがコメントで指摘しているように、このテストの動作は未定義であり、文字列がアドレス0に割り当てられた場合は実際には機能しない可能性があります-特定のデータセグメントに関連している場合でも、ポインタが0からFFFFFFFF hexのようなものに移動する可能性があるため(0未満のようには見えない)、または「除算」文字の1つではない文字が見つかるまで。
ここでは、コードが何をしているのかについての実際の洞察を得ることができます...入力を「単語」に分割し、入力内の文字のセットのいずれかでdivs
区切ってから、スペース区切り文字を使用して逆の順序で宛先バッファーに書き込みます。それは私たち自身より少し進んでいます-しかしそれを追跡しましょう:
次の行は...
if (p_source < source) break;
...これは、ループがソース文字列の先頭を超えて終了した場合、すべてのループから抜け出すことを意味します(先を見据えると、コードはすでに生成された出力の最後に新しいNULを配置し、 -しかし、それは私たちが期待することですか?-「helloworld」の「hello」をバックスルーしていた場合、文字列の先頭に到達し、最後の「hello」単語をコピーせずにループを終了します。出力!出力は常に入力内のすべての単語(最初の単語を除く)が逆になります。これは作成者が説明した動作ではありません)。
さもないと:
char* w_end = p_source; // remember where the non-divider character "word" ends
// move backwards until there are no more characters (p_source < source) or you find a non-divider character
while((p_source >= source) && (!inDiv(*p_source, divs))) p_source--;
// either way that loop exited, the "word" begins at p_source + 1
char * w_beg = p_source + 1;
// append the word between w_beg and w_end to the destination buffer
for(char* p = w_beg; p <= w_end; p++) *p_dest++ = *p;
// also add a space...
*p_dest++ = ' ';
これは入力内の「単語」ごとに発生し続け、最後の行で宛先にNULターミネータが追加されます。
*p_dest = '\0';
今、あなたは言った:
ライターによると、hello worldの文字列を書き込み、その中に文字列をworldhelloに反転する関数があります。
さて、入力「hello world」とスペースを含む仕切り文字(ただし、入力内の他の文字はありません)が与えられると、出力は「helloworld」になります(最後のスペースに注意してください)。
価値のあることですが、このコードはそれほど悪くはありません...入力の長さに関する仮定は危険であり、最初の単語が欠落していますが、ASCIIZバッファのC処理ではかなり正常です...。
**未定義の動作を修正する方法**
未定義の動作について-バッファの開始時にループが終了するようにループを変更するアドレスへの最小の変更。次の行で、ループが終了した理由を明示的に確認し、必要な動作を確認します。それは少し醜いでしょうが、ロケット科学ではありません。