为Windows编写自己的记忆

时间:2018-10-25 11:59:15

标签: c

我注意到memmem在Windows的MSVC中不可用,因此我尝试为其编写一些内容。我有以下代码:

void *memmem(const void *haystack_start, size_t haystack_len, const void *needle_start, size_t needle_len)
{
    const unsigned char *haystack = (const unsigned char *)haystack_start;
    const unsigned char *needle = (const unsigned char *)needle_start;
    const unsigned char *h = NULL;
    const unsigned char *n = NULL;
    size_t x = needle_len;

    /* The first occurrence of the empty string is deemed to occur at
    the beginning of the string.  */
    if (needle_len == 0) {
        return (void *)haystack_start;
    }

    /* Sanity check, otherwise the loop might search through the whole
        memory.  */
    if (haystack_len < needle_len) {
        return NULL;
    }

    for (; *haystack && haystack_len--; haystack++) {
        x = needle_len;
        n = needle;
        h = haystack;

        if (haystack_len < needle_len)
            break;

        if ((*haystack != *needle) || (*haystack + needle_len != *needle + needle_len))
            continue;

        for (; x; h++, n++) {
            x--;

            if (*h != *n)
                break;

            if (x == 0)
                return (void *)haystack;
        }
    }

    return NULL;
}

但是,我认为它无法正常工作。如果我尝试这样的事情:

static const char haystack[24] = {
    0x4e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x67, 0x6f,
    0x6e, 0x6e, 0x61, 0x20, 0x67, 0x69, 0x76, 0x65,
    0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x70, 0x2c,
};

static const char needle[8] = {
    0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x70, 0x2c
};

char *res = memmem(haystack, sizeof(haystack), needle, sizeof(needle));
printf("%s", res);

结果为空。有什么想法可能是问题所在吗?

3 个答案:

答案 0 :(得分:4)

我认为您过于复杂了。

void *memmem(const void *haystack, size_t haystack_len, 
    const void * const needle, const size_t needle_len)
{
    if (haystack == NULL) return NULL; // or assert(haystack != NULL);
    if (haystack_len == 0) return NULL;
    if (needle == NULL) return NULL; // or assert(needle != NULL);
    if (needle_len == 0) return NULL;

    for (const char *h = haystack;
            haystack_len >= needle_len;
            ++h, --haystack_len) {
        if (!memcmp(h, needle, needle_len)) {
            return h;
        }
    }
    return NULL;
}

直到haystack_len大于或等于needle_len,您应该将heystack中的当前位置的针与当前内存进行比较。如果是真的,请返回heystack。

  1. 无需显式强制转换const void *指针const unsigned char *haystack = (const unsigned char *)haystack_start;就是const unsigned char *haystack = haystack_start;
  2. 正如@molbdnilo (*haystack != *needle) || (*haystack + needle_len != *needle + needle_len))在评论中所说的那样。一旦使用[]运算符而不是*haystack[0] != needle[0] || haystack[0] + needle_len != needle[0] + needle_len,就变得显而易见。即使您的意思是... != needle[needle_len],也无济于事。
  3. for真是奇怪:

for (; *haystack && haystack_len--; haystack++) {
      if (haystack_len < needle_len)
            break;

为什么不呢?

for (; *haystack && haystack_len < needle_len; haystack_len--, haystack++)

表达式*haystack只是无效的,您没有像strstr那样检查以空值结尾的字符串。 heystack指向内存中的任何字节,其值可以为零。 haystack_len保持heystack的长度。

  1. 您可以使用memcmp比较内存,而无需自己编写该部分。

答案 1 :(得分:1)

for (; *haystack && haystack_len--; haystack++) {

在这里,您在循环开始时递减haystack_len。这意味着,当您达到匹配数haystack_len = 7但needle_len = 8时。因此,您无法通过f (haystack_len < needle_len)检查和continue。正如卡米尔(Kamil)在评论中指出的那样,您可能也不想在干草堆上检查一下。所以我建议

for (; haystack_len > 0; ++haystack, --haystack_len) {

答案 2 :(得分:0)

以下语句相同

char needle[] = "a test";
char needle[7] = { 'a', ' ', 't', 'e', 's', 't', '\0' };

您的haystack'\0'在同一位置没有needle

尝试

// needle is NOT a string
char needle[6] = "a test"; // needle is NOT a string