C Const

C90增加了两个属性:不变性和易变性.

通过关键字const 和 volatile 声明的, 这样就创建了受限类型(qualified type).

C99 增加了第三个限定词restrict, 用以方便编译器优化。

类型限定词 const 

如果变量声明中带有关键字const,则不能通过赋值、增量或减量来修改该变量的值。

const int nochange; /* constant */
nochange = 12 /* false */

可以初始化一个const 变量, 初始化之后,不可以再改变它。

const int nochange = 12  // true
const int days1[3] = {31,30,31}; // true

在指针和参量声明中使用const

特别注意区分: 指针本身是const     与        指针指向的值是const

const 紧挨着的是什么,什么就是不变的

const int days1[3] = {31,30,31}; // true  相当于 const int *days1 ;  const在 * 左边, 使得数据成为常量

const float *pf  ; // const 紧挨着 float ,说明 float常量是不变的

float *const pt ;  // const紧挨着 指针pt,说明是一个常量指针

float const *pt; // const紧挨着 *pt, 相当于解引用,是float 常量,不是指针,注意区分

后面有更好的理解方法!!!

1. 指针指向的值是const

const float *pf ;  // pf 指向一个常量

特别注意: const放置在不同的位置,有不同的含义,注意区分!!!

float const *pfc; // 等同于 const float *pfc

把const放在 类型名 的后边和 * 的前边,意味着指针不能够用来改变它所指向的值。

总之:下面理解起来比较容易

一个位于 *左边 任意位置的 const 使得 数据成为常量 

而 一个位于 * 右边 的const使得  指针自身成为常量

 

但是pf本身的值是可以改变的(本身是个地址),它可以指向另一个const值

eg:

const float *pf_new;

pfc  = pf_new;

2. 指针本身是const (指针本身的值不可变)

eg:

float * const pt;  // pt 是一个常量指针

 

必须总是指向同一个地址,但所指向的值可以改变。

3.  地址是常量,地址指向的内容也是常量

const float * const ptr;

意味着ptr必须总是指向同一个位置(地址),并且它所指位置存储的值也不能改变。

 

4.  常见用法

常见用法是声明作为函数形式参量的指针。

eg:

一个名为display()的函数显示一个数组的内容。 为了使用它,可以把数组名作为参数传送,但数组名是一个地址,

这样做将允许函数改变调用函数中的数据。下面的原型防止了这样的情况发生。

void display(const int array[], int limit);

在函数原型和函数头部,参量声明 const int array[]  与 const int *array, 该声明表明array指向的数据是不可变的。

 

5. 对全局数据使用const

文件中共享const 全局常量

策略一:不使用 .h 文件 , 在一个文件中进行定义声明,在下一个文件中进行引用声明

 

// file1.c  定义一些全局变量
const double PI = 3.14159;
const char *MONTH[3] = { "january","february","march" };

 

// file2.c 使用其他文件中定义的全局变量
#include<stdio.h>

extern  double PI;
extern char *MONTH[]; // 引用声明

int main()
{
    printf("%f\n", PI);
    printf("%s\n", MONTH[1]);
    printf("%s\n", MONTH[2]);

    return 0;
}

策略二:使用 .h 文件 , 将常量放在一个include文件中。这时还必须使用静态外部存储类

// 将常量放在一个include文件中。这时还必须使用静态外部存储类
#ifndef _CONSTANT_H
#define _CONSTANT_H

static const double PI = 3.14159;
static const char *MONTH[3] = { "january","february","march" };

#endif
// file1.c 使用在其他文件定义的全局变量
#include<stdio.h>
#include "constant.h"

int  file1_print();

int  file1_print()
{
    printf("%f\n", PI);
    return 0;
}
// file2.c 使用在其他文件定义的全局变量
#include<stdio.h>
#include "constant.h"
int main()
{
    printf("%f\n", PI);
    printf("%s\n", MONTH[1]);
    printf("%s\n", MONTH[2]);
    int a = file1_print();
    return 0;
}
 

static是必不可少的,通过使每个标识符成为静态外部的,实际上给了每个文件一个独立的数据拷贝。

缺点: 复制了数据,如果常量数据包含着巨大的数组,可能是一个问题。头文件尽量不要定义全局变量

策略三:项目中常见的使用方法

.h 头文件extern 声明该变量,在 .c源文件中定义这个变量

其他 .c 文件如果要调用这个变量,直接包含头文件即可。

//constant.h 声明
#ifndef  _CONSTANT_H
#define  _CONSTANT_H

extern  double PI;
extern  char *MONTH[];

#endif
// constant.c 定义
#include "constant.h"

double PI = 3.14159;
char *MONTH[3] = { "january","february","march" };
// file1.c 调用
#include<stdio.h>
#include "constant.h"

int  file1_print();

int  file1_print()
{
    printf("%f\n", PI);
    printf("%s\n", MONTH[0]);
    printf("%s\n", MONTH[2]);
    return 0;
}
// file2.c调用
#include<stdio.h>
#include "constant.h"

int main()
{
    printf("%f\n", PI);
    printf("%s\n", MONTH[1]);
    printf("%s\n", MONTH[2]);
    int a = file1_print();
    return 0;
}

 

 

6. const 指针变量间的赋值关系   常量指针  指针常量 傻傻分不清楚!!!

https://www.cnblogs.com/witty/archive/2012/04/06/2435311.html

 

 

 

一) 常量指针。

 

常量是形容词,指针是名词,以指针为中心的一个偏正结构短语。这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针(变量)。

 

指针指向的对象是常量,那么这个对象不能被更改。

 

在C/C++中,常量指针是这样声明的:

 

1)const int *p;

 

2)int const *p;

 

常量指针的使用要注意,指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改,也就是说常量指针可以被赋值为变量的地址,之所以叫做常量指针,是限制了通过这个指针修改变量的值。例如:

 

int a = 5;

 

const int b = 8;

 

  const int *c = &a; // 这是合法的,非法的是对c的使用

 

*c = 6; // 非法,但可以这样修改c指向的对象的值:a = 6;

 

const int *d = &b; // b是常量,d可以指向b,d被赋值为b的地址是合法的

 

  细心的朋友在使用字符串处理函数的时候,应该会注意到这些函数的声明。它们的参数一般声明为常量指针。例如,字符串比较函数的声明是这样的:

 

int strcmp(const char *str1, const char *str2);

 

可是这个函数却可以接收非常量字符串。例如这段程序:

 

char *str1, *str2;

 

str1 = "abcde1234";

 

str2 = "bcde";

 

if(strcmp(str1, str2) == 0)

 

{

 

printf("str1 equals str2.");

 

}

 

str1和str2的内容显然是可以更改的,例如可以使用“str1[0] = x;”这样的语句把str1的内容由“abcde1234”变为“xbcde1234”。因为函数的参数声明用了常量指针的形式,就保证了在函数内部,那 个常量不被更改。也就是说,对str1和str2的内容更改的操作在函数内部是不被允许的。(就目前的应用来看,我觉得设置常量指针就是为函数参数声明准 备的,不然还真不知道用在什么地方呢,呵呵!)

 

虽然常量指针指向的对象不能变化,可是因为常量指针是一个变量,因此,常量指针可以不被赋初始值,且可以被重新赋值。例如:

 

const int a = 12;

 

const int b = 15;

 

const int *c = &a; // 为了简化代码,很多人习惯赋初始值

 

const int *d;

 

d = &a; // 这样当然是可以的

 

c = &b; // 虽然c已经被赋予初始值,可是仍然可以指向另一个变量

 

特点是,const的位置在指针声明运算符*的左侧。只要const位于*的左侧,无论它在类型名的左边或右边,都声明了一个指向常量的指针,叫做常量指针。

 

可以这么想,*左侧是常量,指针指向的对象是常量。

 

 

 

 

posted @ 2019-09-08 13:23  清风oo  阅读(254)  评论(0编辑  收藏  举报