web-dev-qa-db-ja.com

strnstrの実装

Strnstr関数をCに実装しようとしています(strstrですが、長さをチェックします)。何らかの理由で機能しません(出力は常にnoです)。

#include <stdio.h>

char *searchingFor = "stackdummy";
char *in = "la da\ndoo a da\nnow here comes the stack\nok there it was.\n";

char *strnstr(char *s1, char *s2, int length) {
    if(s1 == NULL || s2 == NULL) return NULL;
    printf("searching \n\n\"%s\"\n for %.*s\n", s1, length, s2);
    char *ss1 = malloc(strlen(s1) + 1);
    strcpy(ss1, s1);
    char *ss2 = malloc(length + 1);
    strncpy(ss2, s2, length);
    char *result = strstr(ss1, ss2);
    free(ss1);
    free(ss2);
    return result;
}

int main(void) {
    printf("found: %s\n", strnstr(in, searchingFor, 5) ? "yes" : "no");
    printf("found: %s\n", strnstr(in, searchingFor, 5) ? "yes" : "no");
    printf("found: %s\n", strnstr(in, searchingFor, 5) ? "yes" : "no");
    return 0;
}
11
Jimmay

Chris Dodd によって提供される実装には、次の欠点があります。

  1. strnstr条件が無制限の文字列関数whileを使用するという点で、strchrの目的を無効にします。
  2. これは、haystackがNULLで終了するかどうかに依存します。これは、たとえば GNU-Darwin によって提供されるstrnstrの通常の実装からの逸脱です。
  3. strchrの呼び出しは、strcharがインライン化されていない場合の不要な関数呼び出しです。
  4. haystackがゼロの場合、NULLの代わりにlenを返します。これは、受け入れられているstrstrセマンティクスからの逸脱です。
  5. haystackの長さがゼロの場合、needleの代わりに空の文字列を返します

次の実装は、GNU-Darwin実装ほど読みにくくなることなく上記の問題を解決し、クリエイティブコモンズライセンスが付与されています。

#include <string.h>

char *strnstr(const char *haystack, const char *needle, size_t len)
{
        int i;
        size_t needle_len;

        if (0 == (needle_len = strnlen(needle, len)))
                return (char *)haystack;

        for (i=0; i<=(int)(len-needle_len); i++)
        {
                if ((haystack[0] == needle[0]) &&
                        (0 == strncmp(haystack, needle, needle_len)))
                        return (char *)haystack;

                haystack++;
        }
        return NULL;
}

どうですか:

char *strnstr(char *haystack, char *needle, size_t len) {
    if (len == 0) return haystack; /* degenerate Edge case */
    while (haystack = strchr(haystack, needle[0])) {
        if (!strncmp(haystack, needle, len)) return haystack;
        haystack++; }
    return 0;
}

haystackをnullで終了させたくない場合は、2つの長さの引数が必要です。

char *memmem(char *haystack, size_t hlen, char *needle, size_t nlen) {
    if (nlen == 0) return haystack; /* degenerate Edge case */
    if (hlen < nlen) return 0; /* another degenerate Edge case */
    char *hlimit = haystack + hlen - nlen + 1;
    while (haystack = memchr(haystack, needle[0], hlimit-haystack)) {
        if (!memcmp(haystack, needle, nlen)) return haystack;
        haystack++; }
    return 0;
}

これはGNU libcで利用できますが、古いバージョンは壊れています。

3
Chris Dodd