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 命令参考.这 ...
随机推荐
- 每天一道Java题[2]
问题 可以直接根据hashCode()方法产生的值判断两个对象是否相等吗? 解答 不能!根据Wikipedia(https://en.wikipedia.org/wiki/Java_hashCode( ...
- Unable open dabase as spfile parameter incorrect
Error desc: ORA-00821: Specified value of sga_target 16M is too small, needs to be at least 4832M ...
- UITextView 实现链接点击事件
UILabel通过富文本可以实现图文混排,但是想要实现文字的点击效果好像不容易实现,这里有2种方法可以达到效果 YYLabel -->YYText框架 参考我之前的博客:http://www.c ...
- UIWebView 跳过HTTPS证书认证
UIWebView跳过证书认证 在UIWebView中加入如下代码即可(Error Domain=NSURLErrorDomain Code=-1202) //跳过证书验证 @interface NS ...
- 开涛spring3(6.9) - 对JDBC的支持 之 7.1 概述
7.1 概述 7.1.1 JDBC回顾 传统应用程序开发中,进行JDBC编程是相当痛苦的,如下所示: //cn.javass.spring.chapter7. TraditionalJdbcTes ...
- springboot + shiro + cas4.2.7 实战
1. 下载地址 https://github.com/apereo/cas/archive/v4.2.7.zip 2. 解压后, 用intellj idea 打开 3. 执行 gradle build ...
- springboot 获取hibernate 的 SessionFactory
注入bean package cn.xiaojf; import cn.xiaojf.today.data.rdb.repository.RdbCommonRepositoryImpl; import ...
- HTMLTestRunner测试报告美化
前言 最近小伙伴们在学玩python,,看着那HTMLTestRunner生成的测试报告,左右看不顺眼,终觉得太丑.搜索了一圈没有找到合适的美化报告,于是忍不住自已动手进行了修改,因习惯python ...
- 写给Android App开发人员看的Android底层知识(8)
(十)PMS及App安装过程 PMS,全称PackageManagerService,是用来获取Apk包的信息的. 在前面分析四大组件与AMS通信的时候,我们介绍过,AMS总是会使用PMS加载包的信息 ...
- 在.Net下使用redis基于StackExchange.Redis
研究了下redis在.net下的使用,因为以前在java上用redis用的是jedis操作,在.net不是很熟悉,在网站上也看了一部分的.net下redis的使用,大部分都是ServiceStack. ...