当前位置:文档之家› const指针理解

const指针理解

const指针理解
主要有3种用法:

const指针3种用法

格式
限定对象
备注

const int *p = &a;(或写作int const *p = &a;)
*p值不能改变
a的值可以改变

int *const p = &a;
p值不能改变
a的值可以改变

const int *const p = &a;
*p值和p值都不能改变
a的值可以改变


语法并非看起来那么变化多端。一般来说,你可以在头脑里画一条垂直线穿过指针声明中的星号(*)位置,如果const出现在线的左边,指针指向的数据为常量;如果const出现在线的右边,指针本身为常量;如果const在线的两边都出现,二者都是常量。

如:

char *p = "hello";
非const指针, 非const数据

const char *p = "hello";
非const指针, const数据

char * const p = "hello";
const指针, 非const数据

const char * const p = "hello";
const指针,const数据



关于const char*, char const*, char*const(2008-09-14 00:15:25)标签:求职 找工作 c 校园 笔试 分类:职场必备
const char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。

由于这三种声明方式非常相似,所以很容易记混。

Bjarne在他的The C++ Programming Language里面给出过一个助记的方法:
把一个声明从右向左读。

char * const cp; ( * 读成 pointer to )
那么我们可以读成:cp is a const pointer to char

const char * p;
可以读成:p is a pointer to const char;

char const * p;
同上因为C++里面没有const*的运算符,所以const只能属于前面的类型。

这样是不是就不会记混了


前两天在网上看到华为的一些笔试题,对基础的掌握仍然是这种大公司所重视的。其间对指针掌握的要求比较多,有一道是关于const指针的。看到那道题,回来整理了一些有关const指针的内容,分享一下。

const说明指针变量,组合的情况可能会显得很复杂。使用指针时要涉及两个目标,即指针本身和指针所指的对象。关于const指针变量,可归结为以下三种:
1.指向常量的指针变量;
2.常指针变量;
3.指向常量的常指针变量。
下面来分别谈谈这三种情况。

一、指向常量的指针变量:
声明格式: const type * var_name;
或 type const * var_name;
特点: 可改值。
将指针声明冠以const,使指向的对象为常量,而不是指针为常量。注意:指向常量的指针不一定指向真正的常量,它也可以指向常量,只是从该指针的角度来看,它所指向的对象是常量,通过该指针不能修改它指向的对象。它还可以指向其它的对象,可以不初始化。
-----eg:
int a = 0,b = 1;
const int c = 3;
const int* pi; //等同于 (const int*) pi;
pi = &a;
*pi = 10; //错误:不能修改它指向的对象。
a = 10;
pi = &b;
*pi

= &b;
*pi = 20; //错误:不能修改它指向的对象。
b = 20;
pi = &c;
*pi = &c;
*pi = 30; //错误:不能修改它指向的对象。
-----eg2:
const char* pc = "asdf";
pc[3] = 'a'; //错误:不能修改它指向的对象。
pc = "ghik";
-----eg3:
const char* step[3] =
{"left","right","hop"};
step[2] = "skip";
step[2][1] = 'i'; //错误:不能修改它指向的对象。

二、常指针常量:
声明格式: type* const var_name;
特点: 可改对象。
要把指针本身,而不是它指向的对象声明为常量,采用运算符 *const,必须初始化,通过该指针可以修改它指向的对象,但它不可以指向其他的对象。
-----eg:
int a = 0,b = 1;
int* const pi = &a; //等于 int* (const pi) = &a;
*pi = 10;
pi = &b; //错误:pi本身为常量,不能指向其他对象。

三、指向常量的常指针变量:
声明格式: const type * const var_name;
特点: 值与对象均不能改。
要使两个目标都是常量,两者都要声明为 const 。
eg:
int a = 0,b = 1;
const int c = 3;
const int* const pi = &a; //相当于: (const int*)(const pi) = &a;
*pi = 10; //错误:不能修改它的对象。
a = 10;
pi = &b; //错误:不能指向其它对象。
eg2:
const char* const pc = "asdf";
pc[3] = 'a'; //错误:不能修改它的对象。
pc = "ghik"; //错误:不能指向其它对象。
eg3:
const char* const step[3] =
{"left","right","hop"};
step[2] = "skip"; //错误:不能指向其它对象。
step[2][1] = 'i'; //错误:不能修改它的对象。

一般的,当声明中出现 const 描述符时,它修饰的是紧跟其后的声明元素或者在 const 成员函数声明中函数的 this 指针。
注意:可以将变量的地址赋给指向常量的指针变量,不会因此有什么害处,但是,常量的地址不能赋给无约束的指针。
eg:
int a = 1;
const int c = 2;
const int* p1 = &c;
const int* p2 = &a;
int* p3 = &c; //非法!
int* const p4 = &c; //非法! 指针常量 p4 能够改值。
const int* const p5 = &c;


在c/c++中,指针本身就是一个难点,再加与const的结合,常会产生许多让人费解的地方,在这里做个小结。

1.定义const对象
const int buffsize=512;
因为常量定义后就不能修改,所以定义时必须初始化.
const i,j=0; //error,i没有初始化

2.const对象默认为文件的局部变量
//https://www.doczj.com/doc/631251481.html,
extern const int bufsize=512; //定义并初始化

//https://www.doczj.com/doc/631251481.html,
extern const int bufsize; //声明
for(int index=0;index!=bufsize;++index)
{
//...
}

非const变量默认为extern,要使const变量能够在其它的文件中访问,必有显示指定为extern.


3.指向const对象的指针

const int *p;
这个p是一个指向int类型const对象的指针,const限定了指针p所指向的类型,而并非p本身。也就是说p

本身并不是const。在定义时不需要对它进

行初始化,还可以给p重新赋值,使其指向另一个const对象。

但不能通过p修改所指向对象的值。
示例1:int a=0; p=&a; 可以。
示例2:*p=20; 不可以。
结论:这种指向const对象的指针只是限制不能修改p指向对象的数值,而不是限制p指向什么对象。

把一个const对象的地址赋给一个不是指向const对象的指针也是不行的。
示例3:const int b=10;
int *p2=&b; //error
const int *p3=&b; //ok
结论:因为变量b有const修饰,不能被修改。但指针p2是一个普通的指针,可以修改指向对象的值,两种
声明矛盾,所以不合法。而指向const对象的指针不允许修改指针指向对象的数值,所以这种方式合法。

不能使用void*指针保存const对象的地址,而必须使用const void*类型保存const对象的地址。

const int a=6;

void *p=&a;//error

const *cp=&a;//ok

int const *p;
c++规定,const关键字放在类型或变量名之前是等价的.

const int n=5; //same as below
int const m=10;

const int *p; //same as below const (int) * p
int const *q; // (int) const *p

4.const指针

int c=20;
int *const p4=&c;

指针p4称为const指针。它和指向const对象的指针恰好相反,它不能够修改所指向对象,但却能够修改指

向对象的数值。另外,这种指针在声明时必须初始化。

5.指向const对象的const指针

const int d=30;
const int *const dp=&d;

指针dp既不能修改指向的对象,也不能修改只想对象的值。




第五节 const 指针

对于下面涉及指针定义和操作的语句:
int a=1;
int *pi;
pi=&a;
*pi=58;
可以看到,一个指针涉及到两个变量,指针本身pi和指向的变量a。修改这两个变量的对应操作为“pi=&a;”和“*pi=58;”。

1.指向常量的指针(常量指针)

在指针定义语句的类型前加const,表示指向的对象是常量。例如:
const int a=78;
const int b=28;
int c=18;
const int*pi=&a; //指针类型前力口const
*pi=58; //error:不能修改指针指向的常量
pi=&b; //ok:指针值可以修改
*pi=68; //error:同上
pi=&c;
*pi=88; //error:同上
c=98; //ok
a是常量,将a的地址赋给指向常量的指针pi, 使a的常量性有了保证。如果企图修改a,则会引起“不能修改常量对象”(Cannot modify a const object)的编译错误。
可以将另一个常量地址赋给指针“pi=&b;” (指针值可以修改),这时,仍不能进行“*p =68;”的赋值操作,从而保护了被指向的常量不被修改。 见图8-4,图中阴影部分表示不能


图8-4 指向常量的指针


被修改。可以将一个变量地址赋给指针“pi=&c;”, 这时,由于不能进行“*pi=88;”的赋值操作,从而保护了被指向的变量在指针操作中不被修改。定义指向常量的指针只限制指针的间接访问操作,而不能规定指针指向的值本身的操作规定性。例如,变量c可以修改,这在 函数传递中经常被使用。
例如,下面的程序将两个一样大小的数组传递给一个函数,让其完成复制字符串的工作,为了防止作为源数据的数组遭到破坏,声明该形参为常量字符串:
//**********************
//** ch8_10.cpp **
//**********************

#include

void mystrcpy(char* dest, const char* source)
{
while(*dest++ = *source++);
}

void main()
{
char a[20]="How are you!";
char b[20];
mystrcpy(b,a);
cout < }

运行结果为:
How are you!
变量字符串a传递给函数mystrcpy()中的source, 使之成为常量,不允许进行任何修改、但在主函数中, a却是一个普通数组,没有任何约束,可以被修改。
由于数组a不能直接赋值给b, 所以通过一个函数实现将数组a的内容复制给数组b。
函数mystrcpy()中的语句是一个空循环,条件表达式是一个赋值语句。随着一个赋值动作,便将一个a数组中的字符赋给了b数组中对应的元素,同时两个数组参数都进行增量操作以指向下一个元素。只要所赋的字符值不是'\0',(条件表达式取假值),则循环就一直进行下去。 ,
常量指针定义"const int *pi=&a;”告诉编译,*pi是常量,不能将,pi作为左值进行操作。

2.指针常量

在指针定义语句的指针名前加const,表示指针本身是常量。例如:
char *constpc="asdf"; //指针名前加const定义指针常量
pc="dfgh"; //error:指针常量不能改变其指针值
*pc='b'; //ok:pc内容为,'bsdf',
*(pc+1)='c'; //ok:pc内容为'bcdf',
*pc++='y'; //error:指针常量不能改变其指针值
const int b=28;
int* const pi=&b; //error:不能将const int*转换成int*
pc是指针常量,在定义指针常量时必须初始化,就像常量初始化一样。这里初始化的 值是字符串常量的地址,见图8_5



图8_5 指向变量的指针常量图

由于pc是指针常量,所以不能修改该指针值。“pc="dfgh";”将引起一个“不能修改常量对象”(Cannot modify a const object)的编译错误。
pc所指向的地址中存放的值并不受指针常量的约束,即*pc不是常量,所以“*pc

='b';”和“*(pc+1)='c';”的赋值操作是允许的。但“*pc++=y;”是不允许的,因为该语句修改*pc的同时也修改了指针值。
由于此处*pi是不受约束的,所以,将一个常量的地址赋给该指针“int* const pi=&b;”是非法的,它将导致一个不能将const int *转换成int *的编译错误,因为那样将使修改常量(如:“* pi=38;”)合法化。
指针常量定义"int *const pc=&b;”告诉编译,pc是常量,不能作为左值进行操作,但是允许修改间接访问值,即*pc可以修改。

3.指向常量的指针常量(常量指针常量)

可以定义一个指向常量的指针常量,它必须在定义时进行初始化。例如:
const int c=7;
int ai;
const in * const cpc=&ci; //指向常量的指针常量
const int * const cpi=&ai; //ok
cpi=&ci; //error:指针值不能修改
*cpi=39; //error:不能修改所指向的对象
ai=39; //ok
cpc和cpi都是指向常量的指针常量,它们既不允许修改指针值,也不允许修改*cpc的值,见图8-6。



图8—6 指向常量的指针常量

如果初始化的值是变量地址(如&ai), 那么不能通过该指针来修改该变量的值。也即“*cpi=39;”是错误的,将引起“不能修改常量对象”(Cannot modify a const object)的编译错误。但“ai=39;”是合法的。
常量指针常量定义“coastint * coastcpc=&b;”告诉编译,cpc和* cpc都是常量,它们都不能作为左值进行操作。


1.指向const对象的指针

const int *p;
这个p是一个指向int类型const对象的指针,const限定了指针p所指向的类型,而并非p本身。也就是说p本身并不是const。在定义时不需要对它进行初始化,还可以给p重新赋值,使其指向另一个const对象。但不能通过p修改所指向对象的值。
示例1:int a=0; p=&a; 可以。
示例2:*p=20; 不可以。
结论:这种指向const对象的指针只是限制不能修改p指向对象的数值,而不是限制p指向什么对象。

把一个const对象的地址赋给一个不是指向const对象的指针也是不行的。
示例3:const int b=10;
int *p2=&b; //error
const int *p3=&b; //ok
结论:因为变量b有const修饰,不能被修改。但指针p2是一个普通的指针,可以修改指向对象的值,两种声明矛盾,所以不合法。而指向const对象的指针不允许修改指针指向对象的数值,所以这种方式合法。

2.const指针

int c=20;
int *const p4=&c;

指针p4称为const指针。它和指向const对象的指针恰好相反,它不能够修改所指向对象,但却能够修改指向对象的数值。另外,这种指针在声明时必须初始化。

3.指向const对象的const指针

const int d=30;
const int *co

nst dp=&d;

指针dp既不能修改指向的对象,也不能修改只想对象的值。




我总结的C++问题集2009-05-26 14:40https://www.doczj.com/doc/631251481.html,/sanguomi/archive/2009/01/22/1379813.html

1:C和C++有什么区别:
C++支持面向对象的编程,同时兼容C语言的面向过程编程

2:VB和C++有什么区别:
VB是一门基于对象语言,有对象和类的概念,但是对于继承、多态实现的不好

3:VC和C++有什么区别:
VC可以看成是C++加上MFC基础类库的组合

4:声明一个引用是需要注意什么,函数返回引用时需要注意什么:
1 必须在定义引用的时候就声明引用对象
2 不能更该引用对象
3 不能引用数字,常量,表达式
函数引用返回不能引用局部变量

5:引用和指针有什么区别:
指针:可以随意指向不同的地址(水性杨花)
引用:声明后不能引用其它变量(从一而终)

6:常量引用和常量指针的区别:
不能改变常量引用的值
可以改变常量指针的值,但是不能改变常量指针的指向

7:缺省参数和函数重载的区别和应用:
缺省参数可以看作是函数重载的特例,Java中取消了缺省参数。
应用:缺省参数可以涵盖普通应用和特殊应用,但如果要更灵活的处理,需要函数重载

8:void add(int a, int b)和int add(int a, int b, int c=0)是否是正确的函数重载:
不是,有可能存在二义性

9:void add(int a, int b)和int add(const int &a, const int &b)是否是正确的函数重载:
不是,整型的引用也是整型

10:内联函数有什么用,是否在函数名前加上inline关键字就成为内联函数了?:
用途:节省调用函数的开销,加快运行速度
不一定,编译器会自动优化

11:何时会用到::操作符:
类外实现方法,引用类的静态成员等

12:static成员和普通成员的区别:
1 静态成员可以不经实例化直接引用
2 静态属性可以有初始值
3 静态方法中只能访问静态成员
4 静态成员一般描述对象的共同特征"

13:举一个应用static的例子:
连锁店是一个类,店名属性应该是静态(班级班费)

14:构造函数和析构函数的作用:
构造函数用来初始化属性,为指针分配内存空间,析构函数用来释放分配的空间

15:new/delete操作符和malloc/free的区别:
1 new/delete是C++标准函数,效率高
2 new自动获得分配的size,使用方便
3 new/delete会引发构造/析构函数

16:写一个为int型指针分配100个空间,然后回收的例子:
int *p = new int[100];
delete [] p;

17:什么是浅复制,什么是深层复制:
当类中包含指针属性时,浅复制只复制地址,深层复制则复制内容

18:写一个类模拟cin和cout:
class MyCout {
public:
MyCout & operator <<(int a) {
printf(""%d"", a);
return *this;
}
}

19:描述C++的

异常处理:
就是try, catch模型"

20:同VB的异常处理相比,C++有何优势:
C++的异常处理区分了正常代码和异常处理代码,并且在抛出用户自定义异常方面更加完善

21:简述C++中的4种继承模型:
单一继承,多重继承,层级继承,多极继承

22:图中如果类A, C中存在同名方法abc,如何引用:
实例化D的对象d,可以用d.A::abc()或d.B::abc()引用A中的方法,d.C::abc()引用C中的方法

23:子类会继承父类中所有的内容吗?:
private的成员不会被继承

24:题22的图中,实例化D的对象后,构造函数和析构函数的顺序是什么?:
A()-->B()-->C()-->D()-->~D()-->~C()-->~B()-->~A()

25:如果父类中存在有参数的构造函数,一般来说也要为它提供没有参数的构造函数,为什么?:
因为子类在实例化的时候回收先调用父类中没有参数的构造函数(除非子类中声明调用父类中带参数的),这是因为父类中存在构造函数,编

译器不会为父类产生缺省的构造函数,就会发生错误

26:什么叫Override,和Overload有什么区别?:
Override:函数覆盖,发生在父类和子类中,子类覆盖函数和父类的源函数声明必须完全一致
Overload:函数重载,重载的一组函数必须具有各自不同的参数

27:父类和子类对象是否可以相互转换?:
是单向的,可以将子类对象赋给父类对象,也可以让父类指针指向子类,但是不能反过来

28:继承可以干什么?:
可以实现代码重用
代码重用的三个阶段:
1 复制 缺点:代码分散
2 模块化 缺点:不易维护,扩充
3 继承"

29:父类指针指向子类对象后是否能调用子类中的方法?:
不能,除非将父类中的方法声明成virtual
注意:不能通过父类指针调用子类中特有的方法

30:虚函数和纯虚函数的区别和应用:
区别:纯虚函数一般没有实现
应用:父类中有必要实现该方法,考虑到多态可以用虚函数,如果父类中没有必要实现该方法,但是期望在子类中实现,可以使用纯虚函数

31:类和抽象类的区别和应用:
区别:抽象类不能实例化对象,抽象类的子类一定要覆盖父类中的纯虚函数
应用:类一般用来描述现实中存在的对象,抽象类用来描述现实中不存在的概念。比如抽象类“形状”和类“圆”"

32:子类一定要覆盖(实现)父类中的纯虚函数吗?虚函数呢?:
子类如果不覆盖父类中的纯虚函数子类不能实例化对象,也变成了抽象类,虚函数子类可以不覆盖

33:虚析构函数有什么用途,举例?:
虚析构函数可以保证子类中的析构函数能被调用

34:写一个多态:比如CPU商品

35:写一个类工厂:




相关主题
文本预览
相关文档 最新文档