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和指针》

C语言常量与指针

时间: 2024-10-12 21:00:30

C语言常量与指针的相关文章

c语言常量指针赋值给变量指针导致警告

常量指针定义:常量是形容词,指针是名词,以指针为中心的一个偏正结构短语.这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针.指针指向的对象是常量,那么这个对象不能被更改.常量指针的使用要注意,指针指向的对象不能通过这个指针来修改,可是仍然可以通过原来的声明修改,也就是说常量指针可以被赋值为变量的地址,之所以叫做常量指针,是限制了通过这个指针修改变量的值. 在C/C++中,常量指针是这样声明的: 1)const int *p; 2)int const *p; 例子: int

C语言常量指针与指针常量

常量指针,表述为"是常量的指针",就是指向常量的指针,关键字 const 出现在 * 左边,表示指针所指向的地址的内容是不可修改的,但指针自身可变. 指针常量,表述为 "是指针的常量", 指针吱声是一个常量,关键字 const 出现在 * 右边,表示指针自身不可变,但其所指向的地址的内容是可以被修改的. 例: 常量指针:const char* ptr = "hello" 指针常量:char* const ptr = "hello&quo

C语言中关于指针的学习

指针是C语言中广泛使用的一种数据类型. 运用指针编程是C语言最主要的风格之一.利用指针变量可以表示各种数据结构: 能很方便地使用数组和字符串: 并能象汇编语言一样处理内存地址,从而编出精练而高效的程序.指针极大地丰富了C语言的功能. 学习指针是学习C语言中最重要的一环, 能否正确理解和使用指针是我们是否掌握C语言的一个标志.同时, 指针也是C语言中最为困难的一部分,在学习中除了要正确理解基本概念,还必须要多编程,上机调试.只要作到这些,指针也是不难掌握的. 指针的基本概念 在计算机中,所有的数据

c/c++ 函数、常量、指针和数组的关系梳理

压力才有动力,15年中旬就要准备实习,学习复习学习复习学习复习学习复习……无限循环中,好记性不如烂笔头……从数组开始,为主干. c 的array由一系列的类型相同的元素构成,数组声明包括数组元素个数和类型,c 中的数组参数是引用形式传参(传址调用),而常量标量是按值传递. //[]方括号表示声明的是数组,里面的数字表明了数组包含的元素数目 int states[50];//声明50个整数的数组 double code[365];//声明365个浮点数的数组 char chr[20];//声明20

黑马程序员-C语言基础:指针类型与指针和数组、字符串的关系

//指针变量就是用来存储地址的,只能存储地址 格式:  int  *p;  这个p为指针变量:指针变量占8个字节 类型是用来说明这个指针指向的类型: 比如上边的int代表这个指针变量会指向int类型的存储空间: int *p = &a;//这样一句可以写,此时的*只是一个标志,表示这个*只是表示p是个指针: *p = &a;//这样写就错了:此时*p表示取p指向的空间的值: 指针疑问:指针既然都占据8个字节,那么为什么要划分类型, 是因为当用*p指针取值或者赋值的时候,知道该取几个字节,比

C语言review之指针(1)

1.一元运算符* .&优先级比运算符的优先级高. eg.*ip += 1 等同于 ++*ip 或者(*ip)++ 注意,(*ip)++ 必须加括号,因为类似*和++这样的一元运算符遵循从右到左的顺序. 2.[指针与数组]计算数组元素a[i]的值,c语言实际上先将其转换为*(a+i)的形式,然后再求值. eg.a[i] 与 *(a+i).&a[i] 与 a+i 等价 注意,数组名与指针之间的一个不同,指针是一个变量,{pa = a,pa ++}是合法的,{a = pa,a++}是不合法的.

Swift3.0语言教程使用指针创建和初始化字符串

Swift3.0语言教程使用指针创建和初始化字符串 Swift3.0语言教程使用指针创建和初始化字符串苹果的Swift团队花了不少功夫来支持C的一些基础特性.C语言中为我们提供了指针,Swift也不例外,开发者可以使用指针去创建和初始化字符串. (1)在NSString中init(bytes:length:encoding:)方法可以从给定字符串按照指定获取方向,得到指定个数的字符,然后使用这些字符创建和初始化字符串.其语法形式如下: convenience init?(bytes: Unsaf

深入理解C语言中的指针与数组之指针篇(转载)

前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本所在.相信,任意一家公司如果想要考察一个人对C语言的理解,指针和数组绝对是必考的一部分. 但是之前一方面之前一直在忙各种事情,一直没有时间静下心来写这些东西,毕竟这确实是一件非常耗费时间和精力的事情:一方面,个人对C语言的掌握和理解也还有限,怕写出来的东西会对大家造成误导.当然,今天写的这些东西也肯定存在各种问题,不严谨甚至错误的地方肯定有,也希望大家来共同探讨,相互改进. 我会慢慢的写完这几章,有想法的童鞋可以和我探讨

C语言 结构体指针赋值 incompatible types when assigning to type &#39;char[20]&#39; from type &#39;char *&#39;

strcpy(pstudent->name, "guo zhao wei "); 为什么错误,该怎么写,(红色行) 追问 为什么不能直接赋值啊, 追答 用char nnnn[20]定义的,用strcpy 用char *ppp定义的,用=来赋值 C语言 结构体指针赋值 incompatible types when assigning to type 'char[20]' from type 'char *'