什么是C中的常量指针数组?

什么是C中的常量指针数组?,c,arrays,function,pointers,constants,C,Arrays,Function,Pointers,Constants,一个数组的地址,以及它的所有元素的地址,不也是常量吗 如果是,在声明中,如: char *const argv[] const限定符不是多余的吗?不,不是char*const argv[]是指向char的常量指针数组。因此,const使数组中的指针保持不变(不能将它们更改为指向内存中的其他字符串) 不是数组的地址,也不是数组中所有元素的地址 还是常量 是的,对于C中的任何对象都是如此。回想一下,这里所说的对象是指内存中具有值并由标识符引用的位置。标识符在其作用域中绑定到固定内存位置,您不能更

一个数组的地址,以及它的所有元素的地址,不也是常量吗

如果是,在声明中,如:

char *const argv[] 

const
限定符不是多余的吗?

不,不是
char*const argv[]
是指向
char
的常量指针数组。因此,
const
使数组中的指针保持不变(不能将它们更改为指向内存中的其他字符串)

不是数组的地址,也不是数组中所有元素的地址 还是常量

是的,对于
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 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
和“constant”在C语言中实际上是两个不同的词,尽管
const
关键字显然是从“constant”这个词派生出来的。常量表达式是可以在编译时计算的表达式
const实际上是“只读”的意思。例如:

const int r = rand();
这是完全合法的

是的,数组的地址——就像任何对象的地址一样——是只读的。但这并不意味着数组的值(由其元素的值组成)是只读的,就像任何其他对象都必须是只读的一样

考虑以下三项声明:

char *arr1[10];
char *const arr2[10];
const char *arr3[10];
arr1
是指向
char
的10元素指针数组。您可以修改
char*
元素,也可以修改这些元素指向的对象

arr2
是指向
char
常量(只读)指针数组。这意味着您不能修改数组的
char*
元素(一旦它们被初始化)——但您仍然可以修改这些元素指向的
char
对象或数组

arr3
是指向
const char
的指针数组;可以修改数组元素,但不能修改它们指向的对象

现在,您使用的名称是
argv
,这表明您正在讨论
main
的第二个参数,这对这一点有很大的影响。该语言指定
main
的第二个参数为

char *argv[]
或者,相当于

char **argv
没有
常量
。您可能不需要添加一个,但最好遵循标准指定的形式。(更新:我从您的评论中看到,您询问的是
getopt()
argv
参数,该参数定义为
char*const argv[]

由于它是一个定义为数组的参数,另一个规则也起作用:定义为某种类型数组的参数被“调整”为指向该类型的指针。(此规则仅适用于参数。)这不是运行时转换。函数不能具有数组类型的参数

在C语言中,数组和指针之间的关系可能会令人困惑——而且有很多错误信息。要记住的最重要的事情是数组不是指针


第6节对细节做了很好的解释。

这里所说的“只读”实际上是指“只写一次”,对吗?@Keith Thompson感谢您出色的详细回答。它不仅回答了我的问题,完全消除了困惑,而且还指出了一些我没有想到的其他非常酷的事实(例如关于调整main的论点)。(我的怀疑并非来自main(),而是来自库getopt函数:int-getopt(int-argc,char*const-argv[],const-char*optstring)。)谢谢@EricLippert:“只读”是指不能通过引用对象的名称来修改对象。可以初始化
const
对象。你不能通过给它赋值来修改它——一次也不能<代码>常数int n=42有效<代码>常量int n;n=42
不是。@KeithThompson:谢谢你澄清这一点。@KeithThompson你写的“并且arr3是一个指针数组”,但arr定义为:const char*arr3。有错误吗?感谢您的出色澄清和宝贵的额外提示!