数组的地址以及其所有的元素的地址不是都是常量吗?
如果是这样,那么在像下面这样的声明中:
char *const argv[]
“const”限定符是不是多余的?
不,char *const argv[]
中的const
并非是多余的。
首先,在C语言中const
和“constant” 事实上是两个不同的概念,尽管const
关键字显然派生自单词 “constant”。一个常量表达式可以在编译时计算得出。 const
真正的含义是“只读”。例如:
const int r = rand();
是完全合法的。
是的,数组的地址--就像任何对象的地址一样--是只读的。但这并不意味着数组的值(由其元素的值组成)是只读的,就像任何其他对象一样,并不一定是只读的。
考虑以下三个声明:
char *arr1[10];
char *const arr2[10];
const char *arr3[10];
arr1
是一个包含10个指向char
的指针的数组。你可以修改这些char*
元素,同时也可以修改这些元素所指向的对象。
arr2
是一个包含指向常量(只读)char
指针的数组。这意味着一旦初始化后,你无法修改数组的char*
元素,但你仍然可以修改这些元素所指向的char
对象或数组。
而arr3
是一个指向常量char
的指针数组;你可以修改数组元素,但无法修改它们所指向的内容。
现在你使用了名为argv
的名称,这表明你正在谈论main
的第二个参数,这对结果有巨大影响。语言规定main
的第二个参数是
char *argv[]
或等价地说,
char **argv
没有const
。您可以尝试添加一个,但最好遵循标准指定的形式。(更新:我从您的评论中看到,您正在询问getopt()
的argv
参数,该参数被定义为char * const argv []
。)
由于它是作为数组定义的参数,另一个规则也适用:将参数定义为某种类型的数组会被“调整”为该类型的指针。(此规则仅适用于参数。)这不是运行时转换。函数不能具有数组类型的参数。
C语言中数组和指针之间的关系可能令人困惑 - 还存在许多错误信息。最重要的是要记住:数组不是指针。
comp.lang.c FAQ 的第6节详细解释了细节,非常出色。
数组的地址以及所有元素的地址不是一直都是固定的吗?
是的,这对于任何在C
中的对象都是适用的。请记住,我们所说的对象是指一个内存位置,具有值并由标识符引用。标识符绑定到一个固定的内存位置,在其作用域内无法更改。您可以更改对象的值。
int a = 4;
a = 6; // legal. you can change the value of the object
&a = 23456; // illegal. you cannot change the address of the object
char *const argv[]
char *const *argv
argv
是一个指向char *const
类型对象的指针,即指向字符的常量指针。很明显,char *const *argv
和char **argv
是不同的。让我们看另一个例子。char *const argv[10];
argv
作为一个由10个指向字符的常量指针组成的数组。这意味着您必须初始化该数组,并且无法随后更改指针以指向不同的字符。但是,这与数组元素的地址无关。char c = 'A';
char d = 'B';
char *const argv[2] = {&c, &d};
argv = &c; // illegal. you cannot the change the address of an object
argv[0] = &d; // illegal. you cannot change the value of the array element
*argv[0] = 'C'; // legal. you change the value pointed to by the element
没有使用const
限定词,char *argv[2]
表示一个包含2
个字符指针的数组。
这显然与我们有了如上所述的const
限定词时不同。因此,回答你的第二个问题,const
限定词并不是多余的。这是因为const
限定词限定了数组元素的类型。
char *const argv[]
是指向 char
类型的指针数组,其中指针是常量(无法更改它们指向内存中的其他字符串)。因此,const
关键字使得数组中的指针为常量。
const
对象可以被初始化,但不能通过给它赋值来修改它——甚至不能修改一次。const int n = 42;
是有效的;而const int n; n = 42;
则无效。 - Keith Thompson