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

C语言向二维数组插入Token时截断及段错误问题求助

字符串分割Token插入二维数组时的截断与段错误问题

问题描述

能正确从一行字符串分割出单个Token,但插入二维数组时会截断Token内容,同时存在NULL相关问题触发段错误。

原代码

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

#define MAX_FILE_LENGTH 30
#define MAX_COURSE_LENGTH 30
#define MAX_LINE_LENGTH 1000

void trim(char* str) {
  int l = strlen(str);
  if (str[l - 1] == '\n') {
    str[l - 1] = 0;
  }
}

int main() {
  char filename[MAX_FILE_LENGTH]; 
  char arr[MAX_COURSE_LENGTH][MAX_COURSE_LENGTH];
  const char delim[] = " ";
  char* token;
  int course = 0;
  char c;
  FILE* fp;
  int N = 0;    // number of lines in file

  printf("This program will read, from a file, a list of courses and their prerequisites and will print the list in which to take courses.\n");
  printf("Enter filename: ");
  scanf("%s%c", filename, &c);

  fp = fopen(filename, "r");

  if (fp == NULL) {
    printf("Could not open file %s. Exit\n", filename);
    printf("\nFailed to read from file. Program will terminate.\n");
    return -1;
  }

  while (!feof(fp) && !ferror(fp)) {
    int i = 0;
    if (fgets(arr[N], MAX_LINE_LENGTH, fp)) {
      trim(arr[N]);
      printf("Full line: |%s|\n", arr[N]);
      token = strtok(arr[N], delim);
      arr[N][i] = *token;
      printf("N = %d, i = %d, token = %s arr[%d][%d]: %s\n", N, i, token, N, i, &arr[N][i]);
      while (token != NULL) {
        i++;
        token = strtok(NULL, " \n");
        printf("token at arr[%d][%i]: %s value at arr[%d][%d]: %s\n", N, i, token, N, i, &arr[N][i]);
        arr[N][i] = *token;
        printf("N = %d, i = %d, token = %s arr[%d][%d]: %s\n", N, i, token, N, i, &arr[N][i]);
      }
      N++;
    }
  }
  fclose(fp);
  return 0;
}

运行输出

Full line: |c100 c200|
N = 0, i = 0, token = c100 arr[0][0]: c100
token at arr[0][1]: c200 value at arr[0][1]: 100
N = 0, i = 1, token = c200 arr[0][1]: c00
token at arr[0][2]: (null) value at arr[0][2]: 00
zsh: segmentation fault  ./a.out

输入文件内容

c100 c200
c300 c200 c100
c200 c100

错误原因分析

  • 数组类型不匹配:原代码定义的char arr[MAX_COURSE_LENGTH][MAX_COURSE_LENGTH]每个元素仅能存储单个字符,但需要存储的是c100这类字符串,结构无法容纳完整内容导致截断。
  • 字符串赋值错误:arr[N][i] = *token;仅将Token的第一个字符赋值给数组元素,而非复制整个字符串,这是截断问题的核心。
  • NULL指针解引用:当strtok返回NULL(无更多Token)时,仍执行arr[N][i] = *token;,直接访问NULL指针触发段错误。
  • 循环逻辑混乱:初始获取Token后直接赋值,随后先递增索引再获取Token,处理顺序错误,且未判断Token是否为NULL就操作。

修正后的代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>   // strtok, strcpy

#define MAX_FILE_LENGTH 30
#define MAX_COURSE_COUNT 30   // 最大课程行数
#define MAX_COURSE_CODE_LEN 30  // 单个课程代码最大长度
#define MAX_LINE_LENGTH 1000

void trim(char* str) {
    size_t l = strlen(str);
    if (l > 0 && str[l - 1] == '\n') {
        str[l - 1] = '\0';
    }
}

int main() {
    char filename[MAX_FILE_LENGTH]; 
    // 三维数组:行存储课程行,列存储课程代码,每个代码是独立字符数组
    char arr[MAX_COURSE_COUNT][MAX_COURSE_COUNT][MAX_COURSE_CODE_LEN];
    const char delim[] = " ";
    char* token;
    char c;
    FILE* fp;
    int N = 0;    // number of lines in file

    printf("This program will read, from a file, a list of courses and their prerequisites and will print the list in which to take courses.\n");
    printf("Enter filename: ");
    scanf("%s%c", filename, &c);

    fp = fopen(filename, "r");

    if (fp == NULL) {
        printf("Could not open file %s. Exit\n", filename);
        printf("\nFailed to read from file. Program will terminate.\n");
        return -1;
    }

    char line_buf[MAX_LINE_LENGTH];  // 单独的行缓冲区,避免strtok修改存储数组
    while (fgets(line_buf, MAX_LINE_LENGTH, fp) != NULL) {
        trim(line_buf);
        printf("Full line: |%s|\n", line_buf);
        
        int i = 0;
        token = strtok(line_buf, delim);
        while (token != NULL && i < MAX_COURSE_COUNT) {
            // 复制完整字符串到数组,确保不越界
            strncpy(arr[N][i], token, MAX_COURSE_CODE_LEN - 1);
            arr[N][i][MAX_COURSE_CODE_LEN - 1] = '\0';  // 手动添加字符串终止符
            printf("N = %d, i = %d, token = %s arr[%d][%d]: %s\n", N, i, token, N, i, arr[N][i]);
            
            i++;
            token = strtok(NULL, delim);
        }
        N++;
        if (N >= MAX_COURSE_COUNT) {
            printf("Reached maximum course line limit, stopping.\n");
            break;
        }
    }
    fclose(fp);
    
    // 验证存储结果
    printf("\nStored course data:\n");
    for (int row = 0; row < N; row++) {
        printf("Row %d: ", row);
        for (int col = 0; col < MAX_COURSE_COUNT; col++) {
            if (arr[row][col][0] != '\0') {
                printf("%s ", arr[row][col]);
            } else {
                break;
            }
        }
        printf("\n");
    }
    
    return 0;
}

关键修改说明

  • 调整数组结构:改用三维数组arr[MAX_COURSE_COUNT][MAX_COURSE_COUNT][MAX_COURSE_CODE_LEN],每行可存储多个完整的课程代码字符串。
  • 正确复制字符串:使用strncpy复制整个Token内容,同时手动添加终止符,避免截断和非法字符串问题。
  • 优化循环逻辑:先获取Token并判断非NULL后再处理,避免NULL指针解引用;使用独立缓冲区存储行内容,防止strtok修改存储数组。
  • 添加边界检查:限制行和列的索引范围,防止数组越界访问。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 03:17:07