在C语言中,常量指针数组是什么?

10

数组的地址以及其所有的元素的地址不是都是常量吗?

如果是这样,那么在像下面这样的声明中:

char *const argv[] 

“const”限定符是不是多余的?

3个回答

17

不,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节详细解释了细节,非常出色。


4
“您所说的‘只读’实际上是指‘只写一次’,是这样吗?” - Eric Lippert
@Keith Thompson 谢谢您提供如此详细优秀的答案。它不仅回答了我的问题并消除了困惑,还指出了一些其他非常酷的事实(例如关于main函数参数的调整),这是我没有想到的。(虽然我的疑问并不是来自main()函数,而是来自库函数getopt:int getopt(int argc, char * const argv[], const char *optstring)。)谢谢! - Lavya
3
“只读”指的是对象无法通过其名称进行修改。const对象可以被初始化,但不能通过给它赋值来修改它——甚至不能修改一次。const int n = 42; 是有效的;而 const int n; n = 42; 则无效。 - Keith Thompson
@KeithThompson:谢谢你澄清了这一点。 - Eric Lippert
1
@KeithThompson 你写道:“arr3是一个指针数组”,但是arr被定义为:const char *arr3。这里有错误吗? - Stav Alfi
显示剩余2条评论

5

数组的地址以及所有元素的地址不是一直都是固定的吗?

是的,这对于任何在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 *argvchar **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限定词限定了数组元素的类型。


2
感谢您出色的澄清和宝贵的额外指导! - Lavya

2
不是的。char *const argv[] 是指向 char 类型的指针数组,其中指针是常量(无法更改它们指向内存中的其他字符串)。因此,const 关键字使得数组中的指针为常量。

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