C语言如何使用sscanf拆分含$标识的字符串并处理缺省情况
sscanf拆分含$标识字符串的实现方案
原有代码问题分析
原有格式化串存在两个核心缺陷:
%m[^$]为否定匹配集,要求$前至少存在1个非$字符才会匹配成功。当输入以$开头(如$HOME)时,第一步匹配直接失败,sscanf直接终止执行,后续所有参数都不会被赋值,最终拿到的是未初始化的野指针。- 末尾的
%*m属于非法写法:m修饰符的作用是要求库函数动态申请内存存储匹配结果,必须传入对应的char**参数接收指针,搭配*抑制赋值属于未定义行为,无法正确获取后缀内容。
解决方案
我们可以通过匹配返回值判断+偏移量记录的方式兼容所有场景,代码实现如下:
#include <stdio.h> #include <string.h> #include <stdlib.h> void split_env_str(const char *input) { // 所有接收指针先初始化为NULL,不存在的分段默认就是NULL char *prefix = NULL, *env_name = NULL, *suffix = NULL; int match_offset = 0; int match_cnt; // 先尝试匹配有前缀的场景:[前缀]$[变量名] match_cnt = sscanf(input, "%m[^$]$%m[_a-zA-Z0-9]%n", &prefix, &env_name, &match_offset); // 匹配失败的话尝试匹配无前缀(开头就是$)的场景 if (match_cnt < 2 && input[0] == '$') { match_cnt = sscanf(input + 1, "%m[_a-zA-Z0-9]%n", &env_name, &match_offset); match_offset += 1; // 补回开头$的长度偏移 } // 提取剩余后缀内容 if (match_cnt >= 1 && input[match_offset] != '\0') { suffix = strdup(input + match_offset); } // 此处为测试输出逻辑,实际使用可根据需求返回三个指针 printf("前缀:%s\n", prefix ? prefix : "NULL"); printf("变量名:%s\n", env_name ? env_name : "NULL"); printf("后缀:%s\n", suffix ? suffix : "NULL"); // 使用完后必须释放动态申请的内存 free(prefix); free(env_name); free(suffix); }
适配场景验证
上述代码可覆盖所有你提到的输入场景:
- 输入
something$HOME/something2:前缀为something,变量名为HOME,后缀为/something2 - 输入
$HOME:前缀为NULL,变量名为HOME,后缀为NULL - 输入
$HOME/something:前缀为NULL,变量名为HOME,后缀为/something - 输入
something$HOME:前缀为something,变量名为HOME,后缀为NULL
注意事项
- 代码用到的
m修饰符为POSIX标准扩展,如果需要兼容纯C标准平台,可以自行替换为固定大小缓冲区+长度限制的写法 - 所有通过
m修饰符和strdup申请的内存,使用完成后必须调用free释放,避免内存泄漏
内容的提问来源于stack exchange,提问作者user15890225
相关产品推荐
相关产品推荐

