限定修饰符const

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 = '_';出错,程序试图写只读数据段的错误被编译器发现了,这时开发人员可以很容易就可以发现这个错误。本来在运行时才出现的错误,在编译阶段就由编译器发现了,这样就省了大量的调试时间,这对程序开发来说是很有益的。

 

转载于:https://my.oschina.net/daowuming/blog/768872

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值