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

C语言读取CSV存入二维数组后无法正确访问值的问题求助

问题:C语言二维数组访问异常与随机分配逻辑错误

我是C语言初学者,正在完成一个学校项目:将家庭分配到节日的不同日期,分配需满足人数等约束条件。我们有指定格式的CSV文件,为实现分配函数、约束及目标函数,我将CSV数据存入名为matrix的二维数组,以获取每个家庭的人数和日期偏好,并实现了read_csv_file函数(不存储表头)。但遇到两个问题:

  • 无法正确访问二维数组的值,在choose_random_numbers函数中打印matrix[5][~]时,每次输出的数值都不一样
  • 实现从家庭偏好中随机选日期的choose_random_numbers函数时,有时会分配不在偏好中的日期

CSV数据示例

family_size;preference1;preference2;preference3;preference4;preference5
3; 6; 4; 3; 2; 0
3; 3; 1; 0; 2; 4
4; 3; 2; 0; 6; 4
3; 4; 5; 1; 0; 3
8; 2; 0; 5; 1; 6
5; 1; 0; 4; 6; 2

相关代码

读取CSV文件的函数

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

#define MAX_LINE_LENGTH 1000
#define MAX_NUM_VALUES 6

int read_csv_file(char *filename, int matrix[][MAX_NUM_VALUES], int *num_rows) {

    FILE *fp;
    char line[MAX_LINE_LENGTH];
    int row = 0, col = 0;

    // open the file for reading
    fp = fopen(filename, "r");
    if (fp == NULL) {
        printf("Error opening file %s\n", filename);
        return 0;
    }

    // count the number of rows in the file
    while (fgets(line, MAX_LINE_LENGTH, fp) != NULL) {
        (*num_rows)++;
    }

    // reset file pointer to the beginning of the file
    fseek(fp, 0, SEEK_SET);

    // ignore the first line of the file
    fgets(line, MAX_LINE_LENGTH, fp);

    // store the values from the file into the matrix
    while (fgets(line, MAX_LINE_LENGTH, fp) != NULL) {
        char *token = strtok(line, ";");
        col = 0;
        while (token != NULL && col < MAX_NUM_VALUES) {
            matrix[row][col++] = atoi(token);
            token = strtok(NULL, ";");
        }
        row++;
    }

    // close the file
    fclose(fp);

    return 1;
}

随机分配日期的函数

void choose_random_numbers(int matrix[][MAX_NUM_VALUES], int num_rows, int *random_numbers, int *count_days) {

    int satisfied = 0;

    srand(time(NULL));

    while (!satisfied) {

        // Reset count_days to zero
        memset(count_days, 0, sizeof(int)*7);

        for (int i = 0; i < num_rows; i++) {
            // choose random index from 1 to 5
            int rand_index = rand() % (MAX_NUM_VALUES - 1) + 1;
            
            int day = matrix[i][rand_index];
            random_numbers[i] = day;
        
            for (int j = 1; j < 6; j++) {
                if (day == matrix[i][j]) {
                    satisfied = 1;
                }
                else{
                satisfied = 0;
                }
            }

            count_days[day]+=matrix[i][0];
        }

        satisfied = 1;
          
        printf("test: %d", matrix[5][2]);


}

主函数

int main() {

    char *filename = "pb40.csv";
    int num_rows = 0;
    int matrix[MAX_LINE_LENGTH][MAX_NUM_VALUES];

    if (!read_csv_file(filename, matrix, &num_rows)) {
        return 1;
    }
    int random_numbers[MAX_NUM_VALUES];
    int count_days[7];

    choose_random_numbers(matrix, num_rows, random_numbers, count_days);
   

    return 0;
}

问题原因及修复方案

1. 二维数组访问异常(matrix[5][~]值不稳定)

  • 原因:read_csv_file统计行数时包含了表头,导致num_rows值为总行数(表头+数据行),但后续实际只读取了num_rows-1行数据。主函数中random_numbers数组大小为MAX_NUM_VALUES,当数据行数量超过这个值时,会触发数组越界,破坏matrix的内存空间,导致读取值异常。另外choose_random_numbers末尾强制设置satisfied=1,会让循环提前终止,但越界操作已经造成内存损坏。
  • 修复:
    • 修改行数统计逻辑,跳过表头再统计数据行:
      // 先读取表头,再统计数据行
      fgets(line, MAX_LINE_LENGTH, fp);
      while (fgets(line, MAX_LINE_LENGTH, fp) != NULL) {
          (*num_rows)++;
      }
      fseek(fp, 0, SEEK_SET);
      fgets(line, MAX_LINE_LENGTH, fp); // 再次跳过表头准备读取数据
      
    • 主函数中random_numbers的大小应匹配实际数据行数:
      int random_numbers[num_rows]; // 使用变长数组,或用malloc动态分配内存
      

2. 随机分配不在偏好中的日期

  • 原因:日期合法性检查的循环逻辑错误,循环会遍历所有5个偏好项,最后一次比较的结果会覆盖satisfied的值——即使day是合法偏好,只要最后一个偏好不匹配,satisfied会被设为0,导致错误判断。另外内存越界也会导致matrix中存储的偏好值异常。
  • 修复:
    • 修改合法性检查逻辑,找到匹配项后立即终止循环:
      satisfied = 0; // 初始化为不合法
      for (int j = 1; j < 6; j++) {
          if (day == matrix[i][j]) {
              satisfied = 1;
              break; // 找到匹配直接退出循环
          }
      }
      // 如果不合法,重新处理当前家庭
      if (!satisfied) {
          i--;
          continue;
      }
      
    • 删除choose_random_numbers末尾的satisfied = 1,让循环条件正确判断所有家庭是否都分配了合法日期。

其他潜在问题修复

  • 将srand(time(NULL))移到主函数中,避免每次循环重新初始化随机数生成器,导致随机数重复。
  • 确保日期范围在0-6之间,避免count_days数组越界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:18:10