【问题标题】:duplicating an array of strings (or copying them to another array)?复制字符串数组(或将它们复制到另一个数组)?
【发布时间】:2011-07-09 13:48:12
【问题描述】:

我需要在我的进程启动时传递给它的参数。 这意味着,在argv[] 中,除了第一个(这是我的进程的名称)之外,我需要其他所有内容。

我无法复制它,因为它是 char * argv[] 类型。 谁能给我有关如何正确执行此操作的要点,或者可能是一个小代码sn-p。比起用头撞墙,我更喜欢这样。

编辑:

澄清我的问题:

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

【问题讨论】:

  • 然后只需将 argv + 1 传递给 execv。那是减去第一个参数的数组。
  • execv 采用相同的参数列表,包括 argv[0]。您需要复制它的唯一原因是如果您需要更改 argv[0]。
  • @fizzer 错了—— execv 需要第 0 个参数。
  • 嗯——经过反思,他不能假设 argv 以空指针结尾,正如 execv 所要求的那样
  • 是的 - 他需要复印一份。

标签: c string pointers arguments


【解决方案1】:

如果您想要参数的可修改副本,请执行以下操作:

    #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
  • @JaDogg 谢谢,我更改了 memcpy 行。非常有用的评论。
【解决方案2】:

有趣的是你应该说:

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

这听起来很像我正在做的事情,我想设置 LD_LIBRARY_PATH,然后使用我自己的 ld.so 副本运行二进制文件,这样就根本不使用默认的系统共享库。执行的 arg 是我的 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。
【解决方案3】:

您在评论中写道:“我的第一个程序将具有参数列表 'pname otherpname -arg1 -arg2 -arg3',我想使用 execv 通过 -arg1 -arg2 -arg3 调用 otherpname。”在这种情况下,您要传递给 execv 的参数列表是 [otherpname -arg1 -arg2 -arg3] ...传递给 execv 的参数列表正是 otherpname 的主例程将看到的 argv,它必须包括 argv[0 ] 这通常是程序名称。方便的是,该列表正是 argv + 1 指向的内容……无需复制任何内容。

[编辑] 但是,您确实有将什么作为 its 第一个参数传递给 execv 的问题——要执行的程序的文件名。 otherpname 需要是完全限定的路径,或者您应该使用 execvp,它会在 PATH 中搜索程序。

【讨论】:

  • 感谢所有帮助(说真的,您已经帮助了将近一个小时)。没错,诀窍是使用 execvp。我认为我最大的障碍是意识到无论我指向 argv 的哪个部分,它都包含列表的其余部分。所以 argv+5 包含 5 之后的所有参数。谢谢。
【解决方案4】:

对于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;
}

【讨论】:

    【解决方案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;
    }    
    

    【讨论】:

      【解决方案6】:

      你需要对参数做什么?

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

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

      【讨论】:

        【解决方案7】:

        注意argvchar **,如有必要,您可以将 argv 指针存储到此类型的全局变量。

        否则,要复制它,您需要分配一个数组并复制指针。如果您也不需要自己复制字符串,那么应该可以这样做:

        char **copy_of_argv = malloc(sizeof(char *) * (argc-1));
        memcpy(copy_of_argv, argv + 1, sizeof(char *) * (argc - 1));
        

        (尽管您可能希望也可能不希望在copy_of_argv 中为终止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]);
        }
        

        (同样,您可能想为哨兵分配一个额外的插槽)。

        【讨论】:

        • 我这样做了:pastebin.com/UAeRuS10 但我在 memcopy 上遇到了段错误 :(。有什么想法吗?
        • 一方面,您可能正在访问超出argv 的末尾,除非nArgs 小于argc-5。另一方面,您忘记了 malloc 中的括号,因此您最终为 nArgs char *s 加上 1 个字节分配空间,而不是为 (nAgrs+1) char *s 分配空间。第三,要设置args[nArgs+1],你必须至少分配sizeof(char *)*(nArgs+2)字节。
        【解决方案8】:

        如果您想访问其中一个 argv 字符串,请执行以下操作:

        printf("%s", argv[0]);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-27
          • 1970-01-01
          • 2015-08-22
          • 2015-06-06
          • 2020-09-04
          • 2017-09-13
          • 1970-01-01
          • 2012-08-15
          相关资源
          最近更新 更多