版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第15章 再论指针,通过本章的学习,需要掌握以下知识点: 指针和数组的区别; 使用指针访问数组,使用指针作为形参在函数中传递数组; 指针型数组和数组指针 使用指针访问二维数组,使用指针作为形参在函数中传递二维数组; 使用字符指针来处理字符; 字符串数组和字符指针数组使用上的区别。,15.1 指针与数组,C语言中,指针和数组存在很多相似点,是学习的难点。指针也可以用来指向数组或指向数组中的一个元素。当指针指向一个数组时,可以通过指针来访问数组中的元素。本节将讨论指针和数组组合而成的一些数据类型的概念和使用方法,以使读者能够理解指针和数组之间的区别。,15.1.1 指向数组元素的指针,指向数组元素
2、的指针是指一个指针变量,其指向的空间属于一个数组中的某一个元素。例如,有一个int型array数组,其定义如下: int array10 = 0; 其第0个元素的地址为,15.1.1 指向数组元素的指针,这样,指针变量p0便指向数组的第0个元素。由于数组的第0个元素的地址就是数组的地址。因此,该语句也等效于: int *p0 = array; 此时,指针变量p0就是一个指向数组array的指针变量。类似地,指向其他数组元素的指针可以赋值如下: int * p1 = int * pi = 02printf(“%dn”, *(array + 2);/* 输出array2的值 */ 上述语句中*(a
3、rray + 2)可以访问array数组中的第2个元素。但是,数组元素型指针与数组变量在很多方面是不同的,如下面内容所示。,15.1.3 数组元素型指针和数组变量,1值的可改变性不同 数组元素型指针的值是可变的,而数组变量的值是不能改变的。例如,数组元素型指针可以改变其指向的数组,以下行为是允许的。 int array_120 = 0; int array_220 = 0; int * p = array_1; p = array_2;/* 使指针指向另一个数组 */ p+;/* 使指针指向数组array_21 */ 但不能对数组做类似操作,以下行为是错误的。 /* 接上 */ array_1
4、+;/* 试图使array_1的内容为array11,错误用法 */ array_1 = array_2;/* 错误用法 */,15.1.3 数组元素型指针和数组变量,2占用空间不同 数组元素型指针变量占用的空间都是固定的,由系统决定,32位机一般是4字节。而数组变量的占用空间则是由程序决定的,为数组容量与所存数据类型字长的积。例如,以上例子中,系统为数组变量array_1和array_2都分配(sizeof(int)20)个字节,它们的内容就是所有的数组元素。而系统只为指针变量p分配(sizeof(int)个字节(一般情况下,int型的字长等于系统地址的字长),其内容为p指向的内存空间的地址
5、,当其指向数组array_1时,其值为array_1的值,即数组首地址。,15.1.3 数组元素型指针和数组变量,3访问方式不同 数组元素型指针访问方式为间接访问,而数组变量为直接访问。使用数组变量时,直接以数组变量名对应的地址加上地址偏移量来找到目标空间。而使用数组元素型指针,则先要从数组元素型指针名得到其对应的地址,从该地址取得数组元素型指针的值,再从以该值为地址的内存空间上获取内容。 实际上,索引法也被编译系统转换为数组名加上地址偏移量的形式。例如,a_inti运行时等效于*(a_int + i)。这也是为什么数组的索引要从0开始编号的原因。,15.1.4 声明数组形参的三种方式,当数组
6、作为函数形参时,数组的地址可以用做函数调用的实参。通过数组地址的传递,在函数内便可以对该数组进行访问和修改。在C语言中,数组形参的声明有3种基本形式,本节将对它们进行逐一介绍,并比较各自的特点。在函数一章中已经使用过含有数组形参的函数,其声明形式如下: void print_array(int arraySIZE);/* 形式1 */,15.1.4 声明数组形参的三种方式,使用的函数调用语句一般为: #define SIZE 10 int arraySIZE = 0; print_array(array); 对于读程序的人来说,形式1中声明的array是一个可以存储SIZE个int型数据的数组
7、。而对于编译器而言,这个形参声明则意味着array是一个指针。函数声明中的SIZE实际上是毫无用处的,即使SIZE和真实的数组容量不用也是合法且执行正常的,如下所示。 void print_array(int array1000); void print_array(int array1);,15.1.4 声明数组形参的三种方式,以上两个函数声明都能正常执行函数功能。写成形式1唯一的好处是可以提高程序可读性。它还可以写成以下两种形式: void print_array(int array);/* 形式2 */ void print_array(int * array); /* 形式3 */,1
8、5.1.5 使用三种声明方式,从上面的范例中可以看到,对于编译器,这三种形式的处理方式是完全一致,都会将array作为一个指向一个int型空间的指针变量来对待。但是,如果用来传递数组,那么形式2和形式3的信息显然是不够的,没有办法获得该数组的容量,一般将形式2和形式3写为如下形式: void print_array(int array, int size);/* 形式4 */ void print_array(int * array, int size); /* 形式5 */,15.1.6 调用含数组形参的函数,调用含数组形参的函数时,数组变量和数组元素型指针变量都可以作为实参。但不论是数组变
9、量和数组元素型指针变量,它们的值都是数组的首地址。调用函数时,指针变量型数组的形参会被赋值为数组的首地址。C语言也允许传递其他数组元素的地址来实现部分数组元素的访问。,15.2 指针与二维数组,指针除了可以指向一维数组外,还可以指向二维数组。本节将讨论指针与二维数组的关系和使用。与指针相关的二维数组的表示和使用比一维数组要复杂,而且二维数组的很多特性都由一维数组衍生而来。因此在学习本节前,应当好好掌握15.1节的内容。,15.2.1 二维数组的地址,在前面关于二维数组的讨论中,已经知道C语言中的二维数组可以看做是元素为一维数组的一维数组,其在内存中是转换为一维数组的形式来存储的。例如: int
10、 a32 = 1, 2, 11, 12, 21, 22; 那么,二维数组变量a可以看作是可存储3个一维数组元素的一维数组,其中存储的一维数组可以存储2个int型数据,如下图所示(假设数组的首地址的16进制值为001E)。,15.2.1 二维数组的地址,可以看到,该32数组在数组中的存储形式上与含有6个元素的一维数组的存储形式是一样的。二维数组的首地址有很多种表示形式,如下所示。 将二维数组看作一个整体,其地址为 int * p = *a;/* 即,15.2.2 指针法访问二维数组,虽然,p也会被赋值为数组的首地址,但由于a的类型为二维数组,这是不同类型间的赋值,是有风险的。编译器会对此警告,V
11、isual Studio 2005环境下会有如下信息: warning C4047: initializing : int * differs in levels of indirection from int (*)4 注意:是将数组第0个元素的地址赋值给指针变量,而不是将数组首地址赋值给指针变量。数组第0个元素的地址值与数组首地址值相同,但是数组首地址有很多种表示形式,各种形式的数据类型不同,不可随意混用。 由于32二维数组中第m行第n列元素可以表示为如下形式。 *(*a + i * 2 + j) 使用p代替*a,可得表达式如下: *(p + i * 2 + j),15.2.2 指针法访问
12、二维数组,2. 使用一维数组型指针 与前一种方法相似,首先需要找出使用一维数组型指针变量表示所有数组元素的表达式。对于一维数组型指针,应该将其赋值为数组第0个一维数组的地址。例如: int a32 = 1, 2, 11, 12, 21, 22; int (* p)2 = a;/* 即 int (*p)32 = /* a为二维数组, 其中的p为一维数组型指针,可以存储COL_SIZE个int型数据。由于p的类型声明中已有列数的信息,因此不必再包含列数。在fun函数中,二维数组中第m行第n列元素可以使用以下方式访问: (*(p + m) + n),15.2.3 二维数组形参,3. 使用二维数组型指
13、针 还可以使用二维数组型指针作为形参来传递二维数组。例如有以下函数声明: void fun(int (*p)ROW_SIZECOL_SIZE); 其中的p为二维数组型指针,指向ROW_SIZECOL_SIZE的int型数组。由于p的声明中含有了数组的行数和列数,因此不需要再包含行数和列数的参数。此时在fun函数中,可以使用如下表达式来访问二维数组中第m行第n列元素: *(*p + m) + n 或 *(*p + m * COL_SIZE + n),15.2.3 二维数组形参,其中,*p表示二维数组中第0个一维数组的地址,*p表示二维数组第0个元素的地址。下面来分析如何得到以上两种地址的表示。例
14、如,有如下代码: 01int array32 = 021, 2, 0311, 12, 0421, 22 05; 06. 07fun(,15.3 指针与字符,字符处理是数据处理中十分常见的情况,使用指针变量来处理字符可以提供很多便利。本节先介绍字符指针的概念和使用,然后讨论如何使用字符指针作为形参的问题,还将讨论字符串数组和字符指针数组等内容,最后会介绍如何使用字符指针数组来作为形参。,15.3.1 字符指针,字符指针就是指向字符型内存空间的指针变量,一般的定义语句如下: char * p = NULL; 使用字符指针可以访问字符数组和字符串。,15.3.1 字符指针,1. 访问字符数组 只要将
15、字符指针赋值为字符数组的首地址便可以实现对字符数组的访问。例如: char str = “Hello, world!”; char *p = str; 此时,p被初始化为字符数组str的首地址,使用p可以访问数组str的每一个元素。例如,打印str数组中的第i个元素: printf(“%c”, *(p + i);/* 推荐做法 */ 或 printf(“%c”, pi);/* 不推荐做法 */,15.3.1 字符指针,2. 访问字符串 可以将字符指针赋值为字符串常量的首地址。例如: char *p = “Hello, world!”; 此时,p被初始化为字符串的首地址。可以使用类似的方式访问字
16、符串中的各个字符。例如,打印字符常量中的第i个字符: printf(“%c”, *(p + i); 可以使用以下方式输出整个字符串。 printf(“%s”, p);,15.3.1 字符指针,由于字符串常量是不可改变的,因此不能使用p来改变字符串的内容,如下操作是非法的。 for(i = 0; i sizeof(str); +i) *(p + i) = 0; 注意:C语言中的字符串常量存储在常量区,程序中所有相同的字符串使用的是相同的字符串。,15.3.2 使用字符指针,本节将讨论如何在程序中使用字符指针来进行字符串处理。 1. 字符串的比较 要求使用字符指针实现字符串的比较功能,字符串间的大
17、小比较规则与strncmp函数相同。对于该问题,可以使用两个字符指针分别赋值为两个字符串的首地址。在一个循环结果中比较它们当前指向的结果,每一次比较后都讲两个指针后移一位以指向下一个字符元素,直至找到第一个不相等的字符。,15.3.2 使用字符指针,2. 字符串的复制 要求使用字符指针将一个字符串的内容复制到另一个字符数组中。同样使用两个字符指针,将它们初始化为源字符串和目的字符串的首地址。每一次循环将目的字符指针的内容复制到源字符指针指向的空间中,并同时将字符指针后移一位。,15.3.3 字符串数组和字符指针数组,字符串数组是以字符串作为数组元素的数组,其实质上是一个二维字符数组。下面是一个
18、字符串数组的定义: 01char namesNUMLENGTH = /* 定义并初始化二维数组 */ 02“Nelson Aldrich”, 03“A. Piatt Andrew”, 04“Frank Vanderlip”, 05“Henry P.Davison”, 06“Charles D.Norton” 07,15.3.3 字符串数组和字符指针数组,数组变量names被定义为含有NUM个字符串的数组。由于每个字符串所占最大空间为LENGTH,因此要求每个字符串的最大有效长度要小于LENGTH(要考虑字符串最后的0)。与其余数组的定义类似,可以省略NUM,这样names的可容纳的字符串数由初始化列表中的字符串个数决定;但是,LENGTH不可省略。,15.3.3 字符串数组和字符指针数组,但是,一个程序中处理的数组的长度经常会不一致,有的甚至相差很大。如果把它们一起保存在一个数组中会使每一个字符串的空间都至少扩大为最长字符串所占的空间,这样做十分浪费资源。这时候,可以选择使用字符指针数组。,15.3.3 字符串数组和字符指针数组,在数组中保存字符指针,每个指针指向需要的字符常量。例如: char * p_nameNUM = NULL;/* 定义并初始化指针数组 */ p_name 0 = “Nelson Aldrich”;/* 为第一个元素赋值 */ p_name 1 = “
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年张家港市凤凰镇人民医院自主招聘编外合同制卫技人员5人备考题库及答案详解参考
- 2025年福建华南女子职业学院冬季人才招聘10人备考题库及答案详解一套
- 中班妇女节主题教育活动设计
- 2026年医疗质量管理规范题库及答案
- 2025-2026学年教学设计模板表格
- 2025-2026学年小数乘法人教版教学设计
- 2025-2026学年借教案评职称
- 2025-2026学年瓢的拼音教学设计语文
- 2025-2026学年空间关系教案
- 长沙职业技术学院《车用传感器技术》2024-2025学年第二学期期末试卷
- 2023-2024学年第一学期理论力学期终考试试卷
- 中国网络附加存储(NAS)行业市场动态分析及前景战略研判报告
- 病原生物与免疫学基础(第5版)课件 绪论
- 2024至2030年中国电厂凝汽器数据监测研究报告
- 钻探设备工具材料一览表
- 电气工作三种人培训
- 《一线表扬学》读书心得体会
- 简易游泳池采购投标方案(技术方案)
- (1000题)上海市安全员C3证理论知识考试题库及答案
- 《油气储运安全技术》课件第六章 油气集输站场安全技术与管理
- 商户消防安全责任书范本
评论
0/150
提交评论