首页 > 代码库 > C语言常量与指针

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\n", &num, num);    printf("limit - Address:%p   value:%d\n", &limit, limit);    printf("   pi - Address:%p   value:%p\n", &pi, pi);    printf("  pci - Address:%p   value:%p\n", &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\n", *cpci);    printf("%d\n", **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和指针》