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

C语言使用strtok()拆分字符串后如何正确返回多维数组

问题根本原因

你遇到的问题是C语言中典型的栈内存非法访问问题,具体有两个核心错误点:

  • 返回局部栈数组的地址:get_tokens函数内的ar是栈上分配的局部数组,函数执行结束后,对应的栈帧会被操作系统回收,这块内存会被后续的函数调用(比如main中的printf)复用覆盖,你返回的ar指针属于野指针,访问它指向的内容属于未定义行为,这也是编译警告-Wreturn-stack-address的直接触发原因。
  • token指向的内容同样存储在栈上:你调用strtok拆分的是栈上的局部数组strcopy,所有返回的token指针都是指向strcopy内部的偏移地址,函数退出后strcopy的内存也会被回收,就算ar数组有效,里面存储的指针指向的内容也已经失效。

你看到的第一个token还能正常输出是偶然现象:栈回收只是标记内存为可复用,不会立刻清空内容,后续printf调用执行时逐步覆盖了栈上的旧数据,才出现只有第一个token看起来正常,后续都是null或乱码的情况。

修复方案

需要将需要留存的内存改为堆上动态分配(用malloc申请,使用完后手动free避免内存泄漏),修改后的参考代码如下:

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

char** get_tokens(const char* str, char delim, int token_count) {
    // 动态分配存储token指针的数组,堆内存不会随函数退出回收
    char** ar = malloc(sizeof(char*) * token_count);
    if (!ar) return NULL;

    // 构造分隔符字符串给strtok使用
    char delim_str[2] = {delim, '\0'};
    // 动态分配原字符串的拷贝,留存拆分的内容
    char* strcopy = malloc(strlen(str) + 1);
    if (!strcopy) {
        free(ar);
        return NULL;
    }
    strcpy(strcopy, str);

    char* token = strtok(strcopy, delim_str);
    for (int k = 0; k < token_count; k++) {
        // 拷贝每个token到单独的动态内存
        ar[k] = malloc(strlen(token) + 1);
        strcpy(ar[k], token);
        token = strtok(NULL, delim_str);
    }
    // 临时的strcopy可以释放了,因为每个token已经单独拷贝
    free(strcopy);

    for (int n = 0; n < token_count; n++) {
        printf("ar[%d] is %s\n", n, ar[n]);
    }
  
    return ar;
}

int main(){
    int token_num = 4;
    char** tokens = get_tokens("++All+Along+the+Watchtower++", '+', token_num);

    for (int k = 0; k < token_num; k++) {
        printf("tokens[%d] is this %s\n", k, tokens[k]);
    }

    // 使用完后手动释放动态内存,避免泄漏
    for (int k = 0; k < token_num; k++) {
        free(tokens[k]);
    }
    free(tokens);

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 16:48:02