C语言精要总结-指针系列(二)

此文为指针系列第二篇:
C语言精要总结-指针系列(二)
指针运算
前面提到过指针的解引用运算,除此之外,指针还能进行部分算数运算、关系运算
指针能进行的有意义的算术运算包括加减法运算,但不包括乘除运算。并且运算存在诸多限制。
加法运算
指针加法运算只适合指针与整数,不能用在指针与指针。
指针加上或者减去一个整数n,是存储的地址值加上或者减去n*指针指向类型的空间大小。也就是
结果指针 = 指针 ± n * 指针指向类型空间大小。
例如int类型的整数指针+1,运算结果依然是一个整型指针,其存储的地址值为原指针值+1*4,这是因为整型变量占用4个字节的空间。这个计算结果,恰好在当前指针指向基础上,向下偏移指向下一个相同类型的空间。如下图

指针与整数的加减法一般用在迭代连续的内存空间-数组,如果运算得到的指针指向第一个元素之前或者最后一个元素之后,可能会产生非法读写内存中断,就像引用一个未初始化的指针一样不可预知。
指针除了可以与整数做加减运算,连个指针之间还可以做减法运算(不能做加法运算)且必须是同类型的指针。运算结果为两个指针指向地址之间,可以存放多少此类型的变量数(或其相反数),类型为ptrdiif_t类型(一种有符号整数类型)。
int * p1 = (int *) 0x100;
int * p2 = (int *) 0x10c;
printf("p2-p1 : %d\n",p1 - p2); // -3
如上程序将输出-3,也如上图所示,这3个空间存放着 10、80、6三个整型变量。
指针与指针相减,一般也用在连续地址空间-数组中。此时两个指针相减跟下标索引相减是等价的。
int arr[] ;
printf("%d\n",&arr[] - &arr[] == - ); //
常量指针与指针常量
常量指针表示通过此指针,不能修改其指向的内存区域的内容,指针本身的值是可以修改为指向另一个变量,虽然可以修改指向另一个变量,但是依然不允许修改指向变量里的内容。常量指针一般用在函数一些函数参数中,以只读的方式传递函数参数。这里说明一点C语言除了宏定义常量和枚举之外,是不能定义普通常量的,只可用const定义只读变量,而常量指针指向的是就是一个只读变量。只读变量是不能修改的变量。
const int readOnlyVar = ;
int * pROVar = (int *) & readOnlyVar;
* pROVar = ;
printf("%d\n",readOnlyVar);
而指针常量表示指针本身的内容不可变(指向不可变),因此,定义指针常量时必须同时初始化一个地址值。
定义指针常量和定义常量指针的方式区别在于const关键字的位置
int const * p1 ;
const int * p2 ;
int * const p3 = NULL;
const int * const p4 = NULL;
以*号为界限,看cosnt修饰的是谁,如果修饰的是类型关键字,表示指向常量类型——常量指针,如果修饰的是指针标识符,表示指针常量。显然p1、p2是常量指针,p3是指针常量,p4既是常量指针,又是指针常量。
指针数组
指针数组指元素由指针组成的数组,一般用在存储字符串组,例如下面的程序
 char * options[] = {
     "--list",
     "--prefix",
     "--with"
 };
 for (i =  ; i <  ;i ++)
 {
     if (NULL != options[i]){
         printf("%s\n",options[i]);
     }
 }
此时指针数组前三个成员指向静态区的三个字符串常量,而后两个指针被默认初始化为0(NULL)

C语言中出现的字符串字面量,实际是存储在静态数据区的字符串常量。当一个字符串出现在C语言表达式中,其实际值是一个指针常量。如下面声明一个指针常量的代码
char * str = "hello";
可以用另一段代码来描述,即先在某处为字符串分配空间,记录指向第一个字符的一个指针常量,并将字符拷贝进去。代码如下
char * const strBuff = (char * ) malloc ();
strcpy(strBuff,"hello");
char * str = strBuff;
free(strBuff);
既然明确字符串常量在代码中实际是一个指针常量,因此其也可以参与运算。代码如下
printf("%c\n",* "hello");   //  h
printf("%s\n", "hello" + );//  ello
常量指针“hello”+1后得到一个新的指针,按指针运算的规则将指向下一个e,所以以字符串形式输出ello
除此之外指针输在还用在处理许多多维数组的地方,这在后续的章节中会提到。
常量指针数组与指针常量数组
常量指针数组表示元素都指向常量的数组。定义方式如下
 const char * options[] = {
     "--list",
     "--prefix",
     "--with"
 };
当然,这里的例子,const加与不加没太大区别,因为即便不加const关键字,options中的每一个元素依然是指向一个字符串常量,是不能修改的。例如要将“--list”中的第2个‘-’换成'+'号,下面的代码是行不通的,方法只有让指针指向一个全新的字符串常量(因为是常量指针,所以指针本身的内容可以修改)
* (options[] + ) = '+';
加上const的好处是,让编译器或者IDE工具在运行之前便告知你此类代码存在的问题。关于字符串常量,下面的异常代码可能更易懂一些
char * str = "hello";
*(str + ) = 'w';
指针常量数组表示每个指针元素都是不可修改的(指向固定了),但是其指向内容,视情况是可以修改的。
 char * const options[] = {
     "--list",
     "--prefix",
     "--with"
 };
当然,因为字符串常量的缘故,上面的代码定义了一个指针元素、指针元素指向区域内都不可变的指针数组。例如,像下面的代码都是非法的
options[] = tmpStr; // 修改指针指向新的字符串常量
*(options[]) = '+'; // 修改第一个元素指向区域的内容
下一系列将用一两个复杂的案例详细讲解指针与数组的关系。
C语言精要总结-指针系列(二)的更多相关文章
- C语言精要总结-指针系列(一)
		
考虑到指针内容繁多,这里将指针作为一个系列,从简入繁,一点一点深挖并掌握这C语言的精华.初步计划如下 此文为指针系列第一篇: C语言精要总结-指针系列(一) 内存与地址 我们可以把内存看做一排连续的房 ...
 - 【C++自我精讲】基础系列二 const
		
[C++自我精讲]基础系列二 const 0 前言 分三部分:const用法.const和#define比较.const作用. 1 const用法 const常量:const可以用来定义常量,不可改变 ...
 - C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数
		
1. 数组名 C语言中的数组名是一个特殊的存在, 从本质上来讲, 数组名是一个地址, 我们可以打印一个指针的值,和打印一个数组的值来观察出这个本质: int nArray[10] ={ 0 }; in ...
 - 【C++自我精讲】基础系列一 指针与引用
		
[C++自我精讲]基础系列一 指针与引用 一 前言 指针.引用.指针与引用区别. 二 指针 变量:代码中常常通过定义变量来申请并命名存储空间,并通过变量的名字来使用这段存储空间. //变量 ...
 - C语言高速入门系列(二)
		
C语言高速入门系列(二) -----转载请注明出处coder-pig 本节引言: 在前面一节中我们对C语言进行了初步的了解,学会了使用IDE进行代码的编写,编译执行! 在这一节中我们会对C语言的基本的 ...
 - 论C语言中二级指针和二维数组之间的区别
		
刚开始学习C语言的时候,觉得一个数组可以定义一个一级指针去访问,想当然的就觉得可以定义一个二级指针去访问二维数组.很显然这是错误的. 我们来看看C语言的数组在内存中的存储方式. 实际上C语言中的数组, ...
 - C++学习(二十三)(C语言部分)之 指针4
		
指针 指针 存放地址 只能存放地址 使用 &取地址运算符 *取值 解引用运算符 malloc 申请堆内存 free释放堆内存 1.1 指针 存放的地址(变量地址 常量区的地址 堆区内存首地址 ...
 - c语言中数组,指针数组,数组指针,二维数组指针
		
1.数组和指针 ] = {,,,,};// 定义数组 // 1. 指针和数组的关系 int * pa = array; pa = array; // p[0] == *(p+0) == array[0 ...
 - Redis系列(二):Redis的数据类型及命令操作
		
原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...
 
随机推荐
- VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启)
			
VopSdk一个高逼格微信公众号开发SDK(源码下载) VopSdk一个高逼格微信公众号开发SDK:自动化生产(装逼模式开启) 针对第一版,我们搞了第二版本,老规矩先定个目标. 一 我们的目标 a.移 ...
 - C++ 常见的 Undefined symbols for architecture *
			
出现 Undefined symbols for architecture x86_64: 的原因 1.函数申明了,却未被定义. 2.申明的虚函数未被实现. NOTE: a missing vtabl ...
 - 2017年中国大学生程序设计竞赛-中南地区赛暨第八届湘潭市大学生计算机程序设计大赛题解&源码(A.高斯消元,D,模拟,E,前缀和,F,LCS,H,Prim算法,I,胡搞,J,树状数组)
			
A------------------------------------------------------------------------------------ 题目链接:http://20 ...
 - js图片大小限制,设置
			
//图片大小自动脚本 function AutoResizeImage(maxWidth, maxHeight, objImg) { var img = new Image(); img.src = ...
 - php原生curl接口的请求
			
/** * @desc 接口请求处理 * @date 2017/5/19 11:39 * @param [$url请求的接口地址,$way为false为get请求,true为post请求] * @au ...
 - React,关于redux的一点小见解
			
最近项目做多页面应用使用到了,react + webpack + redux + antd去构建多页面的应用,本地开发用express去模拟服务端程序(个人觉得可以换成dva).所以在这里吐槽一下我自 ...
 - C#基础篇--静态成员、抽象成员、接口
			
1.静态成员: 静态成员(static).静态类与实例成员.类: 静态成员属于类所有,非静态成员属于类的实例所有. 静态成员不能标记为 Virtual,Abstract,Override,也就是说静态 ...
 - 【charger battery 充電 充電器 電池】過充保護警告訊息 over charging protection,Battery over voltage protection, warning message
			
Definition: over charging protection.battery over voltage protection, 是一種 battery 保護機制, 避免 battery 充 ...
 - 关于STM32 IAP
			
转眼间天亮了...... 然后就想起了一个朋友QQ的个性签名:年轻人总是要为一些自己认为有意义的事情而废寝忘食,通宵达旦,直至白发方休........ 对了这篇文章一定会介绍的很详细,请细嚼慢咽... ...
 - JAVA POI 应用系列(2)--读取Excel
			
添加maven依赖 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi< ...