此文为指针系列第二篇:

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语言精要总结-指针系列(二)的更多相关文章

  1. C语言精要总结-指针系列(一)

    考虑到指针内容繁多,这里将指针作为一个系列,从简入繁,一点一点深挖并掌握这C语言的精华.初步计划如下 此文为指针系列第一篇: C语言精要总结-指针系列(一) 内存与地址 我们可以把内存看做一排连续的房 ...

  2. 【C++自我精讲】基础系列二 const

    [C++自我精讲]基础系列二 const 0 前言 分三部分:const用法.const和#define比较.const作用. 1 const用法 const常量:const可以用来定义常量,不可改变 ...

  3. C语言指针系列 - 一级指针.一维数组,二级指针,二维数组,指针数组,数组指针,函数指针,指针函数

    1. 数组名 C语言中的数组名是一个特殊的存在, 从本质上来讲, 数组名是一个地址, 我们可以打印一个指针的值,和打印一个数组的值来观察出这个本质: int nArray[10] ={ 0 }; in ...

  4. 【C++自我精讲】基础系列一 指针与引用

    [C++自我精讲]基础系列一 指针与引用   一 前言   指针.引用.指针与引用区别. 二 指针   变量:代码中常常通过定义变量来申请并命名存储空间,并通过变量的名字来使用这段存储空间. //变量 ...

  5. C语言高速入门系列(二)

    C语言高速入门系列(二) -----转载请注明出处coder-pig 本节引言: 在前面一节中我们对C语言进行了初步的了解,学会了使用IDE进行代码的编写,编译执行! 在这一节中我们会对C语言的基本的 ...

  6. 论C语言中二级指针和二维数组之间的区别

    刚开始学习C语言的时候,觉得一个数组可以定义一个一级指针去访问,想当然的就觉得可以定义一个二级指针去访问二维数组.很显然这是错误的. 我们来看看C语言的数组在内存中的存储方式. 实际上C语言中的数组, ...

  7. C++学习(二十三)(C语言部分)之 指针4

    指针 指针 存放地址 只能存放地址 使用 &取地址运算符 *取值 解引用运算符 malloc 申请堆内存 free释放堆内存 1.1 指针 存放的地址(变量地址 常量区的地址 堆区内存首地址 ...

  8. c语言中数组,指针数组,数组指针,二维数组指针

    1.数组和指针 ] = {,,,,};// 定义数组 // 1. 指针和数组的关系 int * pa = array; pa = array; // p[0] == *(p+0) == array[0 ...

  9. Redis系列(二):Redis的数据类型及命令操作

    原文链接(转载请注明出处):Redis系列(二):Redis的数据类型及命令操作 Redis 中常用命令 Redis 官方的文档是英文版的,当然网上也有大量的中文翻译版,例如:Redis 命令参考.这 ...

随机推荐

  1. Linux安装yum以及更新yum版本

    .使用RedHat系统不能正常使用yum安装 由于RedHat没有注册,所有不能使用它自身的资源更新,于是使用yum instatll gcc-c++的时候出现This system is not r ...

  2. 一步步学习EF Core(1.DBFirst)

    前言 很久没写博客了,因为真的很忙,终于空下来,打算学习一下EF Core顺便写个系列, 今天我们就来看看第一篇DBFirst. 本文环境:VS2017  Win7  .NET Core1.1     ...

  3. nginx 日志分割(简单、全面)

    Nginx 日志分割 因业务需要做了简单的Nginx 日志分割, 第1章 详细配置如下. #建议在mkdir  /home/shell  -p 专门写shell 脚本位置 root@localhost ...

  4. Oracle 12C 新特性之 PDB热克隆(本地克隆、远端异机克隆)

    说明:版本12.2.0.1 12c r1版本中 clone 一份PDB源库需要打开在read only只读模式 , 在12c r2版本中引入了local undo mode, 源PDB在read/wr ...

  5. cocoapods安装和使用常见问题及解决方案

    cocopods安装后pod install出现以下错误 /usr/local/Cellar/ruby/2.4.1_1/lib/ruby/2.4.0/rubygems.rb:270:in find_s ...

  6. Good Vegetable 4级算法题 分值: [320/3120] 问题: [8/78]

    1523 非回文 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 一个字符串是非回文的,当且仅当,他只由前p个小写字母 ...

  7. Opencv在linux下安装

    Opencv in Linux These steps have been tested for Ubuntu 10.04 but should work with other distros as ...

  8. zabbix agent安装详解

    安装 Installing repository configuration package Zabbix 2.2 for RHEL5, Oracle Linux 5, CentOS 5: rpm - ...

  9. 01-.Net编程机制

    .NetFarmwark特点: 多平台:该系统可以在广泛的计算机上运行,包括从服务器.桌面机到PDA和移动电话. 行业标准:该系统使用行业标准的通信协议,比如XML.HTTP.SOAP和WSDL. 安 ...

  10. javascript基础-性能优化

    优化点 性能检测 基调网络 http://www.cesule.com/cesule/status/show/3496d91653a14743af2bd2e261aee204 阿里测 http://a ...