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

C语言图文件解析器无法正确将边值存入数组问题排查

图结构解析器数组存储错误的解决方法

问题描述

我用C语言编写了一个解析图结构文件的程序,文件格式示例如下:

c FILE: graph_test
c
c SOURCE: generator
c 
p edge 10 12
e 1 2
e 2 3
e 6 2
  • 以c开头的行是注释,需忽略
  • p行指定顶点总数和边总数
  • e行描述顶点间的边关系

程序使用strtok()分割字符串提取数据,但将数据存入二维数组int edges[num_edges][2]时出现错误。执行时tmp打印的节点值正确,但数组中出现大量无意义的垃圾数据,输出结果示例:

> Execution 
List of edges :
1 -> 2
2 -> 3
6 -> 2
8 -> 3
3473509 -> 52
8 -> 7
9 -> 4
5 -> 6
7 -> 9
10 -> 1
1 -> 7
5 -> 4

完整代码如下:

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

#define MAX_SIZE 1000

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("\n[USAGE] : ./parser file_path\n");
        exit(1);
    }

    char *file_name = argv[1];
    FILE *file;

    // Open file in read mode
    file = fopen(file_name, "r");
    if (file == NULL) {
        printf("\nUnable to open file '%s'\n", file_name);
        exit(2);
    }

    char line[MAX_SIZE];
    int num_vertices = 0;
    int num_edges = 0;
    int edges[num_edges][2];

    // Read each line from the file
    int i;
    while (fgets(line, MAX_SIZE, file) != NULL) {
        // If the line starts with "c", it is a comment, so we ignore it
        if (line[0] == 'c') {
            continue;
        }
        // If the line starts with "p", it contains the number of vertices and edges
        if (line[0] == 'p') {
            i = 0;
            char *tmp = strtok(line, " ");
            while (tmp != NULL) {
                if (i == 2) {
                    num_vertices = atoi(tmp);
                }
                if (i == 3) {
                    num_edges = atoi(tmp);
                }
                tmp = strtok(NULL, " ");
                i++;
            }
            i = 0;
            continue;
        }

        // If the line starts with "e", we retrieve the edges
        if (line[0] == 'e') {
            char *tmp = strtok(line, " ");
            int j = 0;
            while (tmp != NULL) {
                if (j == 1) {
                    edges[i][0] = atoi(tmp);
                }
                if (j == 2) {
                    edges[i][1] = atoi(tmp);
                }
                printf("tmp : %s\n", tmp);
                tmp = strtok(NULL, " ");
                j++;
            }
            i++;
            continue;
        }
    }

    printf("\nNumber of vertices: %d\n", num_vertices);
    printf("Number of edges: %d\n", num_edges);
    printf("List of edges:\n");

    // Print all edges
    for (int i = 0; i < num_edges; i++) {
        printf("%d -> %d\n", edges[i][0], edges[i][1]);
    }

    // Close the file
    fclose(file);

    return 0;
}

错误原因

核心问题是数组初始化时机错误:

  • 定义int edges[num_edges][2];时,num_edges的初始值为0,因此该数组的实际大小是[0][2],没有可用存储空间。
  • 后续读取p行修改num_edges的值,无法改变已创建数组的大小。
  • 向0大小的数组写入数据会触发内存越界访问,覆盖其他变量空间或读取未初始化的内存区域,导致输出垃圾值。

解决方案

需要先读取p行获取num_edges的值,再创建对应大小的存储结构。由于C语言栈上的变长数组(VLA)无法动态调整大小,推荐使用动态内存分配(malloc/free)解决问题:

修正后的代码

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

#define MAX_SIZE 1000

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("\n[USAGE] : ./parser file_path\n");
        exit(1);
    }

    char *file_name = argv[1];
    FILE *file;

    // Open file in read mode
    file = fopen(file_name, "r");
    if (file == NULL) {
        printf("\nUnable to open file '%s'\n", file_name);
        exit(2);
    }

    char line[MAX_SIZE];
    int num_vertices = 0;
    int num_edges = 0;
    int **edges = NULL; // 先声明指针,后续分配内存

    // 第一步:读取文件找到p行,获取顶点数和边数
    while (fgets(line, MAX_SIZE, file) != NULL) {
        if (line[0] == 'c') {
            continue;
        }
        if (line[0] == 'p') {
            int i = 0;
            char *tmp = strtok(line, " ");
            while (tmp != NULL) {
                if (i == 2) {
                    num_vertices = atoi(tmp);
                }
                if (i == 3) {
                    num_edges = atoi(tmp);
                }
                tmp = strtok(NULL, " ");
                i++;
            }
            break; // 找到p行后跳出循环,准备分配内存
        }
    }

    // 分配内存存储边数据
    if (num_edges > 0) {
        edges = malloc(num_edges * sizeof(int*));
        for (int k = 0; k < num_edges; k++) {
            edges[k] = malloc(2 * sizeof(int));
        }
    } else {
        printf("\nNo edges found in the file\n");
        fclose(file);
        exit(3);
    }

    // 第二步:重置文件指针到开头,再次读取处理边数据
    rewind(file);
    int i = 0;
    while (fgets(line, MAX_SIZE, file) != NULL) {
        if (line[0] == 'c') {
            continue;
        }
        if (line[0] == 'p') {
            continue; // 已处理过p行,直接跳过
        }
        if (line[0] == 'e') {
            char *tmp = strtok(line, " ");
            int j = 0;
            while (tmp != NULL) {
                if (j == 1) {
                    edges[i][0] = atoi(tmp);
                }
                if (j == 2) {
                    edges[i][1] = atoi(tmp);
                }
                tmp = strtok(NULL, " ");
                j++;
            }
            i++;
            // 防止读取的边数超过p行指定的数量
            if (i >= num_edges) {
                break;
            }
        }
    }

    printf("\nNumber of vertices: %d\n", num_vertices);
    printf("Number of edges: %d\n", num_edges);
    printf("List of edges:\n");

    // 打印所有边
    for (int k = 0; k < num_edges; k++) {
        printf("%d -> %d\n", edges[k][0], edges[k][1]);
    }

    // 释放动态分配的内存
    for (int k = 0; k < num_edges; k++) {
        free(edges[k]);
    }
    free(edges);

    // 关闭文件
    fclose(file);

    return 0;
}

关键修改点

  1. 分两次读取文件:
    • 第一次读取仅定位p行,获取顶点数和边数
    • 使用rewind(file)重置文件指针,第二次读取处理所有e行
  2. 动态内存分配:
    • 根据num_edges的实际值分配对应大小的二维数组
    • 程序结束前释放内存,避免内存泄漏
  3. 边界检查:
    • 处理e行时,当读取的边数达到num_edges就停止,防止越界访问

简化替代方案(一维数组模拟二维)

如果不想分两次读取文件,也可以用一维数组存储边对,减少内存分配的复杂度:

// 分配内存
int *edges = malloc(num_edges * 2 * sizeof(int));
// 存储边
edges[i*2] = atoi(tmp);   // 第一个顶点
edges[i*2+1] = atoi(tmp); // 第二个顶点
// 访问边
printf("%d -> %d\n", edges[k*2], edges[k*2+1]);

内容的提问来源于stack exchange,提问作者Le Magicien Annonyme

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 09:05:24