复制一个字符串数组(或将它们复制到另一个数组中)?

4
我需要获取启动进程时传递的参数。这意味着我需要argv[]中除了第一个(即进程名称)之外的所有参数。
由于它是char * argv[]类型,所以我遇到了复制的困难。有人可以给我简要说明如何正确地实现它,或者提供一小段代码片段。与其头疼不如寻求帮助。
编辑:
澄清我的问题:
关键是我需要除了argv的第一个参数之外的所有参数。因此,我不能只将它发送到其他进程,因为我实际上将其用作execv的参数。

execv函数使用相同的参数列表,包括argv [0]。唯一需要复制它的原因是如果您需要更改argv [0]。 - Jim Balter
@fizzer execv 意味着一个 POSIX 系统,并且 POSIX 标准规定:“该数组的最后一个成员应为 NULL 指针”-- 因此可以假定。 - Jim Balter
@Jim,我不明白这怎么可能。我的第一个程序将有参数列表'pname otherpname -arg1 -arg2 -arg3',我想使用execv调用带有-arg1 -arg2 -arg3的otherpname。 - Blackbinary
如果@Blackbinary的第一个程序的参数列表是'pname otherpname -arg1 -arg2 -arg3',那么你确实可以像fizzer所说的那样:只需将argv+1传递给execv即可。在问题中包含所有细节以最大化获得帮助是个好主意。 - Jim Balter
那么,实际上它是一个命令,如下:scavenger USER=2.00 BUSY= 50.00 IDLE=30.00 ls -l。所以我需要删掉4个命令。但如果原理相同,我可以只传递argv+4吗? - Blackbinary
显示剩余12条评论
8个回答

5

没必要复制字符串 - 它们将在程序生命周期内保持不变,您也无权修改它们。只需将 argc 和 argv 传递给需要它们的人,或将它们复制到全局变量中。

#include <stdio.h>

int myargc;
char **myargv;

void print_args()
{
    int i;
    for (i = 1; i < myargc; ++i) {
        puts(myargv[i]);
    }
}    


int main(int argc, char **argv)
{
    myargc = argc;
    myargv = argv;

    print_args();

    return 0;
}    

3
请注意,argv是一个char **类型的变量,如果需要,您可以将argv指针存储到此类型的全局变量中。
否则,如果您需要复制它,您需要分配一个数组并复制指针。如果您不需要复制字符串本身,可以像这样操作:
char **copy_of_argv = malloc(sizeof(char *) * (argc-1));
memcpy(copy_of_argv, argv + 1, sizeof(char *) * (argc - 1));

虽然您可以选择为终止NULL指针分配额外的插槽,但这并非必须。

如果出于某种未知原因您需要复制字符串,那么就会稍微复杂一些:

int i;
char **copy_of_argv = malloc(sizeof(char *) * (argc-1));
for (i = 0; i < argc - 1; i++) {
    copy_of_argv[i] = strdup(argv[i + 1]);
}

(再次提醒,你可能需要为哨兵分配一个额外的插槽。)

我做了这个:http://pastebin.com/UAeRuS10 但是在memcopy上出现了段错误 :(. 有什么想法吗? - Blackbinary
首先,如果nArgs小于argc-5,则您可能正在访问超出argv结尾的内容。其次,在malloc中忘记了括号,因此您最终分配了nArgs个char *和1个字节的空间,而不是(nArgs+1)个char *的空间。第三,在设置args[nArgs+1]之前,您必须至少malloc sizeof(char*)*(nArgs+2)个字节。 - Anomie

3
您在评论中写道:“我的第一个程序将具有参数列表'pname otherpname -arg1 -arg2 -arg3',我想使用execv调用带有-arg1 -arg2 -arg3的otherpname。” 在这种情况下,您要传递给execv的参数列表是[otherpname -arg1 -arg2 -arg3] ... 传递给execv的参数列表正是otherpname的主要例程将视为argv的内容,并且必须包括argv [0],这通常是程序名称。方便的是,该列表恰好是argv + 1所指向的内容。不需要复制任何内容。
[编辑] 然而,您确实遇到了要将其作为execv的第一个参数传递的问题 - 要执行的程序的文件名。otherpname要么是全路径名,要么就应该使用execvp,在PATH中搜索程序。

1
我非常感谢你的帮助(认真地说,你已经帮了将近一个小时)。你是对的,诀窍就在于使用execvp。我认为我最大的障碍是意识到无论我指向argv的哪一部分,它都包含列表的其余部分。因此,argv+5包含5之后的所有参数。谢谢。 - Blackbinary

2
如果你想要可修改的参数副本,请按照以下步骤操作:
    #include <stdio.h>

    void main(int argc, char** argv) {
            int myargc = argc;
            char** myargv = malloc( (argc-1)*sizeof(void*));
            int i;
            for(i=1; i<argc; i++) {
                    int len = strlen(argv[i]);
                    myargv[i-1] = malloc(len+1);
                    memcpy(myargv[i-1], argv[i], len+1); // +1 so \0 copied too.
            }               
            getch();
    }

需要在所有复制的char*末尾添加一个0。 - bhathiya-perera
@JaDogg 谢谢,我已经修改了memcpy行。非常有用的评论。 - Bernd Elkemann

1

很有趣,你这么说:

关键是我需要除了 argv 的第一个参数以外的所有参数。所以我不能只是把它发送到其他进程中,因为我实际上正在将其用作 execv 的参数

这听起来很像我正在做的事情,我想设置 LD_LIBRARY_PATH 然后使用我的自己的 ld.so 运行二进制文件,以便根本不使用默认系统共享库。execve 的参数是我的 ld.so 副本,但一旦真正的二进制文件开始运行,我希望它的 argv 看起来很正常(和环境变量)。以下是我在 Linux 上的实现方式:

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

#define PYBINARY "/data1/packages/python272/bin/python"
#define LDSO "/data1/packages/python272/lib/ld-linux-x86-64.so.2"
#define MYLIBS "/data1/packages/python272/lib"

extern char **environ;

main(int argc, char **argv, char **envp)
{
  int retcode;
  char **e;
  char **myargv;

  setenv("LD_LIBRARY_PATH",MYLIBS,1);
  setenv("_",PYBINARY,1);

  /* copy argv */
  int i = 0;
  myargv = (char **)malloc(sizeof(char *) * 100);
  for(;argv[i] != NULL; i++) {
    myargv[i+1] = (char *)malloc(sizeof(char) * (strlen(argv[i]) + 1));
    memcpy(myargv[i+1], argv[i], strlen(argv[i]));
  }
  myargv[i+1] = NULL;
  myargv[0] = LDSO;
  myargv[1] = PYBINARY;

  e = myargv;
  while (*e != NULL){
    printf("arg: %s\n",*e++);
  }

  retcode = execve(LDSO, myargv, environ);
  perror("exec2: execve() failed");
  exit(1);
}

如果您将以下内容放入test.py文件中:
import sys
print sys.argv
import os
print os.environ["_"]

使用 python -i test.py 运行它,您将获得与 ./mypy -i test.py 相同的结果,因此任何依赖于 argv 或 envp 的内容都不会出现问题。


sizeof(char)的定义总是为1。 - luser droog

0

对于execv,可以像这样

#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    int i;
    char** myargs;

    if (argc <= 0)
    {
        return EXIT_FAILURE;
    }

    myargs = malloc(sizeof *myargs * (argc + 1));

    myargs[0] = "your_program_name_here"; 
    for (i = 1; i < argc; ++i)
    {
        myargs[i] = argv[i];
    }
    myargs[argc] = 0;
    execv("/your/program/here", myargs);
    return EXIT_FAILURE;
}

0
如果你想访问其中一个 argv 字符串,请执行以下操作: printf("%s", argv[0]);

0

你需要对这些参数做什么?

arg1,arg[2],arg[3]等都是简单的C字符串(char*)。

如果你需要将它们复制到另一个数组中,可以使用strcpy函数(例如,strcpy(destination,arg[1])),但由于参数的值不会改变,您很可能不需要复制它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接