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
相关产品推荐
相关产品推荐

