知识点:让编程学习者们又爱又恨的指针基础,为你详解(二)

指针运算

(1)赋值运算编程

指针变量能够互相赋值,也能够赋值某个变量的地址,或者赋值一个具体的地址小程序


 

(2)指针与整数的加减运算数组

指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不一样类型的指针,单元长度不一样)。这个在数组中很是经常使用。函数

指针变量加上或减去一个整形数。和第一条相似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。学习


 

(3)关系运算spa

假设有指针变量 px、py。3d

px > py 表示 px 指向的存储地址是否大于 py 指向的地址指针

px == py 表示 px 和 py 是否指向同一个存储单元视频

px == 0 和 px != 0 表示 px 是否为空指针blog


 

指针与数组

以前咱们能够经过下标访问数组元素,学习了指针以后,咱们能够经过指针访问数组的元素。在数组中,数组名即为该数组的首地址,结合上面指针和整数的加减,咱们就能够实现指针访问数组元素。

指向数组的指针

如如下语句:


 

上面语句定义了一个数组 nums,在定义时分配了 10 个连续的int 内存空间。而一个数组的首地址即为数组名nums,或者第一个元素的首地址也是数组的首地址。那么有两种方式让指针变量 p 指向数组 nums:


 

上面两句是等价的。


 

以下几个操做,用指针操做数组:

*p = 1,此操做为赋值操做,即将指针指向的存储空间赋值为 1。此时 p 指向数组 nums 的第一个元素,则此操做将 nums 第一个元素赋值为 0,即 nums[0] = 1。

p + 1,此操做为指针加整数操做,即向前移动一个单元。此时 p + 1 指向 nums[0]的下一个元素,即 nums[1]。经过p + 整数能够移动到想要操做的元素(此整数能够为负数)。

如上面,p(p + 0)指向 nums[0]、p + 1 指向 nums[1]、、、类推可得,p+i 指向 nums[i],由此能够准确操做指定位置的元素。

在 p + 整数的操做要考虑边界的问题,如一个数组长度为 2,p+3 的意义对于数组操做来讲没有意义。

下面写一段代码,用指针访问数组的元素:


 

注:数组名不等价于指针变量,指针变量能够进行 p++和&操做,而这些操做对于数组名是非法的。数组名在编译时是肯定的,在程序运行期间算一个常量。

 

字符指针与字符数组

在 C 语言中自己没有提供字符串数据类型,可是能够经过字符数组和字符指针的方式存储字符串。

(1)字符数组方式

这个在前面应该学习过,这里就不赘述了。


 

(2)字符指针方式

指针方式操做字符串和数组操做字符串相似,能够把定义的指针看作是字符数组的数组名。在内存中存储大体以下,这里为了方便换了个字符串:


 

注:字符指针方式区别于字符数组方式,字符数组不能经过数组名自增操做,可是字符指针是指针,能够自增操做。自增自减小会实现什么效果你们能够本身尝试运行一下

下面作个小练习,利用字符指针将字符数组 sentence 中的内容复制到字符数组 word 中:


 

注:指针变量必须初始化一个有效值才能使用

多级指针及指针数组

(1)多级指针

指针变量做为一个变量也有本身的存储地址,而指向指针变量的存储地址就被称为指针的指针,即二级指针。依次叠加,就造成了多级指针。咱们先看看二级指针,它们关系以下:


 

其中 p 为一级指针,pp 为二级指针。二级指针定义形式以下:


 

和指针变量的定义相似,因为*是右结合的,因此*pp 至关于*(*p)。在本次定义中,二级指针的变量名为 pp,而不是**p。多级指针的定义就是定义时使用多个“*”号。下面用一个小程序给你们举例:


 

注:在初始化二级指针 ppi 时,不能直接 ppi = &&i,由于&i 获取的是一个具体的数值,而具体数字是没有指针的。

(2)指针数组

指针变量和普通变量同样,也能组成数组,指针数组的具体定义以下:


 

下面举一个简单的例子熟悉指针数组:

//定义一个数组intnums[5] = {2,3,4,5,2}, i;//定义一个指针数组int*p[5];//定义一个二级指针int**pp;//循环给指针数组赋值for(i =0; i <5; i++){ p[i] = &nums[i]; }//将指针数组的首地址赋值给 pp,数组 p 的数组名做为 p 的首地址,也做为 p 中第一个元素的地址。//数组存放的内容为普通变量,则数组名为变量的指针;数组存放的内容为指针,则数组名为指针的指针。pp = p;//利用二级指针 pp 输出数组元素for(i =0; i <5; i++){//pp == &p[0] == &&nums[0],nums[0] == *p[0] == **ppprintf("%d", **pp);//指针变量+整数的操做,即移动指针至下一个单元pp++; }

指针与多维数组

讲多维数组是个麻烦的事,由于多维数组和二维数组没有本质的区别,可是复杂度却是高了许多。这里我主要仍是用二维数组来举例,可是仍是会给你们分析多维数组和指针的关系。

(1)多维数组的地址

先用一个简单的数组来举例:

int nums[2][2] = {

{1, 2},

{2, 3}

};

咱们能够从两个维度来分析:

先是第一个维度,将数组当成一种数据类型 x,那么二维数组就能够当成一个元素为 x 的一维数组。

如上面的例子,将数组当作数据类型 x,那么 nums 就有两个元素。nums[0]和 nums[1]。 咱们取 nums[0]分析。将 nums[0]看作一个总体,做为一个名称能够用 x1 替换。则 x1[0]就是 nums[0][0],其值为 1。


 

咱们知道数组名即为数组首地址,上面的二维数组有两个维度。首先咱们把按照上面 1 来理解,那么 nums 就是一个数组,则nums 就做为这个数组的首地址。第二个维度仍是取 nums[0],咱们把 nums[0]做为一个名称,其中有两个元素。咱们能够尝试如下语句:


 

此语句的输出结果为一个指针,在实验事后,发现就是 nums[0][0]的地址。即数组第一个元素的地址。

若是再多一个维度,咱们能够把二维数组看作一种数据类型 y,而三维数组就是一个变量为 y 的一维数组。而数组的地址咱们要先肯定是在哪一个维度,再将数组某些维度当作一个总体,做为名称,此名称就是该维度的地址(这里有些绕)。

例:


 

三维数组实际存储形式以下:


 

实际存储内容的为最内层维度,且为连续的。对于 a 来讲,其个跨度为 4 个单元;对 a[0]来讲,其跨度为 2 个单元;对 a[0][0]来讲,跨度为一个单元。有上面还能够得出:


 

上面的等式只是数值上相等,性质不一样。

(2)多维数组的指针

在学习指针与数组的时候,咱们能够以下表示一个数组:


 

在前面讲指针数组时,全部指针数组元素都指向一个数字,那么咱们如今能够尝试用指针数组的每一个元素指向一个数组:


 

这里可能不能理解为何*p + 1 = &nums[0][1],而不是 nums[1]。*p 得到的是一个一维数组,而 int 数组 + 1 的跨度只有 4 个字节,也就是一个单元。前面 p 是一维数组的指针,其跨度为一个数组。因此*p + 1 = &nums[0][1],而 p + 1 = nums[1]。

指针与函数

前面学习函数学到,函数参数能够为 int、char、float 等,可是在操做时,这些参数只做为形参,全部操做都只在函数体内有效(除对指针的操做外),那么今天来学习一下指针做为函数参数。

函数参数为指针

咱们直接作一个练习,定义一个函数,用来交换两个变量的内容。


 

代码很是简单,我也就不细讲了。这里传入的参数为指针,因此调用 swap 方法后 x,y 的内容发生了交换。若是直接传入 x,y,那么交换只在 swap 中有效,在 main 中并无交换。

函数的返回值为指针

返回值为指针的函数声明以下:


 

在函数调用前要声明须要对函数声明(有点编译器不须要)


 

除了上面的操做,更实用的是返回一个指向数组的指针,这样就实现了返回值为数组。

指向函数的指针

C 语言中,函数不能嵌套定义,也不能将函数做为参数传递。可是函数有个特性,即函数名为该函数的入口地址。咱们能够定义一个指针指向该地址,将指针做为参数传递。

函数指针定义以下:


 

函数指针在进行“*”操做时,能够理解为执行该函数。函数指针不一样与数据指针,不能进行+整数操做。

下面举个例子,来使用函数指针:


 

利用函数指针调用方法具体操做以下:

 

 

若是你想更好的提高你的编程能力,以便更好从事编程类工做的话!那么你很幸运~分享(源码、项目实战视频、项目笔记,基础入门教程)

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比本身琢磨更快哦!