C语言常量与指针
C语言功能强大而丰富,还表现在const与指针的结合使用上,对不同的问题,它提供不同的保护,特别有用的是指向常量的指针
本文地址:http://www.cnblogs.com/archimedes/p/c-const-point.html,转载请注明源地址。
指向常量的指针
可以将指针指向常量,这就意味着不能通过指针修改它所引用的值
int num = ;
const int limit = ;
int *pi;
const int *pci;
pi = # //指向整数
pci = &limit; //指向整数常量
下面的代码会打印这些变量的地址和值:
#include <stdio.h>
int main(void)
{
int num = ;
const int limit = ;
int *pi;
const int *pci;
pi = # //指向整数
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 ;
}
不能解引指向常量的指针并改变指针所引用的值,但是指针的值不是常量,可以改变指针,指针可以改为引用另一个整数常量或普通整数
把pci声明为指向整数常量的指针意味着:
pci可以被修改为指向不同的整数常量
pci可以被修改为指向不同的非整数常量
可以解引pci以读取数据
不能解引pci从而修改它指向的数据
注意:数据类型和const的顺序无关紧要,可以互换
const int *pci = int const *pci
指向非常量的常量指针
指针不可变,但是它指向的数据可变
int num;
int *const cpi = #
如果将cpi初始化为指向常量limit将产生错误,因为cpi指向的数据可以修改,但是常量是不能被修改的
const int limit = ;
int * const cpi = &limit;
指向常量的常量指针
这种类型的指针很少使用,这种指针不能修改,它指向的数据也不能通过它来修改,下面是一个例子:
const int * const cpci = &limit;
不一定只能将常量的地址赋给cpci,如下:
int num;
const int * const cpci = #
声明此类指针的时候必须进行初始化
指向“指向常量的常量指针”的指针
#include <stdio.h>
int main(void)
{
const int limit = ;
const int * const cpci = &limit;
const int * const * pcpci = &cpci;
printf("%d\n", *cpci);
printf("%d\n", **pcpci);
return ;
}
下表总结所讨论的四种指针:
| 指针类型 | 指针是否可修改 | 指向指针的数据是否可修改 |
| 指向非常量的指针 | 是 | 是 |
| 指向常量的指针 | 是 | 否 |
| 指向非常量的常量指针 | 否 | 是 |
| 指向常量的常量指针 | 否 | 否 |
举例说明
下面的例子中,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();
ptr->x = ;
return ptr;
}
int main(void)
{
int y;
const struct a *ptr;
ptr = function();
y = ptr->x;
return ;
}
如果我们试图修改,我们将得到一个gcc error
int main(void)
{
int y;
const struct a *ptr;
ptr = function();
ptr->x = ;
return ;
}
error: assignment of read-only location ‘*ptr’
如果将值赋值给一个非结构体常量,我们将得到gcc的警告
int main(void)
{
int y;
struct a *ptr;
ptr = function();
ptr->x = ;
return ;
}
warning: assignment discards qualifiers from pointer target type
如果使用类型转换将可以成功运行
int main(void)
{
struct a *ptr;
ptr = (struct a *) function();
ptr->x = ;
return ;
}
结构体常量指针作为参数
#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();
}
ptr->x = ;
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 ;
}
常量指针
将一个指针指定为常量的,const关键字放在"*"的后面,就像上面的do_something()原型可以改写为下面的形式,所有的都不可以修改,ptr变量通过调用传递参数初始化,以后就不能修改
void do_something(const struct b * const ptr);
常量初始化延伸
一个结构体常量可以像下面这样初始化:
int main(void)
{
const struct a obj = [ ];
return obj.x;
}
一个指向结构体常量的指针可以像下面这样初始化:
int main(void)
{
const struct a obj = [ ];
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 ;
}
再看下面的代码,在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语言常量与指针的更多相关文章
- c语言常量指针赋值给变量指针导致警告
常量指针定义:常量是形容词,指针是名词,以指针为中心的一个偏正结构短语.这样看,常量指针本质是指针,常量修饰它,表示这个指针乃是一个指向常量的指针.指针指向的对象是常量,那么这个对象不能被更改.常量指 ...
- c/c++ 函数、常量、指针和数组的关系梳理
压力才有动力,15年中旬就要准备实习,学习复习学习复习学习复习学习复习……无限循环中,好记性不如烂笔头……从数组开始,为主干. c 的array由一系列的类型相同的元素构成,数组声明包括数组元素个数和 ...
- Swift3.0语言教程使用指针创建和初始化字符串
Swift3.0语言教程使用指针创建和初始化字符串 Swift3.0语言教程使用指针创建和初始化字符串苹果的Swift团队花了不少功夫来支持C的一些基础特性.C语言中为我们提供了指针,Swift也不例 ...
- 深入理解C语言中的指针与数组之指针篇
转载于http://blog.csdn.net/hinyunsin/article/details/6662851 前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本 ...
- 深入理解C语言中的指针与数组之指针篇(转载)
前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本所在.相信,任意一家公司如果想要考察一个人对C语言的理解,指针和数组绝对是必考的一部分. 但是之前一方面之前一直在忙各种事情 ...
- C/C++语言结构体指针的使用
C/C++语言结构体指针的使用 主要内容 结构体的使用 - 定义,赋值,结构体指针 结构体作为函数参数的使用 指针的使用 代码内容重点 结构体的使用 - 定义,赋值,结构体指针 结构体作为函数参数的使 ...
- C++ 中指针常量、指向常量的指针、引用类型的常量
命题1. 在C++ 中 const T a 与 T const a 是一样的, 表示a是一个T类型的常量. 测试: 一. 形参定义为引用类型的常量 在函数传参时,形参若定义为 const T& ...
- 不可或缺 Windows Native (2) - C 语言: 常量,变量,基本数据类型
[源码下载] 不可或缺 Windows Native (2) - C 语言: 常量,变量,基本数据类型 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 常量 变量 基本 ...
- C语言中的指针数组
C语言中的指针数组是什么,像 char *a[]={"ddd","dsidd","lll"}; 这里讲一下注意如果我们使用了a也就是首元素的 ...
随机推荐
- Android 优化布局层次结构
前面介绍过使用HierarchyViewer和Android lint来优化我们的程序,这一篇算是总结性的,借助一个小例子来说用怎么优化应用布局.这个例子是android官网给出的,作者也当一把翻译. ...
- mysql中替换字符串(正则) 模糊
例如: abcd(efg)hijk 替换之后是abcdhijk , name)),''); 执行之后,报错:Truncated incorrect DOUBLE value解决办法,经过查询发现是co ...
- 审核流(2)流程设计-SNF.WorkFlow功能使用说明--SNF快速开发平台3.1
流程设计 图形化的流程设计,更方便.直观 1.打开“流程设计“程序,如上.点击”新建“如下: 2.红色部分为必填项,审批对象是选择要审批的程序菜单,单据名称是在审核流流转时用于提示的单据名称,还要选择 ...
- Android应用安全之外部动态加载DEX文件风险
1. 外部动态加载DEX文件风险描述 Android 系统提供了一种类加载器DexClassLoader,其可以在运行时动态加载并解释执行包含在JAR或APK文件内的DEX文件.外部动态加载DEX文件 ...
- php分享三十三:常量
一:常量定义 1:在脚本执行期间该值不能改变(除了所谓的魔术常量,它们其实不是常量) 2:常量默认为大小写敏感 3:命名规则:用正则表达式是这样表达的:[a-zA-Z_\x7f-\xff][a-zA- ...
- 0x00411202指令引用的0x00000000内存该内存不能为read错误,怎么解决
0X000000该内存不能为read的解决方法 出现这个现象有方面的,一是硬件,即内存方面有问题,二是软件,这就有多方面的问题了. 一.先说说硬件问题,主要方面是: 1.内存条坏了 更换内存条 2.双 ...
- [Node.js] 也说this
原文地址:http://www.moye.me/2014/11/21/也说this/ 引子 Any sufficiently advanced technology is indistinguisha ...
- 前端优化:RequireJS Optimizer 的使用和配置方法
RequireJS Optimizer 是 RequireJS 自带的前端优化工具,可以对 RequireJS 项目中的 JavaScript & CSS 代码使用 UglifyJS 或者 C ...
- Guzzle – 构建 RESTful Web 服务的 PHP HTTP 框架
Guzzle 减轻了发送 HTTP 请求和创建 Web 服务客户端的痛苦.它包含建立一个强大的网络服务客户端的工具,包括:服务描述定义的输入和输出的 API,资源迭代器遍历分页资源,尽可能有效地发送大 ...
- 较友好的Web文件下载用户体验实例
1.实际需求整理与分析 该问题起源于为公司做的一个B/S架构的游戏静态数据管理工具,其中有一个需求是点击页面上的一些按钮要下载文件,可能根据按钮类型的不同需要转换下载.json..zip..xlsx等 ...