指向const对象的指针
指向const对象的指针就是一个指针,不能通过它来修改它所指向的对象的值。 声明方法:const int *p;
const对象在初始化后是不允许对其值进行修改的,因此,我们不能用一个普通指针指向一个const对象,即下面的赋值会引起编译错误:
const int i = 1;
int *p = &i;
否则的话,我们就可以利用普通指针来修改一个const对象的值,那么const也就毫无意义了。
正确的方法是利用一个指向const对象的指针来获取const对象的地址:
const int i = 1;
const int *p = &i;
char const *p == const char *p;
这样,利用指向const对象的指针也是不能修改它所指向的const对象的值的。
注意:
1.指向const对象的指针本身不是const类型(这也是它与const指针的主要不同点),所以它可以指向另一个const对象
2.指向const对象的指针可以被赋予一个非const对象的地址,但是此时试图通过此指针来修改对象的值的操作是非法的
const指针
const指针就是一个指针,它本身就是const类型,所以将它初始化后不能再改变它的指向,即不能让它指向一个新的对象。声明方法:
int *const p;//指向非const对象的const指针
const int *constp;//指向const对象的const指针
使用const指针不可以修改其地址值,但是const指针指向非const对象,就可以利用它修改它所指向的对象的值
技巧:
如果指针名前紧邻的关键字为const,那么它就是一个const指针;如果声明指针所指向的对象类型前有const关键字,那么它就是一个指向cosnt对象的指针。
补充:
Bjarne在他的The C++ Programming Language里面给出过一个助记的方法:把一个声明从右向左读(这可能和我们平常习惯有所不同,需要特别注意)。
char * const cp; ( * 读成 pointer to )
cp is a const pointer to char ,亦即指针常量,cp值不可改变,但*cp,也就是cp所指对象能够改变。
const char * p;
p is a pointer to const char,亦即指向常量的指针,所以p所指的对象不可改变。
补:
一、可能的组合: (1)const char*p (2)char const*p (3)char *const p (5)char const**p (6)char *const *p (7)char **const p 当然还有在(5)、(6)、(7)中再插入一个const的若干情况,不过分析了以上7中,其他的就可类推了! 二、理解助记法宝: 1。关键看const 修饰谁。 2。由于没有const *的运算,若出现const*的形式,则const实际上是修饰前面的。 比如:char const*p,由于没有const*运算,则const实际上是修饰前面的char,因此char const*p等价于const char*p。也就是说上面7种情况中,(1)和(2)等价。 同理,(4)和(5)等价。在(6)中,由于没有const*运算,const实际上修饰的是前面的char*,但不能在定义时转换写成 const(char *)*p,因为在定义是"()"是表示函数。 三、深入理解7种组合 (0)程序 在执行时为其开辟的空间皆在内存(RAM)中,而RAM里的内存单元是可读可写 的;指针只是用来指定或定位要操作的数据的工具,只是用来读写RAM里内存单元的工作指针 。若对指针不加任何限定,程序中一个指针可以指向RAM中的任意位置(除了系统敏感区,如操作系统内核所在区域)并对其指向的内存单元进行读和写操作(由RAM的可读可写属性决定);RAM里内存单元的可读可写属性不会因为对工作指针的限定而变化(见下面的第4点),而所有对指针的各种const限定说白了只是对该指针 的 读写权限 (包括读写位置)进行了限定 。 (1)char *p:p是一个工作指针,可以用来对任意位置 (非系统敏感区域)进 行读操作和写操作 ,一次读写一个字节(char占一个字节)。 { 待验证 : 还有一个4字节的指针变量s 。不过s是“有所限制”的,属于char *const类型,也就是前面说的 (3)这种情况,s一直指向s[0], 即(*s==s[0]=='h'),可以通过*s='k'来改变s所指向的 s[0]的值,但不能执行(char *h=“aaa”;s=h;)来对s另外赋值。 } (4)上面的(2)和(3)只是对p进行限定,没有也不能对p所指向的空间进行限定,对于"char s[]="hello";const char*p=s;" 虽然不能通过*(p+i)='x'或者p[i]='x'来修改数组元素s[0]~s[4]的值,但可以通过*(s+i)='x'或者s[i]='x'来修改原数组元素的值--RAM里内存单元的可读可写属性不因对工作指针的限定而改变,而只会因对其本身的限定而改变。如const char c=‘A’,c是RAM里一个内存单元(8字节)的名字,该内存单元的内容只可读,不可写。 (5)const char **p或者char const**p :涉及两个指针p和 *p。由于const修饰char ,对指针p没有任何限定,对指针*p进行了上面情况(2)的限定。 (6)char *const *p:涉及两个指针p和 *p。由于const修饰前面的char*,也就是对p所指向的内容*p进行了限定(也属于前面的情况(2))。而对*p来说,由于不能通过"*p=..."来进行另外赋值,因此属于前面的情况(3)的限定。 (7)char **const p : 涉及两个指针p和 *p,const修饰p,对p进行上面情况(3)的限定,而对*p,没有任何限定。 四、关于char **p 、const char **p的类型相容性问题 1。问题 char *p1;const *p2=p1;//合法 char **p1;const char**p2=p1;//不合法,会有警告warning: initialization from incompatible pointer type char **p1;char const**p2=p1;//不合法,会有警告warning: initialization from incompatible pointer type char**p1;char*const*p2=p1;//合法 2。判断规则 明确const修饰的对象!对于指针p1,和p2,若要使得p2=p1成立,则可读做 : “p1是指向X类型的指针,p2是指向“带有const限定”的X类型的指针 “。 char *p1;const *p2=p1;//合法:p1是指向(char)类型的指针,p2是指向“带有const限定"的(char)类型的指针。 char **p1;const char**p2=p1;//不合法:p1是指向(char*)类型的指针,p2是指向 ((const char)*)类型的指针。 char **p1;char const**p2=p1;//不合法;与上等价。 char**p1;char*const*p2=p1;//合法: p1是指向(char *)类型的指针,p2是指向“带有const限定"的(char*)类型的指针。 五、其他 1。 含有const的单层或双层指针的统一读法: “p是一个指针,是一个[“带有const限定”的]指向[”带有const限定”的]X类型的指针”。 2。定义时const修饰的对象是确定的,但不能在定义时加括号,不然就和定义时用“()”表示的函数类型相混淆了!因此定义时不能写(char *)const *p或者(const char) **p。 六、问题探讨(由于博文后的留言有字符数目限制,将回复移到这里) 问题1 (见博文后留言):讲解非常好,不过有个问题想探讨下: 例如: const char wang[]={"wang"}; char *p; p=wang; 是错误的。 所以char *p中的P不能指向常变量。 (1)需要补充纠正。 回复 : 你好!谢谢指正!我在ubuntu 10.04(gcc 4.4.3)下做了如下测试: gcc -o test_const test_const.c ./test_const 问题2 回答 http://www.linuxsir.org/bbs/showthread.php?t=239058 提到的问题 在c语言里 // test.c 回复: (1)首先,以上代码编译时会出错warning: initialization discards qualifiers from pointer target type, 因为char *s2 = s1和问题1提到的一样,不符合相容规则。 (2)输出结果是正确的,代码分析如下: int main() { (4)额外收获:执行gcc -o test test.c后,“test”、“It's modified!”、"%s\n"都被作为字符串常量存储在二进制文件test的只读区 域 (.rodata)。事实上,一个程序从编译到运行,对变量空间分配的情况如下: A。赋值了的全局变量或static变量=>放在可执行文件的.data段。 B。未赋值的全局变量或static变量=>放在可执行文件的.bss段。 C。代码中出现的字符串常量或加了const的A=>放在可执行文件的.rodata段。 D。一般的局部变量=>在可执行文件中不占空间,在该二进制文件作为进程在内存中运行时才为它分配栈空间。 E。代码中malloc或new出的变量=>在可执行文件中不占空间,在该二进制文件作为进程在内存中运行时才为它分配堆空间。 问题3:(待进一步分析) 验证博文中 三(3)提到的是否为s分配空间,初步分析结果为:不分配!文中的s只是s[0]的地址的代号而已。 #include<stdio.h> 输出结果: the address of a is 3213037836 由结果可以看出,编译器做了些优化。 七、其他相关经典文章转载 王海宁,华清远见嵌入式学院讲师,对const关键字的理解 http://www.embedu.org/Column/Column311.htm 目前在进行C语言补习时,发现很多的同学对于const这个关键字的理解存在很大的误解。现在总结下对这个关键字理解上的误区,希望在以后的编程中,能够灵活使用const这个关键字。 1、 const修饰的变量是常量还是变量 对于这个问题,很多同学认为const修饰的变量是不能改变,结果就误认为该变量变成了常量。那么对于const修饰的变量该如何理解那? 下面我们来看一个例子: int main a = 10; 这个比较容易理解,编译器直接报错,原因在于“a = 10;”这句话,对const修饰的变量,后面进行赋值操作。这好像说明了const修饰的变量是不能被修改的,那究竟是不是那,那么下面我们把这个例子修改下: int main buf[4] = 97; 其中最后一句printf的目的是看下变量a的值是否改变,根据const的理解,如果const修饰的是变量是不能被修改的话,那么a的值一定不会改变,肯定还是0。但是在实际运行的结果中,我们发现a的值已经变为97了。这说明const修饰的变量a,已经被我们程序修改了。 那综合这两个例子,我们来分析下,对于第二例子,修改的原因是buf[4]的赋值操作,我们知道buf[4]这个变量已经造成了buf这个数组变量的越界访问。buf数组的成员本身只有0,1,2,3,那么buf[4]访问的是谁那,根据局部变量的地址分配,可以知道buf[4]的地址和int a的地址是一样,那么buf[4]实际上就是访问了const int a;那么对buf[4]的修改,自然也修改了const int a的空间,这也是为什么我们在最后打印a的值的时候看到了97这个结果。 那么我们现在可以知道了,const修饰的变量是不具备不允许修改的特性的,那么对于第一个例子的现象我们又如何解释那。 第一个例子,错误是在程序编译的时候给出的,注意这里,这个时候并没有生成可执行文件,说明const修饰的变量可否修改是由编译器来帮我们保护了。而第二个例子里,变量的修改是在可执行程序执行的时候修改的,说明a还是一个变量。 综上所述,我们可以得出一个结论,那就是const修饰的变量,其实质是告诉程序员或编译器该变量为只读,如果程序员在程序中显示的修改一个只读变量,编译器会毫不留情的给出一个error。而对于由于像数组溢出,隐式修改等程序不规范书写造成的运行过程中的修改,编译器是无能为力的,也说明const修饰的变量仍然是具备变量属性的。 2、 被const修饰的变量,会被操作系统保护,防止修改 如果对于第一个问题,有了理解的话,那么这个问题,就非常容易知道答案了。Const修饰的变量是不会被操作系统保护的。 其原因是操作系统只保护常量,而不会保护变量的读写。那么什么是常量?比如“hello world”这个字符串就是被称为字符串常量。 对于这个问题的另一种证明方法,可以看下面这个程序: int main printf(“the &a is %p, the buf is %p\n”,&a, buf); 可以发现buf保存的地址是在0x08048000这个地址附近的,而a的地址是在0xbf000000这个地址附近的,而0x08048000附近的地址在我们linux操作系统上是代码段。这也说明了常量和变量是存放在不同区域的,自然操作系统是会保护常量的。 如果我们知道这个道理后,再看下面的题目: int main buf[0] = ‘a’; 我们可以思考下,这个程序的运行结果会是什么呢?
(4)const char **p
(2)const char*p或者char const *p(因为没有const*p运算,因此const修饰的还是前面的char):可以对任意位置(非系统敏感区域)进行“只读” 操作。(“只读”是相对于char *p来说所限定的内容)
(3)char *const p(const 修饰的是p):只能对“某个固定的位置” 进 行读写操作,并且在定义p时就必须初始化(因为在后面不能执行“p=..”的操作,因此就不能在后面初始化,因此只能在定义时初始化)。(“某个固定的位 置”是相对于char *p来说所限定的内容)
可以总结以上3点为:char *p中的指针p通常是”万能”的工作指针 ,而(2)和(3)只是在(1)的基础上加了些特定的限制 ,这些限制在程序中并不是必须的,只是为了防止程序员的粗心大意而产生事与愿违的错 误。
另外,要明白“每块内存空间都可有名字;每块内存空间内容皆可变(除非有所限) ” 。比如函数里定义的char s[]="hello";事实上在进程的栈内存里开辟了6个变量共6个字节的空间,其中6个字符变量的名字分别为:s1[0]、s1[1]、 s1[2]、s1[3]、s1[4]、s1[5](内容是'\0')
//test_const.c
#include<stdio.h>
int main()
{
const char wang[]={"wang"};
char *p;
p=wang;
p[2]='c';
printf("p is %s\n",p);
return 0;
}
编译 :
输出如下 :
test_const.c: In function ‘main’:
test_const.c:17: warning: assignment discards qualifiers from pointer target type
执行:
p is wacg
结论: 根据本博文中第四点--相容性问题,将const型的wang赋值给p是不合法的。但编译器对其的处理只是警告,因此执行时通过p修改了只读区域的数据。这应该是该编译器处理不严所致后果,不知你用的什么编译器?
int main() {
const char* s1 = "test";
char *s2 = s1;
s2 = "It's modified!";
printf("%s\n",s1);
}
out: It's modified!;
这样也可以吗? 照我的理解岂不是const限定符在c语言里只是摆设一个?
const char* s1 = "test"; // 在只读数据区(objdump -h test后的.rodata区)开辟5字节存储"test",并用s1指向首字符‘t’。
char *s2 = s1; // s2也指向只读数据区中“test”的首字符't'。
s2 = "It's modified!"; // 在只读数据区开辟15字节存储"It's modified!",并将s2由指向't'转而指向"It's modified!"的首字符'I'。
printf("%s\n",s1); // 从s1所指的‘t’开始输出字符串"test"。
}
(3)总结:提问者的误区在于,误以为s2 = "It's modified!"是对“test”所在区域的重新赋值,其实这里只是将“万能”工作指针s2指向另外一个新开辟的区域而已。比如若在char *s2 = s1后再执行s2[2]='a'则是对“test”的区域进行了写操作,执行时会出现段错误。但这个段错误其实与const没有关系,因为“test”这块区域本身就是只读的。为了防止理解出错,凡事对于对指针的赋值(比如 s2 = "It's modified!" ),则将其读做:将s2指向“ It's modified! ”所在区域的首字符。
int main() {
int a=3;
char s1[] = "test";
int b=4;
char s2[] ="test2";
printf("the address of a is %u\n",&a);
printf("s1 is %u\n",s1);
printf("the address of s1 is %u\n",&s1);
printf("the address of b is %u\n",&b);
printf("s2 is %u\n",s2);
printf("the address of s2 is %u\n",&s2);
}
s1 is 3213037827
the address of s1 is 3213037827
the address of b is 3213037832
s2 is 3213037821
the address of s2 is 3213037821
{
char buf[4];
const int a = 0;
}
{
char buf[4];
const int a = 0;
printf(“the a is %d\n”,a);
}
{
const int a;
char *buf = “hello world”;
}
{
char *buf = “hello”;
printf(“the buf is %s\n”,buf);
}
发表评论
-
set容器的反向迭代器
2013-05-02 16:56 3742#include <iostream> #in ... -
对于CRITICAL_SECTION用法的介绍和理解[转]
2013-04-08 11:50 2181很多人对CRITICAL_SECTION ... -
二维数组知识
2012-09-15 17:20 816二维数组和指针⑴ 用 ... -
Realloc的使用
2012-08-14 11:04 829realloc 用过很多次了。 ... -
extern C的由来
2012-08-09 10:14 695时常在cpp的代码之中看到这样的代码: #ifdef ... -
C++类对象的创建过程
2012-07-26 16:02 938分配空间(Allocation) ... -
静态数据成员和静态成员函数
2012-07-26 15:04 3110静态类成员包括静态数据成员和静态函数成员两部分。 与 ... -
复制构造函数(拷贝构造函数)以及深浅拷贝
2012-07-25 22:39 1428对于普通对象而言复制是很简单的,一般是将变量或者常量赋值给某 ... -
cin、cin.get、cin.getline()、getline()、gets()的用法【转】
2012-07-24 20:05 831学C++的时候,这几个输入函数弄的有点迷糊;这里做个小结,为了 ... -
编程笔记(07-24)
2012-07-24 15:15 6671 #include < stdio.h ... -
堆、栈解疑
2012-07-12 21:53 584一、预备知识—程序的内存分配 一个由C/C++编译的程序 ... -
指针和内存分配的深度理解
2012-07-12 18:57 1031一 :关于指针和堆的内存分配 先来介绍一下指针: 指针一种 ... -
数组指针和指针数组
2012-07-12 18:56 1187先看一下基本的形式,我们从这里起步! ----------- ... -
typedef的学习
2012-07-11 15:03 738typedef,顾名思义,为“类型定义”,可以解释为:将一种数 ... -
函数指针和指针函数
2012-07-11 11:21 594【函数指针】 ... -
Define学习
2012-07-11 10:12 1073宏替换是C/C++系列语言的技术特色,C/C++语言提 ... -
sizeof 深研
2012-07-11 09:39 6671、什么是sizeof 首先看一下sizeof ... -
内存对齐问题
2012-07-10 22:35 10961.内存数据对齐的原因: 无论如何,为了提高程序的性 ... -
指针深究
2012-07-09 21:55 594在说指向指针的指针之前,不得不说指向变量的指针。先看如下示例: ... -
C语言文件使用方式详解
2012-07-04 10:23 768文件的打开(fopen函数) f ...
相关推荐
C++ 编程语言中,const 指针和指向const的指针是两个容易混淆的概念,但它们有着不同的定义和使用场景。在本文中,我们将详细分析 C++ const 指针和指向const的指针,帮助读者更好地理解和学习这两个概念。 const ...
C语言中的const指针变量是一种特殊的指针,它用于确保指针所指向的值不会被修改。但是,const指针变量的概念经常被混淆,理解其工作原理对于学习C语言非常重要。 首先,我们可以根据const关键字的位置区分两种常...
3. **指向常量的常指针(Const Pointer to Const)**: - 定义格式:`const int *const a = &b;` - 这种类型的指针表示指针本身及其指向的内容都是常量,即既不能改变指针的指向,也不能通过该指针修改其指向的...
这种情况是`const`同时修饰指针和指针所指的变量,两者都不能改变。例如: ```c const int* const pi = &a; // pi和*a都是常量 *pi = j; // 错误,*pi是常量,不能修改 pi = &j; // 错误,pi是常量,不能改变 ...
虚函数与const指针 虚函数是C++多态的一种表现形式。虚函数是基类的非静态成员函数,其访问权限可以是 protected 或 public。...在使用虚函数时,需要正确地使用const指针和指向const的指针,以避免出现错误。
### 函数指针和指针函数的区分及应用 #### 函数指针的理解与使用...通过以上介绍,我们可以看出函数指针和指针函数有着本质的区别,同时正确使用 `const` 可以帮助我们更好地控制程序的行为,提高程序的安全性和效率。
<类型> const * <指针变量> 或 const <类型> * <指针变量> 2、常量指针: <类型> * const <指针变量> 3、指向常量的常量指针: <类型> const * const <指针变量> 或 const <类型> * const <指针变量>
### const指针的使用 #### 一、const指针概述 在C++中,`const`关键字被广泛用于控制变量的可修改性以及提高代码的安全性和效率。当与指针结合时,`const`可以有不同的含义,具体取决于它在声明中的位置。下面将...
如果`const`位于指针类型和星号之间,那么`const`修饰的是指针所指向的对象。 理解`const`与指针的关系,可以帮助我们编写更安全、更易维护的代码。在分析问题时,应明确指针的`const`属性和它所指向的对象的`const...
const 指针是指向常量的指针,例如: ```cpp const int *a; ``` 这里,a 是一个指向整型常量的指针,指向的对象不能被修改,但指针 a 可以指向另一个常量。例如: ```cpp const int *a = &b; a = &c; // ok! *a = 2...
const指针是一种指针,它的值不能被改变。例如:int * const p=&n;,这里declare p as a const pointer to an int,p的值不能被改变,但*p的值可以被改变。 十、总结 本文总结了复杂的C/C++声明,包括const、...
深入理解const与指针 一、可能的组合: 在 C 语言中,const 和指针的组合有很多...深入理解 const 和指针的组合是非常重要的,因为它可以帮助我们更好地理解内存空间和指针的关系,并且在编程中避免一些常见的错误。
在本文中,我们将详细介绍 C/C++ 语言中 const 的用法,包括 const 定义变量、指针的用法和不同。 首先,让我们来看一个例子: ```c const int a = 10; int *pa = &a; *pa = 20; printf("%d\n", *pa); ``` 在上面的...
// ptr是一个const指针,即指针本身的值(所指向的地址)不可改变,但可以通过ptr修改它所指向的int值。 ``` 而当我们用typedef定义一个新的类型名称时,const关键字的位置就显得尤为重要。如文章中所述的例子: ...
对于指针和常量,有以下三种形式都是正确的: 代码如下:const char * myPtr = &char_A;//指向常量的指针char * const myPtr = &char_A;//常量的指针const char * const myPtr = &char_A;//指向常量的常量指针下面...
const指针赋值给const指针是允许的,因为这不会改变指针本身的特性,而如果将const指针赋值给非const指针,则需要强制类型转换,这通常被视为不安全的操作,因为可能会试图修改const对象。 3、const与引用的结合 在...
下面我们将详细介绍C++中的引用、const指针和各种传递方式。 一、引用 在C++中,引用是变量的别名,它必须在定义时初始化,并且不能再成为其他变量的别名。引用实际上是用const指针来实现的。例如: int x = 5; ...
- 指向对象成员的指针则分为两种:指向数据成员的指针和指向成员函数的指针。前者用于指向类的特定数据成员,定义格式为:`<类型> <类名>::* <指针名> = <初值>`;后者用于指向类的特定成员函数,定义格式为:`...
根据给定文件的信息,我们可以提炼出关于“常量指针和指针常量”的相关知识点。下面将对这些概念进行详细的解析。 ### 常量指针与指针常量的概念 #### 1. 常量指针(const int *) **定义**:`const int *p` 这种...