hengai 阅读(810) 评论(8)
  自己在VCKBASE上,总是听到有人问 const int *pint const *pint *const p 有什么区别,我自己也回答了很多次,这次又看到有人问,想想自己应该记录下来,虽然这个问题很简单,几乎每一本讲 C 基础的书上都会说明。
  自己还没有(也不能完成)仔细的说出 const  有几种用法,但是我下面将会说出我所知道的用法。
下面的代码,使用 VC6 在 WindowsXP 上编译运行

1、用作变量修饰符
  const可以在定义变量时作为修饰符,用来表示该变量不可修改。需要注意的是:const修饰某个变量时,总是限定const所处位置的右侧。例如代码 const int nc = 0;  用来声明一个整型常量 nc,这个常量不可更改。假如执行下面的语句

int main(int argc, char* argv[])

{

  const int nc = 0;

  nc = 1;       //修改了常量 nc,不能编译过去

  return 0;

}


编译时会报错“l-value specifies const object”
需要说明的是,声明变量时,const int nc = 0
i nt const nc = 0 意义是一样的,个人推荐使用后面一种 i nt const nc = 0 ,这样别人在看代码的时候,可以先很快的知道 nc 是常量。
大家看完我上面所说的,可能更好的理解下面我所说的 int const *pint *const p 的区别。
前面我也说了,const 是修饰它位置右侧的,所以 int const *p 主要是修饰 *p 为常量,也就是说 *p 的值不能改变;而 int *const p 则是修饰 p 为常量,也就是说指针 p 为一个常量指针。可以根据下面的代码来加深印象

int main(int argc, char* argv[])

{

  int n = 0;

  int m = 1;

  int const *p1 = &n;

  int * const p2 = &n;

  p1 = &m;

  (*p1) = m;  //这里编译出错,错误为 error C2166: l-value specifies const object

 

  p2 = &m;    //这里编译出错,错误为 error C2166: l-value specifies const object

  (*p2) = m;

  
  return 0;

}


执现在大家该明白了 int const *pint *const p 两者之间的区别了吧。
好了,我们又回到上面的代码。去除了两行编译错误的行后,可以正确的编译并运行。调试信息如下所示:

int main(int argc, char* argv[])

{

  //说明: 下面的注释(以 //D 开头)都是对上面语句执行后的注释

  int n = 0;

  int m = 1;

  //D &m = 0x0012ff78

  //D &n = 0x0012ff7c

  int const *p1 = &n;

  //D p1 = 0x0012ff7c, (*p1) = 0

  int * const p2 = &n;

  //D p2 = 0x0012ff7c, (*p2) = 0

  p1 = &m;

  //D p1 = 0x0012ff78[改变], (*p1) = 1[改变]

  (*p2) = m;

  //D p2 = 0x0012ff7c[未改变], (*p2) = 1[改变]

  //D 注意,这时候, n 的值改变了, n = 1[改变]

  //D p1 *p1 都未改变

  return 0;

}


2、用来修饰函数
const 用来修饰函数,有两种情况

int const foo1()

{

  return 0;

}

 与

int CXXX::foo2() const

{

  return 1;

}


不过,上面的那种情况,一般是使用在函数的返回值为一个指针的情况下,告诉编译器(或者说是编码人员),请不要修改我这个函数的返回值,否则有可能出错;下面的那种情况,只能是用在一个类成员函数中,不能用在普通的函数中,作用是告诉编译器,我这个函数体中,不会修改任何同类(都是类 CXXXX)的任何变量。下面我来列出代码说说情况。我写了下面的代码:

class CXXX{

public:

  //构造函数与析构函数

  CXXX();

  ~CXXX();

  //外部调用的函数

public:

  int foo();

  int const foo1();

  int fooc() const;

  int const *foop();

protected:

private:

  //成员变量

public:

  int m_public;

protected:

  int m_protected;

private:

  int m_private;

};

CXXX::CXXX()

{

  m_public = 0;

  m_protected = 1;

  m_private = 2;

}

CXXX::~CXXX()

{

}

 

int CXXX::foo()

{

  m_public    += 100; // 编译不会产生任何的错误

  m_protected += 100; // 编译不会产生任何的错误

  m_protected += 100; // 编译不会产生任何的错误

 

  return 0;

}

int const CXXX::foo1()

{

  m_public    += 100; // 编译不会产生任何的错误

  m_protected += 100; // 编译不会产生任何的错误

  m_protected += 100; // 编译不会产生任何的错误

 

  return 1;

}

int CXXX::fooc() const

{

  m_public    += 100; // error C2166: l-value specifies const object

  m_protected += 100; // error C2166: l-value specifies const object

  m_protected += 100; // error C2166: l-value specifies const object

 

  return 2;

}

int const *CXXX::foop()

{

  return &m_protected;

}

int main(int argc, char* argv[])

{

  CXXX myclass;

  int n = myclass.foo();

  n = myclass.foo1();         // 正确。请注意这一行,调用的函数 int const CXXX::foo1()
  n = 1000;   // 正确

  int const nc = myclass.foo1();

  int *p = myclass.foop();    // error C2440: 'initializing' : cannot convert from 'const int *' to 'int *'

  const *pc = myclass.foop(); // 正确

  return 0;

}

具体的,我在上面的代码中已经注释出来了,详细的我就不再说明。

------------------------------------------------------------------------------------------

还是那句话,如果写错了,欢迎指正,但是骂人的就不欢迎了。

评论列表
BonderWu
re: 关于 const 修饰符的一些说明
int const *p1 = &n;这里p1是一个指向int 类型的被定义成const的对象的指针。此中微妙在于p1本身不是常量,我们可以重新赋值p1,使其指向不同的对象,但是我们不能修改p1指向的对象。比如说这里我们就不能修改n的值;  int * const p2 = &n;这里p2是一个非const对象的const指针,是一个指向int类型对象的const指针,这意味着我们不能赋给p2其他的地址值,但可以修改p2指向的值,这里我们可以修改n的值。
xawi2000
re: 关于 const 修饰符的一些说明
To BonderWu :
我觉得你说得有一点问题,
int const *p1=&n;
可以修改p1和n的值,但不能修改*p1的值,
注意这个地方n的值是可以变的...
xawi2000
re: 关于 const 修饰符的一些说明
TO 作者:
其实对于const我也只是知道一点,你写得很好.
不过里面有一点笔误.

_____________________________________
  //D p1 = 0x0012ff78[改变], (*p1) = 1[改变]

  (*p2) = m;

  //D p2 = 0x0012ff7c[未改变], (*p2) = 1[改变]

  //D 注意,这时候, n 的值改变了, n = 1[改变]

  //D p1 与 *p1 都未改变
______________________________________
这里应该是p2和*p1未改变,你前面已经说p1变了,
后面又说p1没变,感觉这里有点矛盾.我想这里应该是笔误.

--------------------------------------------------------
const *pc = myclass.foop(); // 正确
---------------------------------------------------------
似乎掉了一个int.应该是int const *pc=myclass.foop()

sacred
re: 关于 const 修饰符的一些说明
楼上的大哥对上面作者的意思有误会…
ss
re: 关于 const 修饰符的一些说明
作者写得很好,顶
hengai
to xawi2000
我想你是理解错我的意思了。我在开头就已经说明了注释是对上面那句代码得到注视
(*p2) = m;

//D p2 = 0x0012ff7c[未改变], (*p2) = 1[改变]

//D 注意,这时候, n 的值改变了, n = 1[改变]

//D p1 与 *p1 都未改变

注释是对 (*p2)=m 代码的注释

对于那个const *pc = ... 那倒可能是我漏写了(时间很久了,不记得了),不过如果没写的话,C编译器默认的就是 int 类型。
gmg
re: 关于 const 修饰符的一些说明
同意BonderWu : 因为P是指针常量,而不是常量指针,起指向的N 是不能修改的!!
mercedes
re: 关于 const 修饰符的一些说明
int n = 9;
int m =7;
int const *p;

p = &n;   /*   初始化   */
p = &m; //正确
*p = n;    //错误
*p = m;   //错误
*p = 7;    //错误
*p = 6;    //错误
n = 5;      //正确

发表评论
切换编辑模式