此质料是摘要:<<彻底搞定C
指针 >>,自己感觉比较有价值,现与大家分享。

1. const int
说起

你知道我们声明一个变量时象这样int
i ;这个i是可能在它处重新变赋值的。如下:

int i = 0;

i = 20;

不过有一天我的程序可能需要这样一个变量(暂且称它变量),在声明时就赋一个初始值。之后我的程序在其它任何处都不会再去重新对它赋值。那我又应该怎么办呢?用const 。

const int ic =20;

ic = 40;

有了const修饰的ic我们不称它为变量,而称符号常量,代表着20这个数。这就是const的作用。ic是不能在它处重新赋新值了。

认识了const 作用之后,另外,我们还要知道格式的写法。有两种:

const int ic =
20; 与int const ic = 20;

它们是完全相同的。这一点我们是要清楚。总之,你务必要记住const
与int哪个写前都不影响语义。有了这个概念后,我们来看这两个家伙:

const int
*pi

int const
*pi

按你的逻辑看,它们的语义有不同吗?呵呵,你只要记住一点:int const 哪个放前哪个放后都是一样的,就好比const
int ic;与int constic;一样。也就是说,它们是相同的。

好了,我们现在已经搞定一个“双包胎”的问题。那么

int *const
pi;

与前两个语句又有什么不同呢?我下面就来具体分析它们的格式与语义吧!

2. const
int *pi
的语义

我先来说说const int
*pi是什么作用 (当然int const *pi也是一样的,前面我们说过,它们实际是一样的)。看下面的例子:

int i1 =
30;

int i2 =
40;

const int *pi =
&i1;

pi =
&i2;

i2 = 80;

printf("%d\n",*pi);

语义分析:

看出来了没有啊,pi的值是可以被修改的。即它可以重新指向另一个地址的,但是,不能通过*pi来修改i2的值。这个规则符合我们前面所讲的逻辑吗?当然符合了!

首先const修饰的是整个*pi(注意,我写的是*pi而不是pi)。所以*pi是常量,是不能被赋值的(虽然pi所指的i2是变量,不是常量)。

其次,pi前并没有用const修饰,所以pi是指针变量,能被赋值重新指向另一内存地址的。你可能会疑问:那我又如何用const 来修饰pi呢?其实,你注意到int *const
pi中const 的位置就大概可以明白了。请记住,通过格式看语义。哈哈,你可能已经看出了规律吧?那下面的一节也就没必要看下去了。不过我还得继续我的战斗!

3. 再看int *const pi

确实,int*const
pi与前面的int const
*pi会很容易给混淆的。注意:前面一句的const 是写在pi前和*号后的,而不是写在*pi前的。很显然,它是修饰限定pi的。我先让你看例子:

int i1 = 30;

int i2 = 40;

int *const pi
=&i1;

i1 = 80;

printf("%d",
*pi);

语义分析:

看了这段代码,你明白了什么?有没有发现pi值是不能重新赋值修改了。它只能永远指向初始化时的内存地址了。相反,这次你可以通过*pi来修改i1的值了。与前一个例子对照一下吧!看以下的两点分析:

1)pi因为有了const
的修饰,所以只是一个指针常量:也就是说pi值是不可修改的(即pi不可以重新指向i2这个变量了)(请看第4行的注释)。

2)整个*pi的前面没有const
的修饰。也就是说,*pi是变量而不是常量,所以我们可以通过*pi来修改它所指内存i1的值(请看第5行的注释)。

总之一句话,这次的pi是一个指向int变量类型数据的指针常量。

我最后总结两句:

1) 如果const
修饰在*pi前,则不能改的是*pi(即不能类似这样:*pi=50;赋值)而不是指pi。

2) 如果const
是直接写在pi前,则pi不能改(即不能类似这样:pi=&i;赋值)。

请你务必先记住这两点,相信你一定不会再被它们给搞糊了。现在再看这两个声明语句int const *pi和int
*constpi时,呵呵,你会头昏脑胀还是很轻松惬意?它们各自声明的pi分别能修改什么,不能修改什么?再问问

自己,把你的理解告诉我吧,可以发帖也可以发到我的邮箱(我的邮箱yyf977@163.com)!我一定会答复的。

4.补充三种情况

这里,我再补充以下三种情况。其实只要上面的语义搞清楚了,这三种情况也就已经被包含了。不过作为三种具体的形式,我还是简单提一下吧!

情况一:int
*pi指针指向const int i常量的情况

const int i1 =
40;

int *pi;

pi =
&i1;

pi = (int *)
&i1;

情况二:const int
*pi指针指向const int i1的情况

const int
i1=40;

const int *
pi;

pi=&i1;

情况三:用const int *const
pi声明的指针

int i;

const int *
constpi=&i;


0



const&nbsp;int&nbsp;*pi与int&amp;nbs…的更多相关文章

  1. VS2013 error C2556: “const int &Array<int>::operator [](int)”: 重载函数与“int &Array<int>::operator [](int)”只是在返回类型上不同

    1,VS2013 错误 1 error C2556: “const int &Array<int>::operator [](int)”: 重载函数与“int &Array ...

  2. (int &)a 和(int)a

      [cpp] view plain copy float a = 1.0f;     cout < < (int)a < < endl;     cout < < ...

  3. open_clientfd(char* hostname,int port)和open_listenfd(int port)

    #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h&g ...

  4. C语言复杂声明-void (*signal(int sig, void (*handler)(int)))(int);

    问题提出 请分析此声明:void (*signal(int sig, void (*handler)(int)))(int); 求解过程 在对上面的例子作分析之前,我们需要了解C语言的声明优先级,&l ...

  5. 编写Java应用程序。首先,定义描述学生的类——Student,包括学号(int)、 姓名(String)、年龄(int)等属性;二个方法:Student(int stuNo,String name,int age) 用于对对象的初始化,outPut()用于输出学生信息。其次,再定义一个主类—— TestClass,在主类的main方法中创建多个Student类的对象,使用这些对象来测 试Stud

    package zuoye; public class student { int age; String name; int stuNO; void outPut() { System.out.pr ...

  6. C++中int *p[4]和 int (*q)[4]的区别

    这俩兄弟长得实在太像,以至于经常让人混淆.然而细心领会和甄别就会发现它们大有不同. 前者是指针数组,后者是指向数组的指针.更详细地说. 前: 指针数组;是一个元素全为指针的数组.后: 数组指针;可以直 ...

  7. 如何理解这段代码:void (*signal (int sinno,void(*func)(int)))(int)

    void (*signal (int sinno,void(*func)(int)))(int) 先来看void(*func)(int)   这里的意思是声明一个函数指针func,它的参数类型为int ...

  8. HSSFClientAnchor(int dx1,int dy1,int dx2,int dy2,short col1,int row1,short col2, int row2)

      public HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int  ...

  9. C++中(int&)和(int)的区别

    在说这个问题之前,先说两个需要知道的背景知识: (1)语言的类型的强制转换不会修改原来的数据,会另外的开辟一个临时的或者程序中指定的空间来存储强制转换后的值. (2)C++引用的实现是在符号表中动了手 ...

随机推荐

  1. PHP获取访问页面HTTP状态码的实现代码

    方法一 $header_info=get_headers('//www.jb51.net/'); echo $header_info[0]; //耗时 0.67~0.78 方法二 $ch = curl ...

  2. TCP中的服务端与客户端的实现

    TCP中首先要在服务端开启监听,这样才可以从客户端链接 using System; using System.Collections.Generic; using System.Linq; using ...

  3. Android Issue分析方法(用anr来说明)

    Log的产生大家都知道 , 大家也都知道通过DDMS来看log , 但什么时候会产生log文件呢 ?一般在如下几种情况会产生log文件 . 1,程序异常退出 , uncaused exception ...

  4. 2——FFMPEG之协议(文件)操作----AVIOContext, URLContext, URLProtocol

    协议操作对象结构: 协议(文件)操作的顶层结构是AVIOContext,这个对象实现了带缓冲的读写操作:FFMPEG的输入对象AVFormat的pb字段指向一个AVIOContext. AVIOCon ...

  5. Photoshop脚本指南——Hello World

    作为一个程序猿,每一个东西的学习都是从Hello World开始的,从今天开始,让我们一起进入Photoshop脚本的世界,并以Hello World开始我们的旅程. 1.简介 Photoshop支持 ...

  6. 在C / C ++中清除输入缓冲区

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

  7. 判定客户端IP所在的省市[2]

    在上一篇地址控件的基础上,添加了判定客户端IP所在省市的功能. 调用新浪提供的IP库接口:http://counter.sina.com.cn/ip/,(可直接点击链接查看返回的数据) 126提供的接 ...

  8. Consul做服务发现

    使用Consul做服务发现的若干姿势 https://www.cnblogs.com/bossma/p/9756809.html 从2016年起就开始接触Consul,使用的主要目的就是做服务发现,后 ...

  9. 数据库SQL、SQLite语句单引号、双引号的用法

    最近编程操作数据库语句的时候出现一些问题. 关于Insert字符串 ,在(单引号,双引号)这个方面发生了问题,其实主要是因为数据类型和变量在作怪. 下面我们就分别讲述,虽然说的是Insert语句, 但 ...

  10. 一次SQL Server 10054 Troubleshooting

    问题 对某个库新增了一个订阅节点,然后需要把一些应用切到新订阅库,以分散负载.当应用切换后,有一个应用每次启动不到30秒,总是报超时的错误,而error log中又没有任何记录: Timeout ex ...