【问题标题】:Parsing String into tokens in C - what's going wrong?在 C 中将字符串解析为标记 - 出了什么问题?
【发布时间】:2017-03-29 22:24:20
【问题描述】:

我正在尝试将字符串拆分为标记以创建参数参数数组。我当前的实现如下(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 直到第一个空格字符是什么。

但是,当您在空格后输入另一个参数时,它不会分配到tokens[2],以此类推以用于后续参数。

我似乎无法发现我在使用 strsep 时做错了什么,但没有提供所需的功能?

输入: exe = "/usr/bin/ps" args = "-e -l"

输出: exec ps -e

【问题讨论】:

  • scanf("%s", args); 不会将'\t' 或空格保存到args。使用fgets()。建议发布您使用的输入。
  • 已添加输入。尝试过使用fgets(),但在提示我在命令行输入参数时,它只是继续而不提示?
  • 由于这篇文章缺乏完整的可编译代码,它只是使它变得比需要帮助更难。添加fgets() 可能是个问题,因为其他代码仍在使用scanf()。强烈建议发布显示问题的完整最小代码。
  • 对不起,代码没有太多额外的上下文,我已经更新以包含完整的方法。没有使用 scanf 运行其他代码

标签: c arrays argv strsep


【解决方案1】:

多个错误:

  • 您必须使用fgets() 读取参数才能读取多个单词。

  • 1234563

这是一个更正的版本:

#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")] = '\0';  // 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 如果成功,将不会返回您的程序。

  • strsep 不会折叠分隔符序列,如果您有多余的空格,您的方法将创建额外的参数。

编辑:如果在运行 execute 之前从 stdin 读取输入,并且如果通过调用 scanf() 执行此类输入,则在stdin 缓冲区和 fgets() 会将其读取为空行。如果是这种情况,请在调用 printf() 之前先刷新待处理的输入:

int c;
while ((c = getchar()) != EOF && c != '\n') {
    continue;
}

【讨论】:

  • 感谢这对如何正确实现它很有帮助,但是"args to %s", exe 永远不会被打印到控制台,而是程序在没有参数的情况下执行此代码?这是我一直试图使用fgets()getline() 的问题。在我上面的原始代码中,它仍然会打印提示并执行,但只识别第一个参数
  • @transiti0nary:如果添加fflush(stdout);,是否会打印提示?您确定可以从标准输入中读取吗?我更新了我的答案以使失败更加明确。
  • 是的,现在会打印提示,但它仍然不会停止输入,只是运行不带参数的 exec
  • 您的环境一定有问题。您能描述一下您是如何编译和执行上述程序的吗?我添加了一个简单的 main 函数进行测试,它在 OS/X 上运行良好
  • 该函数是用于提取数据并在给定文件路径上执行操作的更大函数库的一部分,尝试找出可能导致此类问题的原因可能比为了查看此处的所有其他功能以查看确切问题所在,我正在使用 gcc -o fileinfo ~/fileinfolib.c ~/fileinfo.c 在 OSX 上进行编译。 fileinfo.c 只包含一个 main 方法,它调用一个库函数向用户呈现文件信息,然后根据文件类型提示他们做什么。如果是exe,则调用此方法
猜你喜欢
  • 2023-03-05
  • 2012-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 2016-01-19
相关资源
最近更新 更多