C语言指针常量和指向常量的指针

指针常量本质是一个常量,而用指针修饰它,那么说明这个常量的值应该是一个指针。指针常量 的值是指针,这个值因为是常量,所以不能被赋值。因为指针常量是一个常量,在声明的时候一定要给它赋初值。一旦赋值,以后这个常量再也不能指向别的地址。下面的例子展示了指针常量不同于指向常量的指针:
int var;                        // 一个int类型的对象
int *const c_ptr = &var;     // 一个int类型指针常量
*c_ptr = 123;            // 合法:我们可以修改它所引用的对象
++c_ptr;                         // 错误:我们不能修改指针

当一个指针指向具有 const 限定的对象,称为指向常量的指针,可以修改该指针的值。然而,只能使用这样的指针来读取所指向的对象,但不能修改所指向的对象。因此,指向常量的指针常常被称为只读指针(read-only pointer)。所引用对象本身可以是常量,也可以不是常量。例子如下:
int var;                      //一个int类型的对象
const int c_var = 100,   // 一个int类型的常量对象
          *ptr_to_const;         // 一个指向常量的指针:指针本身不是常量!
ptr_to_const = &c_var;       // 合法:使得ptr_to_const指向c_var
var = 2 * *ptr_to_const;         // 合法:等效于var = 2 * c_var
ptr_to_const = &var;         // 合法:使得ptr_to_const指向var
if ( c_var < *ptr_to_const )  // 合法:“只读”方式获取
  *ptr_to_const = 77;    // 错误:我们不能使用ptr_to_const修改var,
                                         // 尽管var不是常量

类型修饰符和类型限定符可以以任何顺序排列。因此,下面的写法是合法的:
int const c_var = 100, *ptr_to_const;

赋值表达式 ptr_to_const=&var 必需采用隐式转换:int 指针值 &var 会自动地转换成左操作数的类型,也就是指向 const int 的指针。对于与之类似的类型操作数的运算符,编译器会隐式地将指向某一类型T的指针,转换为具有更多限定符的类型 T 的指针。

如果想将一个指针转换为有较少限定符的类型,必须使用显式的类型转换。下面的程序代码片段使用前面例子所声明的变量:
int *ptr = &var;             // 一个指向var的int指针
*ptr = 77;                      // 合法:ptr 不是一个只读指针
ptr_to_const = ptr;             // 合法:隐式地将ptr从指向int的指针
                                        // 转换为指向int常量的指针
*ptr_to_const = 77;             // 错误:不能通过一个只读指针修改一个变量
ptr = &c_var;               // 错误:不能隐式地将指向int常量的指针转换
                                        // 为指向int 的指针
ptr = (int *)&c_var;        // 合法:显式的指针类型转换总是可行的
*ptr = 200;                     // 尝试修改c_var:可能会造成运行错误

如果编译器将常量对象 c_var 放置在内存中的只读区域,那么最后一条语句将会引发运行错误。

也可以声明指向常量的常量指针,如下面函数原型的参数声明:
void func( const int * const c_ptr_to_const );

该函数的参数是只读指针,当该函数被调用时该只读指针参数会被初始化,并且在函数执行过程中保持该值不变。