• C语言常量与指针


    C语言功能强大而丰富,还表现在const与指针的结合使用上,对不同的问题,它提供不同的保护,特别有用的是指向常量的指针

    本文地址:http://www.cnblogs.com/archimedes/p/c-const-point.html,转载请注明源地址。

    指向常量的指针

    可以将指针指向常量,这就意味着不能通过指针修改它所引用的值

    int num = 5;
    const int limit = 500;
    int *pi;
    const int *pci;
    pi = #    //指向整数
    pci = &limit; //指向整数常量

    下面的代码会打印这些变量的地址和值:

    #include <stdio.h>
    int main(void)
    {
        int num = 5;
        const int limit = 500;
        int *pi;
        const int *pci;
        pi = &num;    //指向整数
        pci = &limit; //指向整数常量
        printf("  num - Address:%p   value:%d
    ", &num, num);
        printf("limit - Address:%p   value:%d
    ", &limit, limit);
        printf("   pi - Address:%p   value:%p
    ", &pi, pi);
        printf("  pci - Address:%p   value:%p
    ", &pci, pci);
        return 0;
    }

    不能解引指向常量的指针并改变指针所引用的值,但是指针的值不是常量,可以改变指针,指针可以改为引用另一个整数常量或普通整数

    把pci声明为指向整数常量的指针意味着:

    • pci可以被修改为指向不同的整数常量

    • pci可以被修改为指向不同的非整数常量

    • 可以解引pci以读取数据

    • 不能解引pci从而修改它指向的数据

    注意:数据类型和const的顺序无关紧要,可以互换

    const int *pci = int const *pci

    指向非常量的常量指针

    指针不可变,但是它指向的数据可变

    int num;
    int *const cpi = &num;

    如果将cpi初始化为指向常量limit将产生错误,因为cpi指向的数据可以修改,但是常量是不能被修改的

    const int limit = 500;
    int * const cpi = &limit;

    指向常量的常量指针

    这种类型的指针很少使用,这种指针不能修改,它指向的数据也不能通过它来修改,下面是一个例子:

    const int * const cpci = &limit;

    不一定只能将常量的地址赋给cpci,如下:

    int num;
    const int * const cpci = &num;

    声明此类指针的时候必须进行初始化

    指向“指向常量的常量指针”的指针

    #include <stdio.h>
    int main(void)
    {    
        const int limit = 500;
        const int * const cpci = &limit;
        const int * const * pcpci = &cpci;
        printf("%d
    ", *cpci);
        printf("%d
    ", **pcpci);
        return 0;
    }

    下表总结所讨论的四种指针:

    指针类型 指针是否可修改 指向指针的数据是否可修改
    指向非常量的指针
    指向常量的指针
    指向非常量的常量指针
    指向常量的常量指针

    举例说明

    下面的例子中,function函数返回一个指向结构体常量的指针,意味着结构体中的值是只读的,限定符很有用,因为它告诉我们一些不能进行的操作

    #include<stdio.h>
    #include<stdlib.h>
    struct a
    {
        int x;
    };
    const struct a * function(void)
    {
        struct a *ptr;
        if((ptr = (struct a *)malloc(sizeof(struct a))) == NULL)
            exit(1);
        ptr->x = 0;
        return ptr;
    }
    int main(void)
    {    
        int y;
        const struct a *ptr;
        ptr = function();
        y = ptr->x;
        return 0;
    }

    如果我们试图修改,我们将得到一个gcc error

    int main(void)
    {    
        int y;
        const struct a *ptr;
        ptr = function();
        ptr->x = 1;
        return 0;
    }

    error: assignment of read-only location ‘*ptr’
    如果将值赋值给一个非结构体常量,我们将得到gcc的警告

    int main(void)
    {    
        int y;
        struct a *ptr;
        ptr = function();
        ptr->x = 1;
        return 0;
    }

    warning: assignment discards qualifiers from pointer target type

    如果使用类型转换将可以成功运行

    int main(void)
    {
        struct a *ptr;
        ptr = (struct a *) function();
        ptr->x = 1;
        return 0;
    }

    结构体常量指针作为参数

    #include<stdio.h>
    #include<stdlib.h>
    struct a
    {
        int x;
    };
    struct b
    {
        const struct a *nested_ptr;
    };
    const struct a * function(void)
    {
        struct a *ptr;
        if((ptr = (struct a *) malloc(sizeof(struct a))) == NULL){
            exit(1);
        }
        ptr->x = 0;
        return ptr;
    }
    void do_something(const struct b *ptr)
    {
        const struct a *x = ptr->nested_ptr;
    }
    int main(void)
    {
        struct b b_obj;
        b_obj.nested_ptr = function();
        do_something(&b_obj);
        return 0;
    }

    常量指针

    将一个指针指定为常量的,const关键字放在"*"的后面,就像上面的do_something()原型可以改写为下面的形式,所有的都不可以修改,ptr变量通过调用传递参数初始化,以后就不能修改

    void do_something(const struct b * const ptr);

    常量初始化延伸

    一个结构体常量可以像下面这样初始化:

    int main(void)
    {
        const struct a obj = [ 5 ];
        return obj.x;
    }

    一个指向结构体常量的指针可以像下面这样初始化:

    int main(void)
    {
        const struct a obj = [ 5 ];
        const struct a *ptr_a = &obj;
        const struct a *ptr_b = function();
        return ptr_a->x;
    }

    返回常量指针

    const struct a * const function(void);

    传递指向常量指针的指针

    一个常见传递二重指针的原因就是需要修改指针值,看下面的例子:

    void fill_in(const struct a **location)
    {
        *location = function();
    }
    int main(void)
    {
        const struct a *ptr;
        fill_in(&ptr);
        return 0;
    }

    再看下面的代码,在location前面加上const

    void fill_in(const struct a ** const location)
    {
        *location = function();
    }

    解释如下:

    1、结构体是常量的,内容不能修改

    2、指向该结构体的指针,通过location指向,*location不是常量,可以修改

    3、变量location是常量的,意味着不能被修改

    还可以添加一个const:

    void fill_in(const struct a * const * const location)
    {
        *location = function();
    }

    error: assignment of read-only location ‘*location’ (由于*location也是常量,所以会得到gcc error)

    下面的代码不是操作结构体的内容,也不是指向结构体的指针,而是允许函数通过传递的参数操作它自身的局部变量

    void make_use_of(const struct a * const *location)
    {
        const struct a * const ptr_a = *location;
        const struct a *ptr_b = *location;
        ptr_b = NULL;
        location = NULL;
    }

    解释如下:

    1、结构体是常量的,内容不能修改

    2、指向该结构体的指针,通过location指向,*location也是常量,不可以修改

    3、变量location是非常量,意味着可以被修改

    4、局部变量ptr_a是常量,不可以被修改

    4、局部变量ptr_a不是常量,可以被修改

    参考资料

    维基百科

    《C和指针》

  • 相关阅读:
    mysql max(),min()的优化
    统计网站某天的点击数
    小程序网络图片下载
    小程序封装
    小程序 封装调用
    小程序request封装
    git 使用
    MYSQL查询语句优化
    微信开发遇到的坑
    PHP支付宝支付开发流程
  • 原文地址:https://www.cnblogs.com/wuyudong/p/c-const-point.html
Copyright © 2020-2023  润新知