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

C函数返回嵌套结构体异常:split功能实现输出不符合预期

C语言split函数输出异常问题分析与修复

问题描述

尝试实现一个简易的字符串分割功能,将分割后的元素存入TOKENS结构体,再通过OUTPUT结构体返回结果集合与元素数量。但运行代码后,前几个分割出的字符串为空,仅最后一个元素正常输出。

原代码

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

struct TOKENS
{
  int length;
  char word[];
};

struct OUTPUT
{
  struct TOKENS *a;
  int l;
};

struct OUTPUT explode(char *a, char *b)
{
  struct TOKENS tokens[10];
  int i = 0;
  char *ptr = strtok(a, b);
  while (ptr != NULL)
  {
    tokens[i].length = strlen(ptr);
    strcpy(tokens[i].word, ptr);
    ptr = strtok(NULL, b);
    i++;
  }
  struct OUTPUT r = {
      .a = &tokens[0], .l = i};
  return r;
}

int main()
{
  char str[] = "This is test for the start";
  struct OUTPUT r = explode(str, " ");
  struct TOKENS *tokens = r.a;
  printf("%d\n", r.l);
  for (int i = 0; i < r.l; i++)
  {
    printf("%d %s (%d)\n", i, tokens[i].word, tokens[i].length);
  }

  return 0;
}

实际输出

6
0  (4)
1  (2)
2  (4)
3  (3)
4  (3)
5 start (5)

问题原因

  1. 柔性数组未分配内存:struct TOKENS中的char word[]是柔性数组成员,它本身不占用结构体内存,需要在分配结构体时额外为其申请空间。原代码中直接在栈上声明struct TOKENS tokens[10],每个tokens[i].word没有实际存储空间,执行strcpy时会越界写入,破坏内存布局。
  2. 返回栈内存指针:explode函数中的tokens是栈上的局部数组,函数返回后栈内存会被回收,OUTPUT结构体中保存的指针指向已失效的内存区域,后续访问属于未定义行为,导致输出异常。

修复方案

改用动态内存分配,为每个TOKENS结构体分配足够空间(结构体大小 + 字符串长度 + 1),并将结果存储在堆上,避免栈内存失效问题。

修复后的代码

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

struct TOKENS
{
  int length;
  char word[];
};

struct OUTPUT
{
  struct TOKENS **a;
  int l;
};

struct OUTPUT explode(char *a, char *b)
{
  struct OUTPUT r = {.a = NULL, .l = 0};
  char *ptr = strtok(a, b);
  
  // 先统计分割出的元素数量
  int count = 0;
  char *temp_ptr = ptr;
  while (temp_ptr != NULL) {
    count++;
    temp_ptr = strtok(NULL, b);
  }
  
  // 重新初始化strtok,恢复原始字符串的token遍历
  strtok(a, b);
  
  // 为指针数组分配内存
  r.a = malloc(count * sizeof(struct TOKENS*));
  if (!r.a) {
    r.l = 0;
    return r;
  }
  
  int i = 0;
  ptr = strtok(a, b);
  while (ptr != NULL) {
    int len = strlen(ptr);
    // 为单个TOKENS结构体+字符串分配内存
    r.a[i] = malloc(sizeof(struct TOKENS) + len + 1);
    if (!r.a[i]) {
      // 分配失败时释放已分配的内存,避免内存泄漏
      for (int j = 0; j < i; j++) {
        free(r.a[j]);
      }
      free(r.a);
      r.a = NULL;
      r.l = 0;
      return r;
    }
    r.a[i]->length = len;
    strcpy(r.a[i]->word, ptr);
    ptr = strtok(NULL, b);
    i++;
  }
  r.l = count;
  
  return r;
}

int main()
{
  char str[] = "This is test for the start";
  struct OUTPUT r = explode(str, " ");
  
  printf("%d\n", r.l);
  for (int i = 0; i < r.l; i++)
  {
    printf("%d %s (%d)\n", i, r.a[i]->word, r.a[i]->length);
  }
  
  // 释放动态分配的内存
  for (int i = 0; i < r.l; i++) {
    free(r.a[i]);
  }
  free(r.a);

  return 0;
}

输出结果

6
0 This (4)
1 is (2)
2 test (4)
3 for (3)
4 the (3)
5 start (5)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:30:41