全知全能を目指す人のありがたい雑記

何かしら意味のあるありがた~い話か、意味のない雑念だらけの日記を書く予定です。

文字列1から文字列2を検索するプログラム+解説

strstrっていう関数がある

#include <string.h>
char *strstr(const char *s1, const char *s2);

これを学習目的で自作する人が居たので、類似のソースを見つけて解説してみた
printfで出力の途中経過を混ぜてます

ソース

#include <stdio.h>

char *myStrstr(const char *s1, const char *s2)
{
    printf("start\n");
    const char *p1 = s1;
    const char *p2 = s2;
    
    while (*p1 && *p2) {
        if (*p1 == *p2) {
            p1++;
            p2++;
            printf("true [p1:%s] [p2:%s]\n",p1,p2);
        } else {
            long diff = (p2-s2-1);
            p1 -= p2 - s2 - 1;
            p2 = s2;
            printf("false [p1:%s] [p2:%s] ",p1,p2);
            printf("p1 pointer moves %ld\n",diff);
        }
    }
    printf("end\n");
    printf("p2 is [%s], [%s] - ([%s] - [%s]) = [%s]\n",p2,p1,p2,s2,(p1 - (p2 - s2)));
    return (*p2 ? NULL : (char *)(p1 - (p2 - s2)));
}

int main(void){
    const char* str1 = "eyanyaoewar9nyan349reawr";
    const char* str2 = "nyan";
    
    char* str3 = myStrstr(str1,str2);
    
    printf("result is %s",str3); 
}

str1を「eyanyaoewar9nyan349reawr
str2を「nyan」とした。

出力結果

start
false [p1:yanyaoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:anyaoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:nyaoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
true [p1:yaoewar9nyan349reawr] [p2:yan]
true [p1:aoewar9nyan349reawr] [p2:an]
true [p1:oewar9nyan349reawr] [p2:n]
false [p1:yaoewar9nyan349reawr] [p2:nyan] p1 pointer moves 2
false [p1:aoewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:oewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:ewar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:war9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:ar9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:r9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:9nyan349reawr] [p2:nyan] p1 pointer moves -1
false [p1:nyan349reawr] [p2:nyan] p1 pointer moves -1
true [p1:yan349reawr] [p2:yan]
true [p1:an349reawr] [p2:an]
true [p1:n349reawr] [p2:n]
true [p1:349reawr] [p2:]
end
p2 is [], [349reawr] - ([] - [nyan]) = [nyan349reawr]
result is nyan349reawr

解説

p1のp2の1文字目を比較して

  • 一致したら次の文字を比較、すなわち先頭文字を削る(p1++;p2++;)…①
  • 一致しなかったらp1のポインタの位置をp2-s2-1分移動し、(p1 -= p2 - s2 - 1;)し、p2の文字列を元に戻す(p2=s2;)…②

p2-s2-1分、ポインタを移動するというのは、
①でp1を何度インクリメントしたかで結果が変わる

  • 0回なら1個左に移動
  • 1回なら移動しない
  • 2回なら1個右に移動
  • 3回なら2個右に移動

って感じ

そのとき、p1の文字列の状態は、
ポインタが、

  • 1個左に移動したら、p1から1文字を削除
  • 移動しないなら、p1を変更しない
  • 1個右に移動したら、p1を1文字復元
  • 2個右に移動したら、p1を2文字復元

って感じ

ループは、以下の条件を満たすまで回り続ける。

  • ①が呼ばれることでp2のポインタが文字列外へ移動するか
  • ②が呼ばれることでp1のポインタが文字列外へ移動するか

戻り値は、
p2のポインタの先頭が

  • 存在すれば、NULL
  • 存在しなければ、p2と一致した位置のp1のポインタ

を返す。