在C中的数组中存储为使用strtok的结果

Storing as using result of strtok in array in C

我正在尝试使用 strtok 拆分来自 fgets 的输入,并将结果存储在一个数组中,即 newArgs,这样我就可以调用 execvp 并实质上执行由 fgets 传递的输入。

例如ls -la 将映射到 /bin/ls -la 并正确执行。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char * argv[])
{
    char buff[1024];
    fgets(buff, 1024, stdin);
    buff[strcspn(buff, "\n")] = 0;
    printf("%s\n", buff);
    printf("%d\n", strlen(buff));
    char *newArgs[30];
    char *token;
    char delim[2] = " ";
    token = strtok(buff, delim);
    int i = 0;
    while(token != NULL) 
    {
        if(newArgs[i])
        {
            sprintf(newArgs[i], "%s", token);
            printf("%s\n", newArgs[i]); 
        }
        token = strtok(NULL, delim);
        i++;
    }
    execvp(newArgs[0], newArgs);

    return 0;
}

尽管我正在检查 newArgs[i] 是否存在,但我总是遇到分段错误,这有点奇怪。关于出了什么问题有什么想法吗?

您没有为 newArgs 的每个元素分配任何内存。尝试使用多维数组,例如 newArgs[30][100]。不要忘记确保它们以 null 结尾。

我看到的问题:

  1. 您正在使用 newArgs[i] 的未初始化值。你有:

    char *newArgs[30];
    

    这是一个未初始化指针数组。然后,您继续将它们用作:

    if(newArgs[i])
    

    这是导致未定义行为的原因。您可以通过将指针初始化为 NULL 来解决此问题。

    char *newArgs[30] = {};
    
  2. 在调用

    之前,您还没有为 newArgs[i] 分配内存
    sprintf(newArgs[i], "%s", token);
    

    这也是导致未定义行为的原因。您可以使用以下方法解决该问题:

    newArgs[i] = strdup(token);
    
  3. 传递给 execvp 的参数列表必须包含 NULL 指针。

    来自 http://linux.die.net/man/3/execvp(强调我的):

    The execv(), execvp(), and execvpe() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a NULL pointer.

    您缺少最后一个要求。您需要确保 newArgs 的元素之一是 NULL 指针。如果将指针初始化为 NULL,此问题将消失。

在将 newArgs 存储到字符串之前,您没有为它分配内存。 添加

    newArgs[i] = malloc(strlen(token));

for 循环中的 if 语句之前。

绝对没有理由复制您在 buff 中找到的标记。

情况并非总是如此,但确实如此:buffexecvp 之前没有被修改,execvp 没有在 return 之前被修改。知道何时不复制 C 字符串不如知道如何复制 C 字符串有用,但两者都很重要。

不复制字符串将大大简化代码。您需要做的就是填写您将传递给 execvp:

的字符串数组
 char* args[30]; /* Think about dynamic allocation instead */
 char** arg = &args[0];
 *arg = strtok(buff, " ");
 while (*arg++) {
   /* Should check for overflow of the args array */
   *arg = strtok(NULL, " ");
 }
 execvp(args[0], args);

请注意,上面的代码会将 strtok 编辑的 NULL return 存储在 args 数组的末尾。这是 execvp 所要求的,它需要知道最后一个参数在哪里。