文档章节

限定修饰符const

大道无名
 大道无名
发布于 2016/10/22 22:02
字数 1483
阅读 7
收藏 0
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 = '_';出错,程序试图写只读数据段的错误被编译器发现了,这时开发人员可以很容易就可以发现这个错误。本来在运行时才出现的错误,在编译阶段就由编译器发现了,这样就省了大量的调试时间,这对程序开发来说是很有益的。

 

© 著作权归作者所有

大道无名
粉丝 29
博文 161
码字总数 96019
作品 0
宣城
程序员
私信 提问
关于const char*和char*、const char** 和char** 赋值问题

根据ANSI C标准的赋值约束条件: 1. 两个操作数都是指向有限定符或无限定符的相容类型的指针。 2. 左边指针所指向的类型必须具有右边指针所指向类型的全部限定符。 一、const char和char co...

余二五
2017/11/08
0
0
C++变量的存储说明符和cv-限定符

在C++中创建变量时,前面有时会有一些修饰符,这里总结一下。 大体分为两个类别:存储说明符和cv-限定符。 存储说明符 存储说明符有下面这些: auto register static extern mutable auto修饰...

Cloudox_
2017/12/02
0
0
容易混淆的const

关键字const并不能把变量变成常量。在一个符号前加上const限定符只是表示这个符号不能被赋值。它的值对于这个符号是只读的,但他不能防止通过程序的内部(甚至是外部)的方法来修改这个值。 ...

superPershing
2017/02/16
0
0
C语言中的CONST使用

C中的CONST使用 const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的安全性和可靠性。 const的使用是c语言中一个比较微妙的地方,请看下面几个问题...

晨曦之光
2012/03/09
657
0
C Primer Plus 第12章 12.9 总结

用于存储程序数据的内存可用存储时期、作用域和链接来表征。存储时期可以是静态的、自动的或者分配的。如果是静态的,内存在程序开始执行时被分配,并在程序运行时一直存在。如果是自动的,变...

idreamo
2016/12/28
25
0

没有更多内容

加载失败,请刷新页面

加载更多

Kubernetes云供应商架构的未来

首先,我想分享SIG的使命,因为我们用它来指导我们现在和将来的工作。从我们的章程中直接来看,SIG的使命是简化,开发和维护云供应商集成,作为Kubernetes集群的扩展或附加组件。这背后的动机...

Linux就该这么学
14分钟前
0
0
线程池没你想的那么简单

前言 原以为线程池还挺简单的(平时常用,也分析过原理),这次是想自己动手写一个线程池来更加深入的了解它;但在动手写的过程中落地到细节时发现并没想的那么容易。结合源码对比后确实不得...

crossoverJie
21分钟前
13
0
Scientific Linux开发停止 相关设备将迁移至CentOS上

在经历了将近14年的版本更迭之后,这个专注于科学领域的GNU/Linux发行版本不会发布下个重大版本更新--Scientific Linux 8了。 目前维护该发行版本的成员最终决定是时候休息了,今后将不再发布...

linuxCool
26分钟前
0
0
Redux

Redux概念 Redux = Reducer + Flux,数据层框架,将所有数据都存储到store中 Redux的工作流程 Antd的使用 安装npm install antd --save import 'antd/dist/antd.css'import { Input, Butto......

星闪海洋
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部