天天看点

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

@toc

前言

在c语言基础阶段,我们学习过指针相关的一些基础内容,比如说:

1.指针是一个变量,用来存放地址,地址是唯一标识一块内存空间 2.指针的大小是固定的4 / 8个字节(32位平台 / 64位平台) 3.指针是由类型,指针的类型决定了指针的 + -整数的步长,指针解引用操作时候的权限 4.指针的运算

本篇文章及后面的几篇文章将会更加详细的去介绍和学习指针的进阶部分。(指针的内容在数据结构中会经常用到,所以一定要好好学习,打好基础~)

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

接下来,我们继续探讨指针的高级使用

在指针的类型中我们知道有一种指针类型为字符指针 <code>char*</code>

一般使用方式:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

还有使用方式如下:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

注意观察区别:%c 与 %s :

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
<code>这种方式是将字符串的首地址放到指针中,通过指针可以找到该字符串(千万不要理解成将字符串放到指针里面去,这是不可能的)</code>。(类似与数组名就是首元素地址,但是跟数组还是有所区别的,这个字符串是一个常量字符串,无法被改变,如下图:)
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

<code>常量字符串不能改变</code>

如果说我们想修改这个字符串,需要将其放入数组中,然后再去修改:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

扩展:在c语言中,内存可以被划分为栈区、堆区、静态区、常量区。

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
栈区:局部变量,函数形参,函数调用 堆区:动态内存如malloc等申请使用 静态区:全局变量,static修饰的局部变量 常量区:常量字符串 常量区中的内容在整个程序的执行期间是不允许被修改的,且同一份常量字符串只会创建一份,不会重复创建存储。

看一面试题,输出什么?

结果展示:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

<code>const修饰常量</code>

分析:

<code>创建数组需要开辟空间,数组arr1和arr2在内存空间所在位置是不同的,所以arr1 != arr2;</code>

char p1 = “abcdef”; char p2 = “abcdef”; "abcdef"是常量字符串,不能被修改,在内存空间所占位置固定,char p1 = “abcdef”; 是将该常量字符串的首地址放到字符指针p1中,char p2 = “abcdef”;

是将该常量字符串的首地址放到字符指针p2中。

<code>也就是说p1和p2存放都是常量字符串"abcdef"的首地址,所以p1 ==p2</code>。(注意:同样的常量字符串只会存一份,不会同时存两份,所以不会开辟不同的空间来存储。)

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
总结: 这里arr1和arr2指向的是一个同一个常量字符串。 c /c++会把常量字符串存储到单独的一个内存区域当几个指针。指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。 所以arr1和arr2不同,p1和p2相同。

通过前面的学习,我们可以知道形如int arr1[5] = {0};的是整形数组,数组存放的是整形,形如char arr2[10] = {0};的是字符数组,数组存放的是字符。

同理,指针数组应该是数组,数组存放的是指针。

指针数组的简单使用

看以下代码,猜猜结果是什么?

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
我们知道数组名可以代表首元素的地址,请看下面这段代码:
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

上面举例都是用整型指针数组,接下来我们来看一个字符指针数组的例子:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

这里我们再复习一下,下面指针数组是什么意思 ?

数组指针是指针还是数组 ?

答案是∶指针

我们已经熟悉︰ 整形指针 : int p ; 能够指向整形数据的指针。 浮点型指针 : float pf ; 能够指向浮点型数据的指针。 那数组指针应该是︰能够指向数组的指针。 数组指针和指针数组要区分开来。

整型指针 ---&gt; 指向整型的指针

字符指针 ---&gt; 指向字符的指针

数组指针---&gt; 指向数组的指针-----&gt;eg : int (*p)[10]=nall ;

首先,我们要知道[]的优先级是比 要高的,对于形式1,p1会先与[ ]结合,在与 结合,所以形式1是指针数组,()的优先级又比[]高,所以p2会先于 * 结合,在与[ ]结合,所以形式2是数组指针。

到这里,相信你对数组指针有了一定了解,哪么<code>怎么建立数组指针呢</code>?

<code>✳</code>例如:给定char arr[5],请写出用来表达char arr[5]的数组指针

先分析char arr[5],很明显,这是一个指针数组,数组名是arr,有五个元素,数组的类型是char,我们已知数组指针 - 指向数组的指针 - 存放数组的地址,所以应该对数组取地址,即&amp;arr,如何应该定义一个有五个元素的指针存放数组的地址,即(p)[5],指针类型为char,所以数组指针是char (p)[5] = &amp;arr
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

<code>不成熟的说指针的指针相当于二级指针,肯定有两个 “ * ”</code>

所以我们现在会写数组指针了。

来试一试!

例如:

[x] 写出char* arr[10]的数组指针

char( pa)[10] = &amp;arr

[x] 写出int* par[2]的数组指针

int( pa)[2] = &amp;par
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

我们看到打印的结果都是一样的,那么数组名arr和数组的地址 &amp; arr是一样的吗?

从地址值来看,两者是一样的,但是两者的含义和使用是不同的:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
int p1; p1+1 表示跳过一个int类型的长度,也就是4个字节 char p2; p2+1表示跳过一个char类型的长度,也就是1个字节 int(p3)[10]; p3+1表示跳过一个具有10个整型长度的数组,也就是410=40个字节
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

我们先看这个例子:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
通过数组指针解引用找到数组,再用方括号[ ],去找到数组中的每个元素。 这种并非数组指针的常用方式,因为用起来很“别扭”。 这种方式不如首元素地址 + i 流畅:
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

数组指针的使用,一般常见于二维数组及其以上

当我们在谈首元素的时候,一维数组的首元素就是第一个元素,二维数组的首元素要先将二维数组看作一维数组(该数组中每一个元素都是一个一维数组),那二维数组的首元素就是第一个一维数组。那么二维数组的首元素地址就是第一个一维数组的地址!(不是第一个一维数组中第一个元素的地址,虽然值相同,但含义和使用不同)

结果展示:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

图解:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

注意:对一个存放数组地址的指针进行解引用操作,找到的是这个数组,也就是这个数组的数组名,数组名这时候又表示数组首元素地址!

<code>*( p + i ):相当于拿到了一行&lt;br/&gt;相当于这一行的数组名&lt;br/&gt;( *p + i )[ j ] &amp;lt;===&amp;gt; *(*(p + i ) + j )</code>

</blockquote>

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

为了更好的理解这一点,我们来看这个例子:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

恍然大悟

总结:我们对一个数组指针变量进行解引用操作,比如int(*p)[10],得到的是一个数组,或者说是这个数组的数组名,而数组名又可以表示该数组首元素的地址。如果要找到该数组中的每一个元素,就需要对这个数组元素的地址进行解引用操作。 简单点来说就是,对一个数组指针类型进行解引用操作,得到的还是地址,对这个地址在进行相应的解引用操作,才能得到数组中的具体的元素。
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

下面这些代码的含义是什么?

解析:

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
int( parr3 [10])[ 5 ]; 拿掉数组名后,剩下 int()[5]就是这个数组的类型
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

问题1:parr2 = &amp;parr1;//能否将数组parr1的地址放到parr2中呢?

答:不能,因为类型不匹配,parr2指向的类型应该是 int[10] parr1 是 int* [10];

答案:以上五种传参方式均ok 注意:一维数组传参可以传数组形式,也可以传指针形式,传数组形式的时候数组元素的个数可以不写,也可以写,传指针的时候要注意指针的类型,也就是指针指向什么类型的元素, <code>比如说指针指向int类型元素,那么指针的类型就是 int*</code>
总结 : 二维数组传参,函数形参的设计只能省略第一个[ ]的数字。 因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。 这样才方便运算。 二维数组传参也能写成指针的形式,指针的类型应该是数组指针。
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

思考1:这里的指针传参可以用数组去接收吗?

【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数
经过实验我们可以看到这样做是没问题的,指针传参可以用数组去接收!

思考2:当一个函数的参数部分为一级指针的时候,函数能接收什么参数 ?

例如:int * p

再例如:char* p

注意: int p1; int p2; *靠近int 或者靠近变量p实际的意义和效果没区别,是一样的。 一般我们习惯用int p2这种写法,这样可以明确表示指针变量p2的类型。**
【C语言进阶】——指针(一) (字符指针,数组指针,指针数组) !!1、字符指针2、指针数组3、数组指针4、数组参数、指针参数

继续阅读