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

哈希表插入函数仅保留最新输入问题排查与malloc用法求助

哈希表程序问题修复方案

问题概述

  • insert函数仅能保存从text.txt读取的最新字符串
  • 核心需求:
    • 解析"Finn 34"格式的行,将字符串与对应数值插入哈希表
    • 哈希索引已有内容时报告冲突
    • 插入重复字符串时提示已存在
  • 当前所有字符串指向同一个fscanf读取的name变量,需通过内存分配解决,但多次尝试未成功

现有代码

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

#define TableSize 45
#define Max 50
///// dont forget the edit in main

typedef struct node {
    char name[Max];
    int value;
} node;
node array[Max];


void init_array(){

    for (int i = 0; i < TableSize; i++){
      //array[i] = NULL;
    }
} 


void insert(int index, node *p){

  /*char * tempName = malloc (sizeof (char) * 50);
  strcpy(tempName, p->name);*/

  if (array[index].value != 0){
    //if (array[index]->name == p->name){
    if (strcmp(array[index].name, p->name) == 0){
      printf("Error %s already exists at index %d\n", array[index].name, index);
    }
    else{
      printf("Collision occured at index %d with\n", index);
    }
  }
  else{
    array[index] = *p;
    strcpy(array[index].name, p->name);
    printf("Stored %s with value of %d at index %d.\n", array[index].name, array[index].value, index);
  }

} 

int hash(char name[Max]){
  int key = 0;
  for (int i = 0; name[i] != '\0'; ++i){
    char x = name[i];
    key = key + x;
  }
  key = key % TableSize;
  return key;
}

int main(int argc, char *argv[]) {
  init_array();
  FILE *fp;
  char ch;
  char name[Max];
  int x, HaValue;


  fp = fopen(argv[1], "r");
  if (NULL == fp) {
        //printf("file can't be opened \n");
        fp = fopen("text.txt", "r"); ///////get rid of when done
    }
  node * p;  
  p = malloc(sizeof(struct node));
 do{
  x = 0;

  int counter = 0;
  if (fscanf(fp, "%49s", name) != 1) break;
  if (fscanf(fp, "%d", &x) != 1) counter = 1;
  HaValue = hash(name);
  p->value = x;
  strcpy(p->name, name);
  if (counter != 0) {
  }
  else{
    insert(HaValue, p);
  }
  
  } while(!feof(fp));

  printf("%d %s %d", 12, array[12].name, array[12].value);
  //test to see if the name was correctly saved. should be "12 Dog 12"

  
    // Closing the file
    fclose(fp);
  
  return 0;
}

测试文件内容(text.txt)

Brom 89
Paul 25
Jake 34
Yokai 45
Jake
Dog 20
Paul 30
Brom
Kron 40
Finn 234

核心问题分析

  1. 哈希表数组定义错误:array大小设为Max,但实际应该与TableSize一致,存在索引越界风险
  2. 初始化不完整:init_array未清空结构体的name和value,空节点判断逻辑(value != 0)不可靠
  3. 重复使用单个动态节点:main中仅分配一个node指针,每次循环覆盖内容,导致所有插入项指向同一块内存,最终只保留最后一次读取的数据
  4. 文件读取逻辑缺陷:do-while(!feof)会导致最后一行重复读取
  5. 插入逻辑冗余:array[index] = *p;已完成结构体复制,后续strcpy完全多余

修复后的代码

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

#define TableSize 45
#define Max 50

typedef struct node {
    char name[Max];
    int value;
} node;
// 修正哈希表数组大小为TableSize
node array[TableSize];

void init_array(){
    // 初始化每个空节点:清空字符串,标记value为0
    for (int i = 0; i < TableSize; i++){
        memset(array[i].name, 0, Max);
        array[i].value = 0;
    }
} 

void insert(int index, node *p){
    if (array[index].value != 0){
        if (strcmp(array[index].name, p->name) == 0){
            printf("错误:%s 已存在于索引 %d\n", array[index].name, index);
        }
        else{
            printf("冲突发生在索引 %d,与已存在的键 %s 冲突\n", index, array[index].name);
        }
    }
    else{
        array[index] = *p;
        printf("已存储 %s,值为 %d,索引为 %d\n", array[index].name, array[index].value, index);
    }
} 

int hash(char name[Max]){
    int key = 0;
    for (int i = 0; name[i] != '\0'; ++i){
        key += name[i];
    }
    return key % TableSize;
}

int main(int argc, char *argv[]) {
    init_array();
    FILE *fp = NULL;

    // 优先使用命令行参数指定的文件,无参数则尝试打开text.txt
    if (argc >= 2) {
        fp = fopen(argv[1], "r");
    }
    if (fp == NULL) {
        fp = fopen("text.txt", "r");
        if (fp == NULL) {
            printf("无法打开文件\n");
            return 1;
        }
    }

    char name[Max];
    int x;
    // 修复读取逻辑:成功读取字符串+整数才处理
    while (fscanf(fp, "%49s %d", name, &x) == 2) {
        // 栈上创建临时节点,避免重复覆盖内存
        node temp_node;
        strcpy(temp_node.name, name);
        temp_node.value = x;
        int ha_value = hash(name);
        insert(ha_value, &temp_node);
    }

    // 测试输出索引12的内容
    printf("索引12的内容:%s %d\n", array[12].name, array[12].value);

    fclose(fp);
    return 0;
}

关键修改说明

  • 修正哈希表数组大小:确保数组大小与哈希表尺寸TableSize一致,避免索引越界
  • 完善初始化:用memset清空字符串,设置value为0,保证空节点判断准确
  • 替换动态节点为栈临时节点:每次读取后在栈上创建独立的node,避免内存覆盖问题,无需手动malloc/free
  • 修复文件读取逻辑:用while(fscanf(...) == 2)替代do-while(!feof),彻底解决重复读取问题
  • 优化提示信息:冲突时打印已存在的键名,提升调试可读性
  • 移除冗余代码:删除重复的strcpy调用,简化插入逻辑

可选:链式哈希表实现(支持冲突链式存储)

如果需要支持冲突的链式解决(而非仅报告冲突),可以修改为指针数组+动态节点:

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

#define TableSize 45
#define Max 50

typedef struct node {
    char name[Max];
    int value;
    struct node *next;
} node;
// 哈希表改为指针数组,初始为NULL
node *array[TableSize];

void init_array(){
    for (int i = 0; i < TableSize; i++){
        array[i] = NULL;
    }
} 

void insert(int index, char *name, int value){
    // 检查当前索引是否已存在相同键
    node *current = array[index];
    while (current != NULL) {
        if (strcmp(current->name, name) == 0) {
            printf("错误:%s 已存在于索引 %d\n", name, index);
            return;
        }
        current = current->next;
    }
    // 动态分配新节点
    node *new_node = malloc(sizeof(node));
    if (new_node == NULL) {
        printf("内存分配失败\n");
        return;
    }
    strcpy(new_node->name, name);
    new_node->value = value;
    new_node->next = array[index];
    // 提示冲突或成功存储
    if (array[index] != NULL) {
        printf("冲突发生在索引 %d,已通过链式存储解决\n", index);
    } else {
        printf("已存储 %s,值为 %d,索引为 %d\n", name, value, index);
    }
    array[index] = new_node;
} 

int hash(char name[Max]){
    int key = 0;
    for (int i = 0; name[i] != '\0'; ++i){
        key += name[i];
    }
    return key % TableSize;
}

int main(int argc, char *argv[]) {
    init_array();
    FILE *fp = NULL;

    if (argc >= 2) {
        fp = fopen(argv[1], "r");
    }
    if (fp == NULL) {
        fp = fopen("text.txt", "r");
        if (fp == NULL) {
            printf("无法打开文件\n");
            return 1;
        }
    }

    char name[Max];
    int x;
    while (fscanf(fp, "%49s %d", name, &x) == 2) {
        int ha_value = hash(name);
        insert(ha_value, name, x);
    }

    // 打印所有哈希表内容(可选)
    for (int i = 0; i < TableSize; i++){
        if (array[i] != NULL){
            printf("索引%d:", i);
            node *current = array[i];
            while (current != NULL){
                printf("%s(%d) -> ", current->name, current->value);
                current = current->next;
            }
            printf("NULL\n");
        }
    }

    fclose(fp);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:40:22