将 String 解析为 C 中的标记 - 出了什么问题?
Parsing String into tokens in C - what's going wrong?
我正在尝试将字符串拆分为标记以创建参数数组。我当前的实现如下(path
是正在读取可选参数的用户可执行文件的路径):
// ARG_MAX as defined in limits.h
int execute(char *exe) {
printf("args to %s: ", exe);
char *args = malloc(ARG_MAX);
scanf("%s", args);
char *argv[ARG_MAX];
int i = 0;
argv[i++] = exe;
while ((argv[i] = strsep(&args, " \t")) != NULL) {
i++;
}
free(args);
execv(exe, argv);
return 0;
}
让我感到困惑的是,根据我对 strsep
的理解,这应该按预期工作,并且在一定程度上确实如此,当测试时它准确地将 tokens[0]
分配为 path
,并且 tokens[1]
是任何 tokens_s
直到第一个白色 space 字符。
当在 space 之后输入另一个参数时,它不会分配到 tokens[2]
中,后续参数依此类推。
我似乎无法发现我在使用 strsep
时做错了什么而没有实现所需的功能?
输入:
exe = "/usr/bin/ps"
args = "-e -l"
输出:
exec ps -e
多个错误:
您必须阅读带有 fgets()
的参数才能阅读多个单词。
您必须为 strsep()
使用一个临时变量,这样您就可以将原始指针从 malloc()
传回 free()
,或者简单地使用本地数组。
这是更正后的版本:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
// ARG_MAX as defined in limits.h
int execute(char *exe) {
char args[ARG_MAX + 1];
printf("args to %s: ", exe);
fflush(stdout);
if (fgets(args, sizeof args, stdin)) {
char *argv[ARG_MAX / 2];
char *p;
int i = 0;
argv[i++] = exe;
p = args;
args[strcspn(args, "\n")] = '[=10=]'; // strip the newline if present
while ((argv[i] = strsep(&p, " \t")) != NULL) {
i++;
}
printf("argv: ");
for (i = 0; argv[i]; i++)
printf(" '%s'", argv[i]);
printf("\n");
execv(exe, argv);
printf("exec failed: %s\n", strerror(errno));
} else {
printf("cannot read input\n");
}
return 0;
}
int main(int argc, char *argv[]) {
char *exe = "printf";
if (argc > 1)
exe = argv[1];
return execute(exe);
}
备注:
如果程序成功,execv
将不会 return 到您的程序。
strsep
不会折叠分隔符序列,如果您有额外的空格,您的方法将创建额外的参数。
编辑: 如果在到达 运行 execute
之前从 stdin
读取输入,并且如果此类输入是通过调用执行的到 scanf()
,stdin
缓冲区中可能有一个待处理的换行符,fgets()
会将其读取为空行。如果是这种情况,请在调用 printf()
:
之前先刷新挂起的输入
int c;
while ((c = getchar()) != EOF && c != '\n') {
continue;
}
我正在尝试将字符串拆分为标记以创建参数数组。我当前的实现如下(path
是正在读取可选参数的用户可执行文件的路径):
// ARG_MAX as defined in limits.h
int execute(char *exe) {
printf("args to %s: ", exe);
char *args = malloc(ARG_MAX);
scanf("%s", args);
char *argv[ARG_MAX];
int i = 0;
argv[i++] = exe;
while ((argv[i] = strsep(&args, " \t")) != NULL) {
i++;
}
free(args);
execv(exe, argv);
return 0;
}
让我感到困惑的是,根据我对 strsep
的理解,这应该按预期工作,并且在一定程度上确实如此,当测试时它准确地将 tokens[0]
分配为 path
,并且 tokens[1]
是任何 tokens_s
直到第一个白色 space 字符。
当在 space 之后输入另一个参数时,它不会分配到 tokens[2]
中,后续参数依此类推。
我似乎无法发现我在使用 strsep
时做错了什么而没有实现所需的功能?
输入:
exe = "/usr/bin/ps"
args = "-e -l"
输出:
exec ps -e
多个错误:
您必须阅读带有
fgets()
的参数才能阅读多个单词。您必须为
strsep()
使用一个临时变量,这样您就可以将原始指针从malloc()
传回free()
,或者简单地使用本地数组。
这是更正后的版本:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
// ARG_MAX as defined in limits.h
int execute(char *exe) {
char args[ARG_MAX + 1];
printf("args to %s: ", exe);
fflush(stdout);
if (fgets(args, sizeof args, stdin)) {
char *argv[ARG_MAX / 2];
char *p;
int i = 0;
argv[i++] = exe;
p = args;
args[strcspn(args, "\n")] = '[=10=]'; // strip the newline if present
while ((argv[i] = strsep(&p, " \t")) != NULL) {
i++;
}
printf("argv: ");
for (i = 0; argv[i]; i++)
printf(" '%s'", argv[i]);
printf("\n");
execv(exe, argv);
printf("exec failed: %s\n", strerror(errno));
} else {
printf("cannot read input\n");
}
return 0;
}
int main(int argc, char *argv[]) {
char *exe = "printf";
if (argc > 1)
exe = argv[1];
return execute(exe);
}
备注:
-
如果程序成功,
execv
将不会 return 到您的程序。strsep
不会折叠分隔符序列,如果您有额外的空格,您的方法将创建额外的参数。
编辑: 如果在到达 运行 execute
之前从 stdin
读取输入,并且如果此类输入是通过调用执行的到 scanf()
,stdin
缓冲区中可能有一个待处理的换行符,fgets()
会将其读取为空行。如果是这种情况,请在调用 printf()
:
int c;
while ((c = getchar()) != EOF && c != '\n') {
continue;
}