const int a = 1;
int const a = 1;
const关键字修饰变量a,表示a是一个整型变量,且这个变量的值是不可改变的。这两个定义的作用一样,编译后变量a分配在只读数据段中,这个数据段在一块只读的内存区域中,任何对这块区域的操作都是非法的。
如下面的程序:
#include <stdio.h>
int main(void)
{
int const a = 100;
a = 200;
return 0;
}
编译器会报错:
所以在定义的时候对该变量舒适化是使得该变量具有值的唯一机会。
const关键字修饰指针--在指针定义之前
const关键字在指针变量的定义之前,如下所示:
int const a = 100;
const int *p; //指针指向的内容不能改变
//等同于 int const *p;
p = &a;
该定义表示p是一个指针变量,指向一个整型变量的存储空间,并且这个整型变量是一个不可改变的值的变量。也就是说指针p是可以改变的,而指针所指向的内容是不可改变的。
例如:
#include <stdio.h>
int main(void)
{
int a = 100;
int b = 200;
const int *p;
p = &a;
printf("a = %d\n", *p);
*p = 200; //错误,指针所指向的内容(通过*p方式)不能改变
p = &b; //正确,指针本身可以改变
printf("a = %d\n", *p);
return 0;
}
运行结果为:
const关键字修饰指针--在指针定义之中
const关键字在指针变量的定义之中:
int a = 100;
int * const p = &a; //指针本身不能改变
该定义表示p是一个指针变量,指向一个整型变量的存储空间,并且这个整型变量是一个可以改变值的变量。而指针p的值不能改变,只能永远指向这个内存单元,也就是说指针p是不可以改变的,而指向的内容是可以改变的。
例如:
#include <stdio.h>
int main(void)
{
int a = 100;
int b = 200;
int * const p = &a;
printf("a = %d\n", *p);
*p = 200; //正确,指针所指向的内容(通过*p方式)可以改变
//p = &b; //指针本身不可以改变
printf("a = %d\n", *p);
return 0;
}
运行结果:
const关键字修饰指针--在指针定义之前和定义之中
在指针变量定义之前和定义之中均有关键字,如下:
const int a = 100;
int const * const p = &a; //指针和指针指向的内容都不能改变
该定义表示a是一个指针变量,指向一个整型变量的存储空间。这个整型变量是一个不能改变值的变量,而且指针a的值也不能改变:
例如:
#include <stdio.h>
int main(void)
{
int a = 100;
int b = 200;
int const * const p = &a;
printf("a = %d\n", *p);
*p = 200; //错误,指针所指向的内容不能改变
p = &b; //错误,指针本身不可以改变
printf("a = %d\n", *p);
return 0;
}
编译结果:
指向非const变量的指针或者非const变量的地址可以传给指向const变量的指针,C语言可以做隐式转换,如下:
int a = 100;
const int *p;
p = &a; //常量指针指向一个普通变量
但是指向const变量的指针,或者const变量的指针币可以传给非const变量的指针,以免意外修改了const存储区的内容,如下:
const int a = 100;
int *p = &a; //普通指针不能指向一个常量变量
使用const关键字的意义
- 合理的只用cosnt关键字,可以使编译器保护那些不希望被改变的参数,防止被意外修改,可以较少bug的出现。
- 关键字const是为了告诉用户这个参数的引用目的。例如一个函数的参数是const char*,这样用户就可以放心的传给它char*或者const char*指针,而不必担心指针所指的内存区域被改写
- 通过给编译器一些附加信息,是const关键字也许能产生更紧凑的代码
第一点是最重要的,来看一个程序:
#include <stdio.h>
//将所有空格替换为"_",失败返回NULL
char * replace(char *str)
{
char *p;
if(str == NULL)
return NULL;
p = str;
while(*p != '\0'){
if(*p == ' ')
*p = '_'; //进行字符串的替换
p++;
}
return p;
}
int main(void)
{
char *p = "hello world and china\n";
if(replace(p) != NULL)
printf("the string : %s\n", p);
return 0;
}
编译并运行程序:
程序出现了段错误,说明内存访问出错了,这个错误出现在*p = '_';这个语句上。该语句将字符串的值修改,但是作为replace()函数的参数的源字符串是一个字符串常量,这个常量被分配在只读数据段中。因此对次字符串的操作造成了非法内存访问,出现了段错误。
如果使用const关键字可以很好的预防这个问题。
修改上面的程序,使用const关键字对字符创常量进行声明,编译器会发现修改常量的错误:
#include <stdio.h>
//将所有空格替换为"_",失败返回NULL
const char * replace(const char *str) //使用const修饰变量
{
const char *p;
if(str == NULL)
return NULL;
p = str;
while(*p != '\0'){
if(*p == ' ')
*p = '_'; //进行字符串的替换
p++;
}
return p;
}
int main(void)
{
const char *p = "hello world and china\n"; //将源字符串声明为const变量
if(replace(p) != NULL)
printf("the string : %s\n", p);
return 0;
}
编译结果:
编译器报错,提示*p = '_';出错,程序试图写只读数据段的错误被编译器发现了,这时开发人员可以很容易就可以发现这个错误。本来在运行时才出现的错误,在编译阶段就由编译器发现了,这样就省了大量的调试时间,这对程序开发来说是很有益的。