详解C语言中的常量指针和指针常量

概述
对于新手来说,指针在c语言里总是一个非常难以理解的概念。在这篇文章中,我们将解释常量指针,指针常量,const pointer to const(ps:楼主以为这可以翻译成指向常量的常量指针)的区别

常量指针
让我们先来理解什么是常量指针。常量指针是指指针指向的地址是常量。换句话说,一旦常量指针指向了一个变量,你不能让该常量指针指向其他变量了

常量指针的声明方法如下:

  <type of pointer> * const <name of pointer>

常量指针声明示例:

  int * const ptr;

让我们用一小段代码来说明常量指针:

  #include <stdio.h> 

  int main(void)
  {
    int var1 = 0, var2 = 0; 

    int * const ptr = &var1; 

    ptr = &var2; 

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

    return 0;
  }

在上面的例子中:

  • 我们定义了两个变量var1和var2
  • 声明一个常量指针ptr,并让其指向var1
  • 然后,我们让ptr指向var2
  • 最后,我们试图打印这个指针指向的内容

简而言之,我们定义了一个常量指针,并且试图修改常量指针指向的地址

现在,让我们来编译这个程序:

所以,一旦常量指针指向了某一地址,我们不能更改常量指针的地址(ps:但是可以修改常量指针指向的内容)

指针常量
从名字中就可以明显得出,一个指针,我们无法修改指针指向的内容,这种指针就叫做指针常量。对于这类指针,你可以修改指针指向的地址,但是不能修改指针指向的内容

指针常量的定义如下:

  const <type of pointer> * <name of pointer>

或者

  <type of pointer> const * <name of pointer>

指针常量示例如下:

  const int *ptr; 

  int const *ptr;

让我们用一小段代码来解释指针常量:

#include <stdio.h> 

  int main(void)
  {
    int var1 = 0; 

    const int *ptr = &var1; 

    *ptr = 2; 

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

    return 0;
  }

在上面代码里:

  • 我们定义了一个变量var1,并将其赋值为0
  • 我们定义了一个指针常量并让它指向变量var1
  • 我们试图修改指针常量指向的值
  • 打印指针常量指向的值

然后我们编译上面的程序:

我们可以看到*ptr是只读属性。这意味着,如果指针常量指向了一个变量,我们不能修改该指针常量指向的值

指向常量的常量指针
如果你理解了上面两种指针类型,那作为上述两种指针的混合形态,你也应该非常好理解。指向常量的常量指针,你既不能修改指针的地址,也不能修改指针指向的内容

指向常量的常量指针定义如下:

  const <type of pointer> * const <name of pointer>

示例:

  const int * const ptr;

让我们写一小段代码来理解指向常量的常量指针:

  #include <stdio.h> 

  int main(void)
  {
    int var1 = 0, var2 = 0; 

    const int * const ptr = &var1; 

    *ptr = 1; 

    ptr = &var2; 

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

    return 0;
  }

在上面代码中:

  • 我们声明了两个变量var1和var2
  • 我们声明了一个指向常量的常量指针ptr,并让ptr指向变量var1
  • 我们试图修改指针的地址和指针指向的内容

当我们编译这段代码的时候:

而C/C++中常把指针和常量混合起来使用,其最大的用途就是作为函数的形式参数,保证实参在被调函数中的不可改变的特性,那到底常量指针和指针常量有什么区别呢?

总结
好了,现在来总结一下 常量指针 和 指针常量 的区别

首先一定要明白哪种定义方式是常量指针,哪种是指针常量,这里可以记住三句话加深记忆:

* (指针)和 const(常量) 谁在前先读谁 ;*象征着地址,const象征着内容;谁在前面谁就不允许改变。

好吧,让我们来看这个例子:

int a =3;
int b = 1;
int c = 2;
int const *p1 = &b;//const 在前,定义为常量指针
int *const p2 = &c;//*在前,定义为指针常量

常量指针p1:指向的地址可以变,但内容不可以重新赋值,内容的改变只能通过修改地址指向后变换。

  • p1 = &a是正确的,但 *p1 = a是错误的。
  • 指针常量p2:指向的地址不可以重新赋值,但内容可以改变,必须初始化,地址跟随一生。
  • p2= &a是错误的,而*p2 = a 是正确的。
  • 对于常量指针p1,我们可以改变它指向的地址,但不能改变指向的内容,如果改变了,就会出错,下面是18行代码取消注释后编译器提示的错误:

下面是在Vim编辑器中的调试结果

上述代码在注释 18行 和 24行 代码后才能正确输出,下图是正确结果

输出结果可以看出,对于常量指针p1,改变其地址指向,内容也随着地址的改变而变化了。

而对于指针常量p2,初始化后地址就固定了,内容可以随时重新赋值。

对于常量指针p1,我们可以改变它指向的地址,但不能改变指向的内容,如果改变了,就会出错,下面是18行代码取消注释后编译器提示的错误:

输出结果可以看出,对于常量指针p1,改变其地址指向,内容也随着地址的改变而变化了。

而对于指针常量p2,初始化后地址就固定了,内容可以随时重新赋值。

对于常量指针p1,我们可以改变它指向的地址,但不能改变指向的内容,如果改变了,就会出错,下面是18行代码取消注释后编译器提示的错误:


经过上面的介绍,我想大家应该知道常量指针和指针常量的区别了。

时间: 2015-08-08

C语言中常量指针与指针常量区别浅析

常量指针是指--指向常量的指针,顾名思义,就是指针指向的是常量,即,它不能指向变量,它指向的内容不能被改变,不能通过指针来修改它指向的内容,但是指针自身不是常量,它自身的值可以改变,从而指向另一个常量.指针常量是指--指针本身是常量.它指向的地址是不可改变的,但地址里的内容可以通过指针改变.它指向的地址将伴其一生,直到生命周期结束.有一点需要注意的是,指针常量在定义时必须同时赋初值.注:也有人将这两个名称的定义与含义反过来认为:"指针常量:顾名思义它的中心词是"常量"这是重点

C语言 变量详解及示例代码

C 变量 变量其实只不过是程序可操作的存储区的名称.C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上. 变量的名称可以由字母.数字和下划线字符组成.它必须以字母或下划线开头.大写字母和小写字母是不同的,因为 C 是大小写敏感的.基于前一章讲解的基本类型,有以下几种基本的变量类型: 类型 描述 char 通常是一个八位字节(一个字节).这是一个整数类型. int 对机器而言,整数的最自然的大小. float 单精度浮点值. doub

C语言中判断int,long型等变量是否赋值的方法详解

当然,如果你不赋值给局部变量,这样会导致整个程序的崩溃,因为,它的内容被系统指向了垃圾内存.下面我们看一段代码: 复制代码 代码如下: #include <stdio.h>#include <string.h>#include <stdlib.h>int globle_value;int my_sum(int value1, int value2);long my_sub(long value1, long value2);int main(void){ int aut

详解C语言中的符号常量、变量与算术表达式

C语言中的符号常量 在结束讨论温度转换程序前,我们再来看一下符号常量.在程序中使用 300.20 等类似的"幻数"并不是一个好习惯,它们几乎无法向以后阅读该程序的人提供什么信息,而且使程序的修改变得更加困难.处理这种幻数的一种方法是赋予它们有意义的名字.#define 指令可以把符号名(或称为符号常量)定义为一个特定的字符串: #define 名字 替换文本 在该定义之后,程序中出现的所有在 #define 中定义的名字(既没有用引号引起来,也不是其它名字的一部分)都将用相应的替换文本

C语言 常量,变量及数据详细介绍

一.数据 图片文字等都是数据,在计算机中以0和1存储. (一)分类 数据分为静态数据和动态数据. ①. 静态数据:一些永久性的的数据,一般存储在硬盘中,只要硬盘没坏数据都是存在的.一般以文件的形式存储在硬盘上,电脑关机重启后依然存在. ②. 动态数据:程序运行过程中,动态产生的的临时数据,一般存储在内存中,内存的存储空间一般较小,计算机关闭后这些数据就会被清除.软件或者电脑关闭则这些临时数据会被清除. ③. 静态数据和动态数据可以转换. ④. 注意:为什么不把动态数据存放到硬盘?因为直接访问内存

c语言全局变量和局部变量问题及解决汇总

1.局部变量能否和全局变量重名? 答:能,局部会屏蔽全局.要用全局变量,需要使用"::" 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量.对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内. 2.如何引用一个已经定义过的全局变量? 答:extern 可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全

解析C语言中空指针、空指针常量、NULL &amp; 0的详解

什么是空指针常量(null pointer constant)?[6.3.2.3-3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 这里告诉我们:0.0L.'\0'.3 - 3.0 * 17 (它们都是"integer constant expression")以及 (void*

Redis源码解析:集群手动故障转移、从节点迁移详解

一:手动故障转移 Redis集群支持手动故障转移.也就是向从节点发送"CLUSTER  FAILOVER"命令,使其在主节点未下线的情况下,发起故障转移流程,升级为新的主节点,而原来的主节点降级为从节点. 为了不丢失数据,向从节点发送"CLUSTER  FAILOVER"命令后,流程如下: a:从节点收到命令后,向主节点发送CLUSTERMSG_TYPE_MFSTART包:          b:主节点收到该包后,会将其所有客户端置于阻塞状态,也就是在10s的时间内

php的常量和变量实例详解

php的常量和变量实例详解 [PHP在命令行下接收参数] 如果在命令行调试php,传入的参数通过$argv获取,注意其中包含了文件名这一个元素,数组中元素的个数通过$argc获取. [可变变量] 指的是变量的名称可变,变量的标识符可以由另一个变量的值来代替. 例如:第二个语句是为argv1这个变量赋值. <?php $varName = 'argv1'; $$varName = 'value1'; var_dump($argv1); ?> [常量] 使用define定义,不可删除和修改,调用时

C语言实现进制转换函数的实例详解

C语言实现进制转换函数的实例详解 前言: 写一个二进制,八进制,十六进制转换为十进制的函数 要求: 函数有两个参数,参数(1)是要转换为十进制的进制数,参数(2)是标示参数(1)是什么进制(2,8,16标示二进制,八进制,十六进制). 要有报错信息,比如参数是1012,但参数(2)是2,显然是进制数表示有错误. 系统表 pg_proc 存储关于函数的信息 内部函数在编译之前需要先定义在 pg_proc.h 中,src/include/catalog/pg_proc.h CATALOG(pg_pr

在javascript中,null>=0 为真,null==0却为假,null的值详解

在javascript中,null>=0 为真,null==0却为假,null的值详解 1.前言 今天看见朋友们在讨论一个问题,说 null 到底和 0 是不是相等的. 听到这里,自己赶紧去写个 Demo 试一下. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>MR_LP:3206064928</tit

Kotlin null的处理详解

Kotlin null的处理详解 NullPointerException,俗称NPE,不管菜鸟还是老鸟们,都是不可避免,经常遇到的一个异常,解释起来很简单,就"空指针"三个字.总是在一次不小心,而掉进这个陷阱里.Kotlin 的设计目标就是希望消除代码中 null 引用带来的危险, 也就是所谓的造成十亿美元损失的大错误. NPE的原因 尽管Kotlin希望消除代码中的NPE,我们总是不小心,总会不小心又掉进NPE的陷阱,下面是可能NPE的原因: 明确调用 throw NullPoin

oracle sql语言模糊查询--通配符like的使用教程详解

oracle在Where子句中,可以对datetime.char.varchar字段类型的列用Like子句配合通配符选取那些"很像..."的数据记录,以下是可使用的通配符: %   零或者多个字符 _    单一任何字符(下划线) \     特殊字符 oracle10g以上支持正则表达式的函数主要有下面四个: 1,REGEXP_LIKE :与LIKE的功能相似 2,REGEXP_INSTR :与INSTR的功能相似 3,REGEXP_SUBSTR :与SUBSTR的功能相似 4,RE

MySQL Innodb 存储结构 和 存储Null值 用法详解

背景: 表空间:INNODB 所有数据都存在表空间当中(共享表空间),要是开启innodb_file_per_table,则每张表的数据会存到单独的一个表空间内(独享表空间). 独享表空间包括:数据,索引,插入缓存,数据字典.共享表空间包括:Undo信息(不会回收<物理空间上>),双写缓存信息,事务信息等. 段(segment):组成表空间,有区组成. 区(extent):有64个连续的页组成.每个页16K,总共1M.对于大的数据段,每次最后可申请4个区. 页(page):是INNODB 磁盘

Java语言面向对象编程思想之类与对象实例详解

在初学者学Java的时候,面向对象很难让人搞懂,那么今天小编就来为大家把这个思想来为大家用极为简单的方法理解吧. 首先我们来简单的阐述面向对象的思想. 面向对象: 官方的语言很抽象,我们把官方的解释和定义抛开.想想,自己有什么,对!!我们自己有手脚眼口鼻等一系列的器官.来把自己所具有的器官就可以看作我们的属性,自己是不是可以喜怒哀乐和嬉笑怒骂,这些是不是我们的行为,那么自己的具有的属性加自己有的行为就称为一个对象. 注意!!我们自己,一个个体是一个对象,因为,你是你,我是我,我们虽然有相同的,但

iOS 泛型中nullable、null resettable、null kindof 用法详解

iOS9新出的关键字:用来修饰属性,或者方法的参数,方法的返回值 iOS9新出关键字nonnull,nullable,null_resettable,_Null_unspecified 需要注意的一点只能修饰对象,不能修饰基本数据类型. 虽然在项目的代码编写中不会经常用到,不过在调用苹果系统方法的时候还是会经常遇到,需要做一个总结 nullable作用:表示可以为空 nullable书写规范: // 方式一: @property (nonatomic, strong, nullable) NSS