C 哈希代码无效

C 哈希代码无效,c,hash,C,Hash,我发现这个散列函数是用Java编写的,在stackoverflow的帮助下,它将其转换为C。问题是,每次在同一个字上运行时,它都会给出不同的散列值 以下是原始函数: long sfold(String s, int M) { int intLength = s.length() / 4; long sum = 0; for (int j = 0; j < intLength; j++) { char c[] = s.substring(j * 4, (j *

我发现这个散列函数是用Java编写的,在stackoverflow的帮助下,它将其转换为C。问题是,每次在同一个字上运行时,它都会给出不同的散列值

以下是原始函数:

long sfold(String s, int M) 
{
  int intLength = s.length() / 4;
  long sum = 0;
  for (int j = 0; j < intLength; j++) 
  {
     char c[] = s.substring(j * 4, (j * 4) + 4).toCharArray();
     long mult = 1;
     for (int k = 0; k < c.length; k++) 
     {
        sum += c[k] * mult;
        mult *= 256;
     }
  }

  char c[] = s.substring(intLength * 4).toCharArray();
  long mult = 1;
  for (int k = 0; k < c.length; k++) 
  {
     sum += c[k] * mult;
     mult *= 256;
  }

  return(Math.abs(sum) % M);
 }
下面是我们如何改写的:

include <stdlib.h>
include <stdio.h>
include <math.h>
include <string.h>

long sfold(char * s, int M);

int main(void)
{
    char *  s = "test";
    int M;
    long x;
    M = 525;
    x = sfold(s,M);

    printf("%ld\n",x);
}   
long sfold(char * s, int M)
{
    int intLength = strlen(s) / 4;
    long sum = 0;

    for (int j = 0; j < intLength; j++) 
    {
       char c[4];
       memcpy(c, s + 4 * j, 4);

       //char c[] = s.substring(j * 4, (j * 4) + 4).toCharArray();
       long mult = 1;

       for (int k = 0; k < strlen(c); k++) 
       {
           sum += c[k] * mult;
           mult *= 256;
       }
    }

    char c[intLength];
    memcpy(c,s,intLength);
    //char c[] = s.substring(intLength * 4).toCharArray();
    long mult = 1;

    for (int k = 0; k < strlen(c); k++) 
    {
       sum += c[k] * mult;
       mult *= 256;
    }

    return(abs(sum) % M);
}

每次我们运行程序时,这不应该给出相同的值吗?有人知道怎么了吗?

所有的字符串复制都很愚蠢。如果只需要字符值,那么复制有什么意义

下面是它在C中的外观:

long sfold(char* s, unsigned long M) {
   unsigned long mult = 1, sum = 0;
   while (*s) {
      sum += (uint8_t)(*s++) * mult;
      mult *= 256;
      if (!mult) mult = 1;
   }
   return sum % M;
}
但这是一个糟糕的散列算法。您最好使用一个简单的模块化散列,它也不是很好,但也没有那么糟糕:

/* This could be any small prime */
static const unsigned long mult = 31;
long sfold(char* s, unsigned long M) {
   /* Avoid having the hash of the empty string be 0 */
   unsigned long sum = 0xBEA00D1FUL;
   while (*s)
      sum += (uint8_t)(*s++) * mult;
   return sum % M;
}

所有的字符串复制都很愚蠢。如果只需要字符值,那么复制有什么意义

下面是它在C中的外观:

long sfold(char* s, unsigned long M) {
   unsigned long mult = 1, sum = 0;
   while (*s) {
      sum += (uint8_t)(*s++) * mult;
      mult *= 256;
      if (!mult) mult = 1;
   }
   return sum % M;
}
但这是一个糟糕的散列算法。您最好使用一个简单的模块化散列,它也不是很好,但也没有那么糟糕:

/* This could be any small prime */
static const unsigned long mult = 31;
long sfold(char* s, unsigned long M) {
   /* Avoid having the hash of the empty string be 0 */
   unsigned long sum = 0xBEA00D1FUL;
   while (*s)
      sum += (uint8_t)(*s++) * mult;
   return sum % M;
}

我想我帮你处理了大部分的虫子。我让它符合C99标准,主要是出于习惯。使用strlenc时出现的主要问题是:c是字符数组,而不是以null“\0”字符结尾的字符数组字符串。您需要重写函数,以便在calloc/malloc失败时,函数会以错误终止。或者,如果编译器支持,您也可以像以前一样返回到可变长度数组,但这至少可以帮助您在不调用未定义行为的情况下以确定性的方式工作

代码清单


我想我帮你处理了大部分的虫子。我让它符合C99标准,主要是出于习惯。使用strlenc时出现的主要问题是:c是字符数组,而不是以null“\0”字符结尾的字符数组字符串。您需要重写函数,以便在calloc/malloc失败时,函数会以错误终止。或者,如果编译器支持,您也可以像以前一样返回到可变长度数组,但这至少可以帮助您在不调用未定义行为的情况下以确定性的方式工作

代码清单


在调试器中逐行遍历代码。strlenc:c未以NUL'\0'终止。原始代码具有intLength*4 not char c[intLength];当然,斯特伦和蓝精灵州一样都是美国黑人。恭喜你!幸运的是,您通过调试器中的代码逐行调用了一个UBStep。strlenc:c没有以NUL“\0”结尾。原始代码具有intLength*4而不是char c[intLength];当然,斯特伦和蓝精灵州一样都是美国黑人。恭喜你!你很幸运地打了个电话,谢谢。当我运行valgrind时,我得到:valgrind./test2==345==命令:./test2==345==345==1==345==at 0x80486F2:sfold test2.c:50==345==by 0x80485B7:main test2.c:18==345==地址0x423c02a在大小为2的块之后是0字节alloc'd==345==at 0x402C109:calloc in/usr/lib/valgrind/vgpreload\memcheck-x86-linux.so==345==by 0x804862E:sfold test2.c:26==345==by 0x80485B7:main test2.c:18==345==345==345==345==ERROR SUMMARY:1上下文中的2个错误被抑制:0来自0@DCR而且请考虑rici在其回答中提出的观点:它们是非常有效的观点。还要注意,与您尝试的哈希函数不同,此哈希函数首先处理所有4字节的块,然后在额外的循环中处理剩余的字节。此代码的子字符串错误。它在4字节块上传递两次,一次是以4字节的步幅,然后是以单字节的步幅。当前代码将为少于4个字母的所有单词提供相同的哈希值,例如,即0。谢谢。当我运行valgrind时,我得到:valgrind./test2==345==命令:./test2==345==345==1==345==at 0x80486F2:sfold test2.c:50==345==by 0x80485B7:main test2.c:18==345==地址0x423c02a在大小为2的块之后是0字节alloc'd==345==at 0x402C109:calloc in/usr/lib/valgrind/vgpreload\memcheck-x86-linux.so==345==by 0x804862E:sfold test2.c:26==345==by 0x80485B7:main test2.c:18==345==345==345==345==ERROR SUMMARY:1上下文中的2个错误被抑制:0来自0@DCR而且请考虑rici在其回答中提出的观点:它们是非常有效的观点。还要注意,与您尝试的哈希函数不同,此哈希函数首先处理所有4字节的块,然后在额外的循环中处理剩余的字节。此代码的子字符串错误。它在4字节块上传递两次,一次是以4字节的步幅,然后是以单字节的步幅。当前代码将为少于4个字母的所有单词提供相同的哈希值,例如,0。