2010-04-16 91 views
1

我正在写一个C程序。它从commandLine获取它的参数。我想改变代码中的commandLine参数。由于它们被定义为“const char *”,所以我无法使用“strcpy”,“memcpy”,......来更改它们。另外,我知道,我不能将它们的类型从“const char *”更改为“char * ”。 有什么方法可以改变它们吗?改变命令行参数

非常感谢你提前。

此致敬礼, 沙迪。

+1

为什么你需要改变命令行参数?如果您正在修改它们以传递到程序的另一部分,则可能需要复制并修改它。 – WildCrustacean 2010-04-16 17:27:06

+0

你有没有想过将参数复制到不同的变量并使用它? – Jacob 2010-04-16 17:27:32

回答

7

根据C99§5.1.2.2.1/ 1,为main签名

int main(int argc, char *argv[]) { /* ... */ } 

所以你允许删除const。只要不会导致比原始参数更长的字符串溢出,或尝试安装比最初传递的参数更多的参数。

其他人基本上是对的,你应该而不是创建一个副本。

+1

C没有的那些真棒向量之一? ;-) – 2010-04-16 17:43:25

+0

@James:rofl,一次为我处理太多问题提供了正确的方法。 – Potatoswatter 2010-04-16 17:47:00

+3

这个标准甚至不仅仅是从参数类型中推断出的内容,还特别指出:“参数argc和argv以及argv数组指向的字符串应该可以通过程序修改...” – 2010-04-16 18:05:59

1

不,你不能修改这些。但是,没有规则将它们复制到新的缓冲区并使用它们。

1

这可能并不重要,但不能用strcpy()和memcpy()都不能改变任何东西。后缀'cpy'是复制的简称(不出意外)。

关于更改argv指针,您当然可以更改指针,但为什么?如果你想让命令行参数不是所给出的东西,只需忽略它们,并使用你喜欢的任何值。还要注意,argv是一个参数,因此对main()是本地的;如果在其他地方需要它,则必须将其作为参数传递,或将其另存为全局变量。

+0

re。 “你不能用'strcpy()''改变任何东西;如果它没有改变任何东西,那将是毫无意义的。如果你做'strcpy(argv [0],“foo”);',它会改变('argv [0]'的内容)。 – Arkku 2010-04-16 20:42:22

0

如果将const char *更改为主函数的char *,则无关紧要。

只有一件你必须关心的是缓冲区溢出strcpy。

根据ELF规范(参见图3-31堆栈布局),http://refspecs.linuxbase.org/elf/abi386-4.pdf,功能参数区后面跟着环境值区。

argv是指向每个参数的指针数组,environ也是指向每个环境var = value字符串的指针数组。 所以布局如下。

argv[0] --> 1st parameter 
argv[1] --> 2nd parameter 
argv[2] --> 3rd parameter 
... 
NULL 
--------------------------------------- memory boundary between param and env 
environ[0] --> 1st env_var=env_value 
environ[1] --> 2nd env_var=env_value 
environ[2] --> 3rd env_var=env_value 
... 
NULL 

所以,如果你复制非常长的字符串到argv [0],它可以溢出param和env之间的边界。 在这种情况下,您必须将argv和环境内存区域移动到下面的另一个堆空间。 我从Postgresql开源代码中提取了以下示例代码。 ps_status.c)

char ** new_environ; 
char ** new_argv; 
char ** org_argv; 
int  i; 

new_argv = (char **) malloc((argc + 1) * sizeof(char *)); 
for (i = 0; i < argc; i++) 
    new_argv[i] = strdup(argv[i]); 
new_argv[argc] = NULL; 
org_argv = argv; 
argv = new_argv; 

new_environ = (char **) malloc((i + 1) * sizeof(char *)); 
for (i = 0; environ[i] != NULL; i++) 
    new_environ[i] = strdup(environ[i]); 
new_environ[i] = NULL; 
environ = new_environ; 

然后,你可以使用getopt的,GETENV等 他们将读取新分配的内存区域的值。另外,如果更改原始参数(org_argv [0]),则可以在ps命令中操作进程的输出名称。 (也在顶部,htop实用程序) 请参阅下文。

$> ps -ef | grep my_proc 
    dplee 10855 1 0 7월28 pts/2 00:00:16 my_proc i can manipulate this name