Реализация strnstr

Я пытаюсь реализовать функцию strnstr в C (strstr, но она проверяет длину), по какой-то причине она не работает (выход всегда нет):

#include <stdio.h>

char *searchingFor = "stackdummy";
char *in = "la dandoo a dannow here comes the stacknok there it was.n";

char *strnstr(char *s1, char *s2, int length) {
    if(s1 == NULL || s2 == NULL) return NULL;
    printf("searching nn"%s"n for %.*sn", 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: %sn", strnstr(in, searchingFor, 5) ? "yes" : "no");
    printf("found: %sn", strnstr(in, searchingFor, 5) ? "yes" : "no");
    printf("found: %sn", strnstr(in, searchingFor, 5) ? "yes" : "no");
    return 0;
}

2 ответов


реализация предусмотренных Крис Додд имеет следующие недостатки:

  1. он побеждает цель strnstr в том, что while условие использует неограниченную строковую функцию strchr
  2. это зависит от того haystack будучи NULL завершается, что является отклонением от обычной реализации strnstr, например, как предусмотрено GNU-Darwin
  3. вызов strchr - это ненужная функция позвоните, когда strchar не встроен
  4. возвращает haystack вместо NULL, когда len равно нулю, отклонение от принятого strstr семантика
  5. возвращает пустую строку вместо haystack, когда needle имеет длину ноль

следующая реализация устраняет вышеуказанные проблемы, не становясь такой же трудной для чтения, как реализация GNU-Darwin, и лицензируется Creative Commons:

#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, вам понадобятся два аргумента длины:

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, хотя более старые версии сломаны.