C+中的简单散列方法+; 我尝试在C++中实现一个简单的哈希方法,它采用最大长度为1024的字符数组,并将其转换成最大长度为256的数组。我得到了不正确的值,我不知道为什么

C+中的简单散列方法+; 我尝试在C++中实现一个简单的哈希方法,它采用最大长度为1024的字符数组,并将其转换成最大长度为256的数组。我得到了不正确的值,我不知道为什么,c++,arrays,C++,Arrays,测试输入:这是一个测试 测试输出:fWhis▒~▒▒▒▒t 预期输出:这是一个测试 我用java编写了相同的方法,效果很好 void hash(char* message, char* output) { //Hash int i = 0; while (i < strlen(message)-1){ output[i % N] += message[i++]; } output[N-1] = '\0'; } 我认为在初始化输出数

测试输入:这是一个测试

测试输出:fWhis▒~▒▒▒▒t

预期输出:这是一个测试

我用java编写了相同的方法,效果很好

void hash(char* message, char* output)
{
    //Hash
    int i = 0;
    while (i < strlen(message)-1){
        output[i % N] += message[i++];
    }
    output[N-1] = '\0';
 }

我认为在初始化输出数组时,输出数组中有垃圾值,所以我尝试创建一个助手方法clear()来初始化输出数组中的每个值,但这又给了我奇怪的值。

总结了注释中提到的内容

  • 在修改变量时在同一语句中访问变量
    i
    两次是未定义的行为
  • 未初始化的缓冲区不是零初始化的。从中读取(也隐式地通过
    +=
    )是未定义的行为
  • 在循环的每次迭代中调用strlen是浪费的
  • 输出缓冲区的NUL终止可疑。由于在一起添加字符不能保证提供任何可打印字符,因此NUL终止可能不是一个好主意
  • 由于加法产生的值可能大于
    char
    所能容纳的值,因此应使用
    无符号char
    ,因为有符号溢出是未定义的行为,
    char
    可能是
    有符号的
    无符号的
  • fgets
    已经从缓冲区大小中减去了终止NUL字节的空间,因此可以将实际数组大小传递给它
  • N
    是一个幻数,它应该是
    hash
    的输入参数
把所有这些放在一起,您的代码可能看起来像这样。注意,虽然你已经把你的问题标记为“C++”,但是代码不使用一个C++特性,所以我在这里展示C99代码。在C++中,您可能更喜欢使用“代码> STD::String s或甚至更好的迭代器来完成原始指针数组。

#include <stddef.h>
#include <stdio.h>
#include <string.h>

void
hash(const char * message, unsigned char *const output, const size_t n)
{
  size_t i = 0;
  memset(output, 0, n);
  while (*message != '\0')
    output[i++ % n] += *message++;
}

int
main()
{
  char message[1024];
  unsigned char output[256];
  printf("Please enter the message: ");
  fgets(message, sizeof(message), stdin);
  hash(message, output, sizeof(output));
  fwrite(output, sizeof(output), 1, stdout);
  fputc('\n', stdout);
}
#包括
#包括
#包括
无效的
散列(常量字符*消息,无符号字符*常量输出,常量大小\u t n)
{
尺寸i=0;
memset(输出,0,n);
而(*消息!='\0')
输出[i++%n]+=*消息++;
}
int
main()
{
字符消息[1024];
无符号字符输出[256];
printf(“请输入消息:”);
fgets(消息、sizeof(消息)、stdin);
散列(消息、输出、sizeof(输出));
fwrite(输出,sizeof(输出),1,标准输出);
fputc('\n',stdout);
}

您的代码有很多问题:

    这是C++编写的C。从长远来看,你将更好地学习使用<代码>字符串< /> > 。
  • 我们应该想象什么是
    N
    。我想是256。如果您提供小的、完整的、可运行的代码,您将从中获得更好的帮助
  • 您应该将输出的长度作为参数传递,而不是采用全局定义。这样函数就独立了,这是一种最佳实践
  • while
    条件在每次迭代中调用
    strlen()<对于长度为
    n
    的字符串,code>strlen()
    的运行时间为O(
    n
    )。您已将本应为O(
    n
    )的循环转换为O(
    n
    ^2)
  • 在这里使用
    ,而
    不是最佳做法。对
    使用
  • 您从未初始化数组
    输出
    
    
  • 您正在用
    N
    字符计算结果,然后用零覆盖
    N
    th。缓冲区
    输出
    的长度必须为
    N
    +1,以便在
    N
    输出字符后有空间写入终止的空字符
  • int
    是索引数组的错误方法。您应该真正使用
    size\u t
  • 在调用代码中,您忘记了为空终止允许额外的字符。您的代码最多只能读取1023个字符,而不是1024个字符。散列也一样
将所有这些清理干净,您将得到如下结果:

void hash(char* message, char* hash_buf, size_t hash_buf_size)
{
  // Zero the output buffer, including the terminal null character.
  memset(hash_buf, '\0', hash_buf_size);
  size_t len = strlen(message);
  for (size_t i = 0; i < len; i++)
    hash_buf[i % (hash_buf_size - 1)] += message[i];
}

是否希望输出与输入相同?在本测试用例中,应该是因为消息不超过256个字符。基本上我想要的是,如果第一个字符是a,第256个字符是b,那么新的第一个字符将是b。换言之,每256个字符它就开始写入自身。当
输出中的数据量小于
N
(我假设
N
为256?)时,您不能正确地以null结尾。同样,此行
输出[i%N]+=消息[i++]显示未定义的行为。在单独的行上递增
i
。缓冲区也未初始化为零,这是未定义行为的另一个来源。请不要在循环条件下重复调用
strlen
。事实上,你根本不需要它。谢谢大家!在下一行增加i,初始化数组时为零,解决了这些问题。我还删除了对strlen的调用。“在修改变量时在同一语句中访问变量I两次是未定义的行为。”据我所知,在C++17中,情况已不再如此。执行顺序现在已经明确。
void hash(char* message, char* hash_buf, size_t hash_buf_size)
{
  // Zero the output buffer, including the terminal null character.
  memset(hash_buf, '\0', hash_buf_size);
  size_t len = strlen(message);
  for (size_t i = 0; i < len; i++)
    hash_buf[i % (hash_buf_size - 1)] += message[i];
}
char message[1025], hash[257];

fgets(message, sizeof message, stdin);
hash(message, hash, sizeof hash);