zoukankan      html  css  js  c++  java
  • 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
    ", PI);
        printf("%s
    ", MONTH[1]);
        printf("%s
    ", 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
    ", PI);
        return 0;
    }
    // file2.c 使用在其他文件定义的全局变量
    #include<stdio.h>
    #include "constant.h"
    int main()
    {
        printf("%f
    ", PI);
        printf("%s
    ", MONTH[1]);
        printf("%s
    ", 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
    ", PI);
        printf("%s
    ", MONTH[0]);
        printf("%s
    ", MONTH[2]);
        return 0;
    }
    // file2.c调用
    #include<stdio.h>
    #include "constant.h"
    
    int main()
    {
        printf("%f
    ", PI);
        printf("%s
    ", MONTH[1]);
        printf("%s
    ", 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位于*的左侧,无论它在类型名的左边或右边,都声明了一个指向常量的指针,叫做常量指针。

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

     

     

  • 相关阅读:
    重构二叉树
    Nlog、elasticsearch、Kibana以及logstash
    技术
    Java 的垃圾回收机制(转)
    Java并发编程:并发容器之CopyOnWriteArrayList
    深入理解Arrays.sort() (转)
    浅析java的浅拷贝和深拷贝
    gradle
    @action 注解
    如何使用mysql
  • 原文地址:https://www.cnblogs.com/focus-z/p/11485612.html
Copyright © 2011-2022 走看看