【问题标题】:How strsep works in C?strsep 如何在 C 中工作?
【发布时间】:2018-11-27 15:32:44
【问题描述】:

我正在创建一个程序,该程序在启动时会使用 scanf 输入命令和一些参数,并使用这些参数调用 execvp。 我正在使用 strsep 执行此操作。 我将字符串存储在一个数组(char *)中,然后我想将它拆分并将令牌存储在一个新数组中(这次它是一个数组 [],所以我可以将它与 execvp 一起使用)。 用 scanf 保存的参数应该是终端命令(如 "ls" 和 "-l" ecc,"pwd"... 但是变量保存在 PATH) 中,所以它们用 "​​ " 分隔。

Ex : 

./mystring  
Type arguments : " ls -l "

这是一个示例,仅用于指定将是哪种输入。 我将单独执行 execvp,我需要帮助将字符串拆分为标记。 这是代码:

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

int main()
{
 fflush(NULL); //to clean streams
 printf("type the command to start (and arguments if required) \n");
 char **st;
 char dest[10];
 scanf("%s",*st);
 int i;
 for (i=0;(dest[i]=strsep(st," "))!=NULL;i++)
    continue;
 for (int c=0;c<i;c++) printf(" arg %d : [%s] ",c,dest[c]);
 return 0;
}

第 5 行和第 6 行需要调用 strsepdest[10] 中的 10 是符号。

第 7 行将输入存储在 st 中。

第 9 行应拆分为 " " 并将命令和参数存储在 dest[I](我将传递给 execvp)中。

第 11 行打印 dest 存储的内容。

这是可悲的输出:

./mystring 
type the command to start (and arguments if required) 
Segmentation fault: 11

我不明白 strsep 是如何工作的,有人可以帮助我吗?

【问题讨论】:

  • 请不要在代码中这样写行号;使用您的代码很痛苦。如果需要数字,最好将它们制成 cmets。
  • char st[20];scanf("%19s",st) 这样会更好
  • fflush(NULL); //to clean streams - 你从哪里读到应该这样做?
  • 为什么需要这样做?
  • @EdHeal 嗯,这是一个很好的问题,我想首先使用 scanf 清理打开的流,因为它通常有很多问题,这是一个奇怪的功能,我不知道它是什么尤其是,我不知道它在main的开头是没用的。

标签: c string split strsep


【解决方案1】:

您需要传递strsep() 指向要分析的字符串的指针。这意味着更像:

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

int main(void)
{
    printf("type the command to start (and arguments if required)\n");
    char *dest[10];
    char line[4096];
    if (fgets(line, sizeof(line), stdin) == 0)
        return 1;
    line[strcspn(line, "\n")] = '\0';  /* Zap trailing newline */
    char *st = line;
    int i;
    for (i = 0; i < 10 && (dest[i] = strsep(&st, " ")) != NULL; i++)
        ;
    for (int c = 0; c < i; c++)
        printf(" arg %d : [%s]\n", c, dest[c]);
    return 0;
}

请注意对destst 的更改——以及添加空格以使代码更易于阅读(以及输出中的换行符)。我也删除了奇怪且不相关的fflush(NULL) — 当程序启动时,缓冲区不需要刷新。该代码从输入中删除换行符; scanf() 不会包含任何换行符。问题中的符号scanf("%s", *st); 只会从输入中读取一个单词,即使假设*st 指向一些分配的内存(在问题中,它没有)。

请注意,macOS 手册页中对 strsep() 的描述是:

char *strsep(char **stringp, const char *delim);

strsep() 函数在*stringp 引用的字符串中定位第一次出现的 字符串delim 中的任何字符(或终止'\0' 字符)并将其替换为 '\0'。分隔符后的下一个字符的位置(或 NULL,如果结束 已到达字符串)存储在*stringp 中。返回*stringp的原始值。

这意味着您需要传递指向char * 变量的指针,而不是char ** 变量的值。 macOS 手册页还包含一个显示类似代码的示例,将&amp;string 传递给strsep(),其中char *string = …;。有时阅读手册页是一门艺术——在手册页的字里行间阅读。

上面的代码(现已测试)可以运行产生:

$ ./ss53
type the command to start (and arguments if required)
command-name-is-long a short arg
 arg 0 : [command-name-is-long]
 arg 1 : [a]
 arg 2 : [short]
 arg 3 : [arg]
$

【讨论】:

  • 非常感谢,我要学习你写的东西,我很快就会回来:'),但是我从来没有用过fgets,是不是像scanf?为什么在下面返回1?跨度>
  • 我想 line[strcspn(line, "\n")] = '\0'; 替换 \n \0。我认为你这样做是因为通过这种方式字符串被可能的问题清除,所以如果这是正确的 for (i = 0; i 应该拆分并存储在 \0" ".
  • fgets() 是读取一行输入的标准 C 方法,这似乎是您想要的。 scanf("%s", str) 不读一行;它读一个词。由于 fgets() 在 EOF 上返回 NULL(或错误),我从 main() 返回 1 — 没有错误消息,因为我在这段代码中很懒惰。 line[strcspn(line, "\n")] = '\0'; 确实删除了尾随换行符;如果您愿意,可以使用"\r\n",它将在输入中查找 CR ('\r') 或 NL ('\n'),以先到者为准。但是,这通常不是必需的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-09
  • 2018-07-17
  • 2016-02-04
  • 2016-06-13
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多