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

结构体嵌套内存访问违规及单向图节点分配、遍历问题求助

问题描述

我要实现的功能是:构建包含listNode的链表,每个listNode持有指向graphNode的指针,这些graphNode构成有向图,需要从指定起点随机遍历到名为"Home"的节点。

目前遇到的核心问题:

  • 将图节点关联到链表节点的过程出错,疑似存在无限循环
  • 读取结构体嵌套内容时触发内存访问违规(Memory access violations)

需要实现一个接收链表头节点、节点名称和路径权重的函数,完成图节点的正确关联,并解决遍历问题。

输入文件结构

Applebees
GroundRound
BlueMoose
DrunkenNoodle
Home
STOP
Applebees BlueMoose 10
Applebees DrunkenNoodle 13
GroundRound Applebees 2
GroundRound DrunkenNoodle 7
GroundRound Home 52
STOP STOP 0
GroundRound

现有代码

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

struct graphNode {
    char name[100]; // 场所名称
    int arcCnt; // 该节点的出边数量
    int weights[10]; // 每条出边的权重
    struct graphNode* arcs[10]; // 存储该节点指向的其他图节点指针
};
struct listNode {
    char name[100]; // 场所名称
    struct listNode* next;
    struct graphNode* graph; // 指向对应图节点的指针
};

void listInsert(struct listNode **head, char name[100]) {
    
    // 创建新的图节点
    struct graphNode* newGraph = (struct graphNode*)malloc(sizeof(struct graphNode));
    for (int i = 0; i < 100; i++) {
        newGraph->name[i] = name[i];
    }
    for (int i = 0; i < 10; i++) {
        newGraph->arcs[i] = NULL;
    }
    newGraph->arcCnt = 0;

    // 创建新的链表节点
    struct listNode* newNode = (struct listNode*)malloc(sizeof(struct listNode));
    
    for (int i = 0; i < 100; i++) {
        newNode->name[i] = name[i];
    }
    newNode->next = NULL;
    newNode->graph = newGraph;


    // 如果链表为空,直接作为头节点
    if (*head == NULL) {
        *head = newNode;
        return;
    }

    // 否则添加到链表末尾
    struct listNode* current = *head;
    while (current->next != NULL) {
        current = current->next;
    }
    current->next = newNode;

}

void graphInsert(struct listNode** head, char src[100], char dst[100], int weight) {

    struct listNode* srcNode = *head;

    printf("CALL:");

    while (srcNode->next != NULL) { // 遍历链表查找源节点
        
        printf("%s %s", srcNode->name, src);
        if (strcmp(srcNode->name, src) == 0) {  // 找到源节点后,查找目标节点并更新图数据
            
            printf("FOUND");
            
            struct listNode* dstNode = *head;
            while (dstNode->next != NULL) { // 遍历链表查找目标节点
                
                printf("    %s %s", dstNode->name, dst);
                if (strcmp(dstNode->name, src) == 0) { // 找到目标节点后更新信息
                
                    printf("FOUND");
                    // 根据当前出边数量分配新边,然后返回退出循环
                    srcNode->graph->arcs[srcNode->graph->arcCnt] = dstNode->graph;
                    srcNode->graph->weights[srcNode->graph->arcCnt] = weight;
                    srcNode->graph->arcCnt++;
                    return;
                }
                dstNode = dstNode->next;
            }
        }
        srcNode = srcNode->next;
    }
}

int main(){
   
    srand(2021);

    // 初始化变量
    struct listNode* head = NULL;
    struct graphNode* sourceNode = NULL;
    FILE* data = fopen("./hw10.data", "r");
    int i = 0;
    int section = 1; // 用于区分文件读取的不同阶段
    
    // 读取文件内容
    while (1) { 
        char name[100];
        char name2[100];
        int weight = 0;
        if (section == 1) { // 读取第一部分:节点名称
            
            fscanf(data, "%100s", name);
            if (strcmp(name, "STOP") == 0) { // 遇到STOP则进入下一阶段
                section++;
            } else { // 否则将名称添加到链表
                listInsert(&head, name);
            }

        } else if (section == 2) { // 读取第二部分:边的信息,构建图

            fscanf(data, "%100s %100s %d", name, name2, &weight);

            if (strcmp(name, "STOP") == 0) { // 遇到STOP则进入下一阶段
                section++;
            } else {
                //graphInsert(&head, name, name2, weight);
            }

        } else if (section == 3) { // 读取第三部分:起始节点名称
            
            char tmp[100];
            fscanf(data, "%100s", tmp);

            struct listNode* current = head;
            while (current->next != NULL) { // 遍历链表找到对应节点
                
                if (strcmp(current->name, tmp) == 0) { // 匹配成功则记录起始图节点
                    sourceNode = current->graph;
                    break;
                }
                current = current->next;
            }

        }
        
        if (feof(data)) break;
        i++;
    }
    
    
    
    // 调试打印链表节点
    printf("\n");
    struct listNode* current = head;
    while (current != NULL) {
        printf("%s\n", current->name);
        current = current->next;
    }
    printf("\n");


    // 打印起始节点
    printf("%s ", sourceNode->name);

    // 从起始节点开始随机遍历,直到到达"Home"节点
    int totalWeight = 0;
    i = 0;
    while (i < 100) {
        char* tmp = sourceNode->name;
        if (strcmp(tmp, "Home") == 0) { // 到达Home则退出程序

            // 打印终点和总权重
            printf("%s %d", sourceNode->name, totalWeight);
            return 0;

        } else { // 未到达则继续遍历

            int index = (rand() % sourceNode->arcCnt); // 生成0到出边数量-1的随机索引
            sourceNode = sourceNode->arcs[index];
            //printf("Going to: %s, Index: %d", sourceNode->name, totalWeight);

        }
        i++;
    }


    return 0;
}
错误分析与修复方案

1. 链表遍历漏节点问题

  • 问题:graphInsert和main中查找节点的循环条件用了xxx->next != NULL,会漏掉链表最后一个节点,导致无法匹配末尾节点(比如输入中的"Home")。
  • 修复:将所有遍历链表的循环条件改为xxx != NULL,确保遍历所有节点:
// graphInsert中查找源节点
while (srcNode != NULL) {
    // ...原有逻辑
    srcNode = srcNode->next;
}

// graphInsert中查找目标节点
while (dstNode != NULL) {
    // ...原有逻辑
    dstNode = dstNode->next;
}

// main中查找起始节点
while (current != NULL) {
    // ...原有逻辑
    current = current->next;
}

2. 目标节点匹配错误

  • 问题:graphInsert中匹配目标节点时,误写为strcmp(dstNode->name, src) == 0,应该和dst比较。
  • 修复:修改为strcmp(dstNode->name, dst) == 0。

3. 字符串拷贝不安全

  • 问题:listInsert中用循环逐个拷贝字符,未处理字符串结束符\0,会导致字符串残留垃圾数据,引发匹配错误。
  • 修复:用strncpy安全拷贝,并手动添加结束符:
strncpy(newGraph->name, name, 99);
newGraph->name[99] = '\0';

strncpy(newNode->name, name, 99);
newNode->name[99] = '\0';

4. 未启用图边构建函数

  • 问题:main中graphInsert被注释,导致图的边未构建,arcCnt始终为0,rand()%0会触发未定义行为。
  • 修复:取消注释graphInsert(&head, name, name2, weight);。

5. 遍历未累加权重

  • 问题:随机遍历过程中未累加路径权重,最终输出的totalWeight始终为0。
  • 修复:切换节点时累加对应边的权重:
int index = (rand() % sourceNode->arcCnt);
totalWeight += sourceNode->weights[index];
sourceNode = sourceNode->arcs[index];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:10:16