【问题标题】:What is an array of constant pointers in C?什么是 C 中的常量指针数组?
【发布时间】:2014-05-10 21:32:34
【问题描述】:

数组的地址以及它的所有元素的地址难道不是不变的吗?

如果是这样,在如下声明中:

char *const argv[] 

const 限定符不是多余的吗?

【问题讨论】:

    标签: c arrays function pointers constants


    【解决方案1】:

    不,char *const argv[] 中的 const 不是多余的。

    首先,const 和“constant”在 C 中实际上是两个不同的东西,尽管 const 关键字显然是从“constant”这个词派生的。 常量表达式是可以在编译时计算的。 const 真正的意思是“只读”。例如:

    const int r = rand();
    

    完全合法。

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

    考虑这三个声明:

    char *arr1[10];
    char *const arr2[10];
    const char *arr3[10];
    

    arr1 是指向char 的指针的 10 元素数组。您可以修改char* 元素并且您可以修改这些元素指向的对象。

    arr2 是一个由const(只读)指针组成的数组,指向char。这意味着您无法修改数组的 char* 元素(一旦它们被初始化)——但您仍然可以修改这些元素指向的 char 对象或数组。

    arr3 是一个指向const char 的指针数组;您可以修改数组元素,但不能修改它们指向的内容。

    现在您使用名称argv 的事实表明您正在谈论main 的第二个参数,这对此有很大的影响。语言指定main的第二个参数是

    char *argv[]
    

    或者,等价的,

    char **argv
    

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

    因为它是一个定义为数组的参数,所以另一个规则开始起作用:定义为某种类型数组的参数“调整”为指向该类型的指针。 (此规则应用于参数。)这不是运行时转换。函数不能有数组类型的参数。

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

    comp.lang.c FAQ 的第 6 节对细节做了很好的解释。

    【讨论】:

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

    不是数组的地址,因此也不是所有元素的地址 还是不变的?

    是的,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 限定符限定了数组元素的类型。

    【讨论】:

    • 感谢您出色的说明和宝贵的额外指点!
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 2023-04-02
      • 2022-11-10
      • 1970-01-01
      • 2011-11-15
      • 2021-10-02
      相关资源
      最近更新 更多