C语言const修饰符探秘

来源:互联网 发布:java旅游管理项目描述 编辑:程序博客网 时间:2024/05/17 04:13

前言

C语言是我接触的第一门程序设计语言,当时还很傻很天真,后来迅速被各种高级语言洗脑,但是不得不说,C的地位真的无可撼动。

const修饰符在C语言中很常用,但是最近读代码的时候常常搞不清楚,搜索了一番,做个总结。

整体认知

const是常量修饰符,代码中设法阻止变量被改变,这个时候可以使用const关键字。必须在声明const变量就初始化,因此,类似与这样的声明是错误的:
const int i;i = 8;

编译器会报:error: assignment of read-only variable ‘i’。
我们必须要这样:
const int i = 8;

const修饰符的典型作用

  1. 最基本的,保护被修饰的作用,防止以外修改
  2. 编译器通常不为const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储和读取内存的操作,效率很高
  3. 使程序中的错误在编译的时候就被报出(因为2)。
下面会一一举例说明。

const修饰符的修饰对象探秘

修饰普通变量

const int i = 8;int const i = 8;

上面两者是等价的,都是声明了一个值为5的常量。

修饰指针

const int *p;int const *p;

上面两个是等价的,都声明了一个const int类型的指针,也就是说,程序里面不能改变*p的值,但是可以改变p的值(即可以改变指针的指向)。
int * const p = &n;

这个是声明了一个const的指针,const是修饰指针的。也即p的值不允许改变(指针就一定得指向n那块内存,不能改变p的指向),但是*p的值可以改变。

小技巧

  • const在*的左侧,const修饰指针所指的变量
  • const在*的右侧,const修饰指针本身

带const修饰的函数形参

首先要明确一点,非指针参数(值传递)传给函数的是参数的一份拷贝,本身就不会改变参数的值,所以加上const是没有意义的,例如:
#include <stdio.h>void add(const int a){        a = a + 1;}int main(){        int temp = 34;        add(temp);        printf("%d",temp);        return 0;}

虽然编译过不去,但是,就算不加const,在函数体中成功尝试修改了a,但是在本例中temp的值也是不变的,因为函数中修改的是a的一个拷贝(值传递)。
先看这个函数:
void foo(const int * p){        *p += 1;}

编译时就会报错,因为我们试图修改一个常量的值。
带const的形参是不允许在函数体内修改其值的(只读)。
不过一旦这样写就没辙了:
void foo(const int * p){        int *r = p;        *r += 1;}

虽然编译器编译时会告诉你:warning: initialization discards qualifiers from pointer target type,说你赋值丢了一个属性修饰符,但是运行时还是可以改变p所指向内存的值。
再看这样一个例子:
void foo(int *const p1) {    int a = 1;    p1 = &a; }

显然编译不过去。这样做本来是想传进来一个const的指针,但实际上,这样是没有意义的。指针作为参数时也是传进去一个指针的拷贝。所以即使不加const,函数体中也是修改的这个“指针的拷贝”。这个函数实际上和本小节开头的例子是没区别的(但是这个指针的拷贝所指向的内容可是和被拷贝的东西是一样的)。
可以用下面的图说明:

和这个是类似的: