这两个概念可以说是很容易就在C语言中弄混淆了;先列举几个例子
(1):const char* p;
(2):char* const p = a;
(3):char* p = "abc";
下面是分析:
语句(1)中定义了一个常量指针,即指向一个常量的指针,指向的内容是常量,不可修改,放在常量区的,但指针本身可以修改,即“*p = 'b'"是非法的,*p是p指向的常量的第一个字符,是个常量,不能改变的。"p = &q"这是可以的,指针可以指向不同的地址。
语句(2)中定义了一个指针常量,即指针本身是个常量,不可修改,但指针指向的内容可以修改,一开始定义时让它指向数组a,“*p = 'b'”这是可以的,但"p = &q"是非法的。
小结:const常量*指针,当const在*之前就是常量指针,而const在*之后,就是指针常量。
例如:“const char *p" 即char *p是个常量,所以内容是常量;
“char* const p”即指针p是一个常量。
语句(3)中 “char *p” 定义的是一个指针变量p,指针字符串abc的首地址。这里特别要注意,在C语言中,(3)中定义的是一个常量字符串,它被放在静态存储区的常量区存储,而p是一个指针变量,放在栈上。如果“*p = 'b'”在编译时能通过,但在运行时就会出现错误,因为你试图去改变常量区的内容。
下面来看代码实例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
char a[] = "ABCDE";
char b[] = "abcde";
char* p1 = "abcde";
const char* p2 = "abcde";
char* const p3 = p1;
*p1 = 'A'; //编译能通过,运行时发生错误,这是因为试图去改变常量区的内容
*p2 = 'A'; //编译不能通过,常量指针,p2指向字符串常量,内容不能被改变
p2 = a; //可以,修改的是指针p2的值
*p3 = 'A'; //若p3指向数组a,则编译运行都能通过,如果p3指向字符指针变量p1,
//那么编译能通过,运行不通过,因为试图去改变常量区的内容
p3 = a; //不可以,指针常量,指针本身是一个常量,不可以被修改
p1 = a;
printf("%s\n",p3); //abcde,p3指向指针变量p1,p1在一开始指向常量区,
//此时,p1指向a,但p3仍然指向p1原来的地址
return 0;
}
总之,常量指针指向的内容不可改变,但地址可以改变,即指针可以指向别的地址;而指针常量是指指针本身不变,而内容可以修改。在这里,还需要注意两点:
(1):如果指针常量指向的是字符指针变量,那么当修改*p时,原则上能够修改,在编译时能通过,但在运行时不能通过,因为它试图去修改常量区的内容,显示是非法的。
(2):当指针常量指向一个另外一个指针时, 当这个指针指向别的内容时,那么指针常量还是指向原先的内容。例如:
char *p = "123";
char *q1 = "456";
char* const p = q;
q = p1;
下面再来说一说常量指针的应用:
在常量指针中,字符串的值不可修改,这在求字符串长度与字符串复制时是很方便的。指针可以操作,但保证了字符串的不被修改。参考代码如下:
int strlen1(const char* b)
{
int i = 0;
while(*b != '\0')
{
i++;
b++;
}
return i;
}
char* strcpy1(char* p,const char* q)
{
char* des = p;
while((*p=*q) != '\0')
{
//不能试图通过改变形参的值来改变实参(即不能试图通过改变地址来改变实参),
//指针传递传的是地址,改变其地址内的内容,也就改变了原来实参的值
p++;
q++;
}
*p = '\0';
return des;
}