You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用UT_hash时HASH_FIND_STR始终返回NULL问题求助

重复账户去重功能异常:HASH_FIND_STR无法找到已存在账户

已通过HASH_ADD_KEYPTR将键指针插入hashmap且生效(打印hashmap全部内容显示正常),但调用HASH_FIND_STR查找对应字符串时,exit_entry始终为NULL,无法找到目标账户。buffer为全局变量,代码如下:

// mutex
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// hash node
struct hash_buf_struct {
    char    *account_hash; 
    char   *password_hash;
    char     *option_hash;
    UT_hash_handle     hh;
}; 

// hash init
struct hash_buf_struct *buffer = NULL;
struct hash_buf_struct *s = NULL;
    
// Producer thread func
void *producer()
{
    while (1)
    {
        char rcvbuf[1500];  
        memset(rcvbuf, '\0', sizeof(rcvbuf));
        recvfrom(sockfd, rcvbuf, sizeof(rcvbuf), 0, (struct sockaddr *)&send_to, (socklen_t *)&send_to_len);
        
        regmatch_t matches[4];
        if (regexec(&regex, rcvbuf, 4, matches, 0) == 0) { 
            char     account[256];
            char    password[256];
            char     operation[5];
            
            regmatch_t account_match    = matches[1];
            regmatch_t password_match   = matches[2];
            regmatch_t operation_match  = matches[3];

            snprintf(  account,     account_match.rm_eo - account_match.rm_so + 1,   "%s", rcvbuf + account_match.rm_so);
            snprintf( password,   password_match.rm_eo - password_match.rm_so + 1,  "%s", rcvbuf + password_match.rm_so);
            snprintf(operation, operation_match.rm_eo - operation_match.rm_so + 1, "%s", rcvbuf + operation_match.rm_so);

            // sendto(sockfd, "Done!\n", 7, 0, (const struct sockaddr *)&send_to, (socklen_t)sizeof(send_to));
            s = (struct hash_buf_struct*)calloc(sizeof(struct hash_buf_struct), sizeof(char));
            s->option_hash            =   (char *)calloc(strlen(operation) + 1, sizeof(char));
            s->password_hash          =   (char *)calloc(strlen(password) + 1,  sizeof(char));
            s->account_hash           =   (char *)calloc(strlen(account) + 2,   sizeof(char));
            
            strcat  (s->password_hash, password);
            strcat   (s->option_hash, operation);
            strcat    (s->account_hash, account);

            struct hash_buf_struct *hash = NULL; 
            printf("---------------print test--------------\n");
            for (hash = buffer; hash != NULL; hash = (struct hash_buf_struct *)(hash->hh.next))
                printf("account = %s\n",hash->account_hash);
            printf("\n");

            struct hash_buf_struct *exit_entry = (struct hash_buf_struct *)calloc(strlen(account) + 1, sizeof(char));
            HASH_FIND_STR(buffer, s->account_hash, exit_entry);  // cant work

            if(exit_entry == NULL)
            {
                pthread_mutex_lock(&mutex);
                HASH_ADD_KEYPTR(hh, buffer, s->account_hash, strlen(account) + 1, s);
                pthread_mutex_unlock(&mutex);

            } else {
                if   (strcmp(s->option_hash, exit_entry->option_hash) == 0) printf("Repetitive operation");
                else {
                    pthread_mutex_lock(&mutex);
                    HASH_ADD_KEYPTR(hh, buffer, s->account_hash, strlen(account) + 1, s);
                    pthread_mutex_unlock(&mutex);
                }
            }

        } else  printf("----------------------------------------------------------\nValid     format:     %s\n\
Please type like:     ACCOUNT PASSWORD OPTION(close|open)\n----------------------------------------------------------\n", rcvbuf);

    }
}

问题根源与修复方案

1. HASH_FIND_STR使用错误

HASH_FIND_STR不需要提前为输出指针分配内存,它会直接将找到的节点地址赋值给传入的指针变量。你当前用calloc给exit_entry分配了无关内存,导致HASH_FIND_STR无法正确覆盖该指针,始终返回你分配的空内存地址。
修复:
将:

struct hash_buf_struct *exit_entry = (struct hash_buf_struct *)calloc(strlen(account) + 1, sizeof(char));

改为:

struct hash_buf_struct *exit_entry = NULL;

2. HASH_ADD_KEYPTR键长度参数不匹配

你插入hash时使用的键长度是strlen(account) + 1,但实际存储的键是s->account_hash,其长度应为strlen(s->account_hash)(或直接用strlen(account),因为snprintf已为account添加终止符)。长度不匹配会导致hash计算错误,无法正确查找。
修复:
将HASH_ADD_KEYPTR中的长度参数改为strlen(s->account_hash):

HASH_ADD_KEYPTR(hh, buffer, s->account_hash, strlen(s->account_hash), s);

3. 遍历hashmap未加锁

遍历hashmap的操作未加互斥锁,在多线程环境下会引发并发访问的未定义行为,可能破坏hash结构或导致打印异常。
修复:
遍历前后添加锁:

printf("---------------print test--------------\n");
pthread_mutex_lock(&mutex);
for (hash = buffer; hash != NULL; hash = (struct hash_buf_struct *)(hash->hh.next))
    printf("account = %s\n",hash->account_hash);
pthread_mutex_unlock(&mutex);
printf("\n");

4. 内存泄漏风险

当找到重复账户时,新分配的s节点及其内部的字符串内存未被释放,造成内存泄漏。
修复:
在else分支中添加内存释放逻辑:

} else {
    if (strcmp(s->option_hash, exit_entry->option_hash) == 0) {
        printf("Repetitive operation");
        // 释放新分配的节点内存
        free(s->account_hash);
        free(s->password_hash);
        free(s->option_hash);
        free(s);
    } else {
        pthread_mutex_lock(&mutex);
        HASH_ADD_KEYPTR(hh, buffer, s->account_hash, strlen(s->account_hash), s);
        pthread_mutex_unlock(&mutex);
    }
}

内容的提问来源于stack exchange,提问作者ColaMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:36:13