为什么main()函数的参数argv是char*[]类型而不是const char*[]类型?

30

当我编写并执行以下代码时,编译器报错:

从字符串常量转换为 char* 已经被弃用

int main()  
{  
  char *p;  
  p=new char[5];  
  p="how are you";  
  cout<< p;  
  return 0;  
}  

这意味着我应该写const char *

但是当我们使用char* argv[]将参数传递到main时,我们不会写成const char *argv []

为什么?


11
你的问题很有趣,但前面的代码与问题无关。无论你是否允许将字符串常量分配给非常量指针,都与main函数的参数类型无关。(此外,你的代码存在内存泄漏问题。) - Rob Kennedy
4
还有一点你忽略了:我们不会向main函数传递参数。在程序中调用main函数是不合法的。调用main函数是编译器为我们设置的,我们不能自己调用它。 - Rob Kennedy
此外,我认为你只是在浪费内存使用new调用。该字符串从堆栈中获取自己的内存。 - Kyle
嘿,谢谢大家。我们是从终端传递参数到主函数对吧? - Frustrated Coder
1
但是你传递的不是一个“const char*”,而是一系列字符。即使平台将参数以只读内存的形式传递给程序,在你的程序进入“main”之前会发生很多步骤,其中一个步骤很容易是“将参数复制到我可以写入它们的地方”。 - Dennis Zickefoose
显示剩余3条评论
5个回答

13

因为 argv[] 不是 const 类型的。而且它肯定不是一个(静态)字符串字面量,因为它是在运行时创建的。

你声明了一个 char * 指针,然后将一个字符串字面量赋给它,这个字面量被定义为常量;实际数据存储在只读内存中。

int main(int argc, char **argv)  {
    // Yes, I know I'm not checking anything - just a demo
    argv[1][0] = 'f';
    std::cout << argv[1] << std::endl;
}

输入:

g++ -o test test.cc

./test hoo

输出:

foo

这并不是关于为什么你要更改argv的评论,但这确实是可能的。


4
如果您接受任何敏感数据作为程序参数,那么您需要更改 argv - Šimon Tóth
1
@Let_Me_Be - 这有很多原因,我只是觉得它们与讨论无关,所以我说我不会对这个方面发表评论。 - Brian Roach

11

出于历史原因,更改main()的签名将破坏太多现有代码。而且有可能某些实现允许您从代码中更改main的参数。但是像这样的代码:

char * p = "helllo";
* p = 'x';

这总是不合法的,因为您不允许像那样操纵字符串文字,因此指针应该是指向const char。


你对 main() 的理解是错误的。main() 不能仅通过字符串常量来调用,因此参数没有必要加上 const。请参考我的回答。 - Šimon Tóth
1
我的观点(我认为OP所问的)是可以更改标准使它们成为const,但不会这样做。 - user2100815
4
但这不是原因。重新编写 argv[] 是一种常见技巧。如果你接受任何敏感数据作为参数,则实际上需要这样做。因此,原因并不是历史原因,如果不能这样做,就毫无意义。 - Šimon Tóth
@Let_ 我所说的是:允许你从代码中更改 main 函数的参数。 - user2100815
改变 main 函数会导致几乎所有通用程序崩溃。 - MarcusJ
@Let_Me_Be 重写 argv 是否保证原始数据不会通过 procfs 或其他机制可见? - Greg Nisbet

2
为什么在将char*赋值给字符串时需要将其设置为常量?
因为这样的字面字符串(例如“hi”,“hello what's going on”等)存储在您的exe文件的只读段中。因此,指向它们的指针需要指向常量字符(例如,不能更改它们)。

1
你正在将一个字符串常量(const char*)赋值给一个非常量字符串指针(char *p)。这将允许你修改字符串常量,例如通过执行p[0] = 'n'
不管怎样,为什么不使用std::string呢?(你似乎在使用C++)。

你说得对,char* 真的很丑陋,但我正在为考试做准备,他们可能会问到这个。 - Frustrated Coder

1
如果您查看像execve这样的执行函数,您会发现它们实际上不接受const char*作为参数,而是确实需要char*,因此您不能使用字符串常量来调用main

4
你不能调用 main 函数。 - Lightness Races in Orbit
9
目前 Linux 的 exec(3) 手册页面 上实际上将这些参数标记为 const。由于执行进程的内存与被执行进程的内存是不同的,因此无论如何都需要进行复制,所以这并不会有任何问题。 - MvG

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