1、C+程序设计新世纪应用型高等教育教材编审委员会 组编主编 罗烨 李秉璋第二版新世纪应用型高等教育软件专业系列规划教材第4章 数组、指针及字符串4.1 数组3数组是同类型数据的有序集合。它由若干个元素组成数组是同类型数据的有序集合。它由若干个元素组成,每个元素数据类型都相同每个元素数据类型都相同,在在内内存存中占用相同大小的存储单元。各元素具有明确的次序关系中占用相同大小的存储单元。各元素具有明确的次序关系,且在内存中连续存放。且在内存中连续存放。数组中的每一个元素都用数组名与若干个带方括号的下标表示。下标的个数表示数组中的每一个元素都用数组名与若干个带方括号的下标表示。下标的个数表示数数组的组
2、的维数维数,数组可以是一维的数组可以是一维的,也可以是多维的。数组的维数和每一维的元素个数必须在也可以是多维的。数组的维数和每一维的元素个数必须在定定义数组义数组时确定时确定,在程序运行时不能改变。在程序运行时不能改变。4.1 数组44.1.1 一维数组1.一一维数组的定义和存储方式维数组的定义和存储方式数组在使用前也必须先定义。语法格式为数组在使用前也必须先定义。语法格式为:其中其中:(1)数组元素的类型可以是数组元素的类型可以是void以外以外的任何类型。的任何类型。(2)数组名是用户自定义的标识符。在数组名是用户自定义的标识符。在C+中数组中数组名表示数组首元素在内存中的地址名表示数组首
3、元素在内存中的地址,它它是一个地址常量是一个地址常量,因此数组名不能修改因此数组名不能修改,不能作为左值出现。不能作为左值出现。(3)常量表达式的值必须常量表达式的值必须是是unsignedint类型类型的正整数或常变量的正整数或常变量,不能是变量。该值不能是变量。该值表示表示数组的大小数组的大小,亦称数组的长度亦称数组的长度,表示数组元素的个数。表示数组元素的个数。(4)是数组下标运算符是数组下标运算符,但是在数组定义时用来规定数组的长度。但是在数组定义时用来规定数组的长度。4.1 数组54.1.1 一维数组2.一一维数组的维数组的初始化初始化与定义普通变量时可以同时初始化一样与定义普通变量
4、时可以同时初始化一样,定义一个数组时也可进行初始化。例如定义一个数组时也可进行初始化。例如:intf10=0,1,1,2,3,5,8,13,21,34;以上以上f数组数组已对全部数组元素初始化已对全部数组元素初始化,也可以省略数组的长度也可以省略数组的长度,即即:intf=0,l,1,2,3,5,8,13,21,34;编译器会根据初始化值的个数自动确定数组的长度。编译器会根据初始化值的个数自动确定数组的长度。4.1 数组64.1.1 一维数组3.一一维数组元素的引用维数组元素的引用对数组元素的访问方法是通过下标运算符对数组元素的访问方法是通过下标运算符,按元素在数组中的位置进行访问按元素在数组
5、中的位置进行访问,称为称为索引索引访问访问或下标访问或下标访问,格式如下格式如下:4.1 数组74.1.2 二维数组及多维数组数组不仅有一维数组数组不仅有一维数组,还有二维、三维甚至多维数组。一维数组可用来表示向量还有二维、三维甚至多维数组。一维数组可用来表示向量,二二维维数数组可用来表示行列式或矩阵组可用来表示行列式或矩阵,例如可以用一个二维数组来存储方程组的系数矩阵。而例如可以用一个二维数组来存储方程组的系数矩阵。而像像玩具玩具魔方这样的立方体结构就需要用三维数组来表示魔方这样的立方体结构就需要用三维数组来表示。1.二二维及多维数组定义和存储方式维及多维数组定义和存储方式二维及多维数组定义
6、的语法格式为二维及多维数组定义的语法格式为:常量常量表达式表达式1为数组为数组第一维的长度第一维的长度(最高维最高维),常量表达式常量表达式2为为数组第二维的长度数组第二维的长度,常量常量表达式表达式n为为数组数组第第n维的维的长度长度(最低维最低维)。4.1 数组84.1.2 二维数组及多维数组2.二二维数组的初始化维数组的初始化对于二维数组对于二维数组,其初始化有以下几种形式其初始化有以下几种形式:(1)嵌套一维数组的初始化嵌套一维数组的初始化:int a34=1,3,5,7,2,1,6,8,3,;i,7,11;(2)按数组元素存储次序列出各元素的值,并只用一个按数组元素存储次序列出各元素
7、的值,并只用一个“”括起来,如括起来,如:int a34=1,3,5,7,2,4,6,8,3,5,7,11;(3)可以对部分元素赋初值,没有明确初值的元素可以对部分元素赋初值,没有明确初值的元素为为0。如如:int a34=1,3,2,,3,5,7;(4)可由初始化数据个数确定数组的最高维长度。如可由初始化数据个数确定数组的最高维长度。如:int a 4=1,3,5,7,2,4,6,8,3,5,7,11;4.1 数组94.1.2 二维数组及多维数组3.二维及多维数组元素的引用二维及多维数组元素的引用二维及多维数组元素的引用与一维类似,其语法形式为二维及多维数组元素的引用与一维类似,其语法形式为
8、:元素下标表达式的个数取决于数组的维数,元素下标表达式的个数取决于数组的维数,N维数组就有维数组就有N个下标表达式。二维及个下标表达式。二维及多多维维数组元素下标的起止值、下标表达式值的要求与一维数组完全相同。数组元素下标的起止值、下标表达式值的要求与一维数组完全相同。4.1 数组104.1.3 数组作为函数参数数组元素和数组名都可以作为函数的参数实现函数间数组数据的传递和共享数组元素和数组名都可以作为函数的参数实现函数间数组数据的传递和共享。由于由于数组元素和普通变量没有区别,因此当数组元素作为函数的实参时,传递给形数组元素和普通变量没有区别,因此当数组元素作为函数的实参时,传递给形参参的是
9、的是数组元素的值。数组元素的值。使用使用数组名作为函数的参数,则实参和形参都应该是数组名,且类型应相同。由于数组名作为函数的参数,则实参和形参都应该是数组名,且类型应相同。由于数组名数组名表示的是数组首元素的地址,所以函数形参得到的是实参数组首元素的地址,实参表示的是数组首元素的地址,所以函数形参得到的是实参数组首元素的地址,实参和和形参地址形参地址值相同,因此被调函数中对形参数组的处理实际上就是对主调函数的实参数组值相同,因此被调函数中对形参数组的处理实际上就是对主调函数的实参数组的处理的处理。4.1 数组114.1.3 数组作为函数参数1.一一维数组作为函数参数维数组作为函数参数4.1 数
10、组124.1.3 数组作为函数参数2.多维数组作为函数多维数组作为函数参数参数多维多维数组也可以作为函数参数。多维数组作为参数,最高维长度可以不写,但其他数组也可以作为函数参数。多维数组作为参数,最高维长度可以不写,但其他各各维必须维必须明确标出。因为编译器只要根据后面每一维明确标出。因为编译器只要根据后面每一维(从第从第2维开始维开始)的大小就可计算数组的大小就可计算数组占用空间占用空间中每一个元素的存储地址。对于多维数组,编译器不检查边界,其实只是不检查中每一个元素的存储地址。对于多维数组,编译器不检查边界,其实只是不检查最高最高维维(第第1维维)的边界。的边界。4.1 数组134.1.4
11、 数组的应用 数据排序是最常见的应用,比如对学生考试成绩进行排序,对候选人得票数排序等。数据排序是最常见的应用,比如对学生考试成绩进行排序,对候选人得票数排序等。排序排序的方法有很多种,常用的的方法有很多种,常用的有:有:冒泡法选择法插入法4.2 指针144.2.1 指针的概念指针是一种数据类型,指针类型的变量称为指针变量指针是一种数据类型,指针类型的变量称为指针变量。对变量的访问也就是对变量的存取有两种方式对变量的访问也就是对变量的存取有两种方式:1.直接访问 程序中按变量名访问变量的方式是直接访问。程序编译后,变量名和变量地址之间程序中按变量名访问变量的方式是直接访问。程序编译后,变量名和
12、变量地址之间就建立就建立了对应关系。程序中访问变量,根据对应关系,寻找到该地址,获得该变量的值了对应关系。程序中访问变量,根据对应关系,寻找到该地址,获得该变量的值。2.间接访问 变量的地址也可以放在另一个变量中,则存放该变量的地址也可以放在另一个变量中,则存放该地址的地址的变量称为指针变量。访问数变量称为指针变量。访问数据变量时,先由指针变量据变量时,先由指针变量获得获得该数据变量的地址,再由数据变量地址实现对数据该数据变量的地址,再由数据变量地址实现对数据变量的变量的存存取,这称为取,这称为“间接访问间接访问”。由于指针变量的值是另一。由于指针变量的值是另一个变量个变量的地址,习惯上形象地
13、称指针的地址,习惯上形象地称指针变量指向该变量。变量指向该变量。指针变量指针变量也简称为指针。也简称为指针。4.2 指针154.2.2 指针变量的定义指针变量的定义格式如下指针变量的定义格式如下:4.2 指针164.2.3 指针变量的初始化和运算3.指针指针的的算术运算算术运算由于由于指针变量存放的都是内存地址指针变量存放的都是内存地址,所以指针的算术运算都是整数运算所以指针的算术运算都是整数运算。一一个指针变量可以加上或减去一个整数值个指针变量可以加上或减去一个整数值,包括指针的包括指针的+、-运算运算。根据。根据C+地址运算地址运算规则规则,一个指针变量加一个指针变量加(减减)一个整数并不
14、是简单地将其地址量加一个整数并不是简单地将其地址量加(减减)一个整一个整数数,而是而是根据根据其所指的数据类型的长度其所指的数据类型的长度,计算出指针最后指向的位置。例如计算出指针最后指向的位置。例如,p+n实际实际表示的地址是表示的地址是:p指向指向的内存单元的的内存单元的地址地址+n*sizeof(指针指针指向的数据类型指向的数据类型)4.2 指针174.2.3 指针变量的初始化和运算4.指针指针的关系运算的关系运算指针可以进行关系运算。当两个指向相同类型数据的指针相等时指针可以进行关系运算。当两个指向相同类型数据的指针相等时,就说明它们就说明它们指向指向同一同一个内存单元。在程序中经常对
15、指向同一个数组的两个指针进行小于、等个内存单元。在程序中经常对指向同一个数组的两个指针进行小于、等于等各种关系于等各种关系运算。运算。和指针相减情况相同和指针相减情况相同,两个指向同类型普通变量的指针进行关系运算也没有任两个指向同类型普通变量的指针进行关系运算也没有任何意义。何意义。一个指针可以一个指针可以和和NULL作相等作相等或不等的关系运算或不等的关系运算,用来判断该指针是否为空用来判断该指针是否为空。4.2 指针184.2.4 指针作为函数参数指针作为函数的形参指针作为函数的形参,在调用时实参将地址值传递给形参在调用时实参将地址值传递给形参,使形参指针指向主调函数中使形参指针指向主调函
16、数中的数据的数据。这样在被调函数中。这样在被调函数中,通过形参指针对数据的访问就是对主调函数中的数据进行访通过形参指针对数据的访问就是对主调函数中的数据进行访问。问。4.2 指针194.2.5 指针数组如果数组的每个元素都是指针变量如果数组的每个元素都是指针变量,称该数组为指针数组。定义一维指针数组的称该数组为指针数组。定义一维指针数组的语法语法格式格式为为:常量表达式同样指出数组元素的个数常量表达式同样指出数组元素的个数,数据类型确定数组中每个元素的类型数据类型确定数组中每个元素的类型,即指针即指针类类型型。4.2 指针204.2.6 指针型函数和函数指针1.指针型函数指针型函数定义指针型函
17、数的语法形式是定义指针型函数的语法形式是:数据类型数据类型 *函数函数名名(参数表参数表)函数函数体体函数名前面的函数名前面的“*”表示该函数是一个指针型函数表示该函数是一个指针型函数,数据类型表明函数返回指针数据类型表明函数返回指针的类型的类型。4.2 指针214.2.6 指针型函数和函数指针2.函数函数指针指针在程序运行时在程序运行时,不仅数据要占据内存空间不仅数据要占据内存空间,程序的代码被调入内存后也占据一定的程序的代码被调入内存后也占据一定的空间空间。每一个函数都有函数名每一个函数都有函数名,C+规定规定这个函数名就表示函数代码在内存中的起始地址。这个函数名就表示函数代码在内存中的起
18、始地址。由此看来由此看来,调用函数的形式调用函数的形式“函数名函数名(参数表参数表)”的实质就是的实质就是“函数代码首地址函数代码首地址(参数表参数表)”。指向指向函数的指针函数的指针,简称函数指针简称函数指针,是用来存放函数代码首地址的指针型变量。是用来存放函数代码首地址的指针型变量。4.2 指针224.2.6 指针型函数和函数指针函数指针名前的圆括号是必需的。圆括号改变了运算符的优先级函数指针名前的圆括号是必需的。圆括号改变了运算符的优先级,使得该标识符使得该标识符首先被首先被解释为指针解释为指针。函数指针在使用之前也要进行赋值函数指针在使用之前也要进行赋值,使指针指向一个已经存在的函数代
19、码的起始地址使指针指向一个已经存在的函数代码的起始地址。语法语法为为:使用函数指针调用函数有以下两种语法形式使用函数指针调用函数有以下两种语法形式:4.2 指针234.2.7 用typedef简化指针C+中中是用是用关键字关键字typedef定义定义一个标识符来代表一种数据类型一个标识符来代表一种数据类型,它的主要用途是它的主要用途是简化简化复复杂的类型说明杂的类型说明,改进程序的可读性改进程序的可读性。typedef定义定义类型的语法格式为类型的语法格式为:4.3 指针与数组的关系24在在C+中中,指针和数组的关系十分密切。数组名代表数组在内存中的首地址指针和数组的关系十分密切。数组名代表数
20、组在内存中的首地址。图图4-10中中,数组名数组名f在在表达式中被自动转换为一个指向数组首元素的指针常量。同样通表达式中被自动转换为一个指向数组首元素的指针常量。同样通过指针过指针也可以也可以访问数组中的元素。这样数组名可以用指针来代替访问数组中的元素。这样数组名可以用指针来代替,而且非常方便。而且非常方便。4.3 指针与数组的关系254.3.1 指针与一维数组从前面的介绍中已知从前面的介绍中已知,数组名表示数组首元素的地址。如定义数组名表示数组首元素的地址。如定义:int f10,则则f是数组名是数组名,也也是数组首元素是数组首元素f0的地址的地址,因此有以下等值关系因此有以下等值关系:4.
21、3 指针与数组的关系264.3.2 指针与二维数组使用指针可以指向一维数组中的元素使用指针可以指向一维数组中的元素,也可以指向多维数组中的元素。但是在概念也可以指向多维数组中的元素。但是在概念和使和使用用上要比一维数组复杂得多上要比一维数组复杂得多。1.二二维数组中元素的地址维数组中元素的地址在在C+中中,对多维数组是一种嵌套定义对多维数组是一种嵌套定义,将二维及多维数组看成是将二维及多维数组看成是“数组的数组数组的数组”。例例如如,二维整型数组二维整型数组mat的定义的定义为为:4.3 指针与数组的关系274.3.2 指针与二维数组4.3 指针与数组的关系284.3.2 指针与二维数组4.3
22、 指针与数组的关系294.3.2 指针与二维数组2.指向指向一维数组的一维数组的指针指针从上面的讨论中可以知道从上面的讨论中可以知道,二维数组名二维数组名mat是是其首其首元素元素mat0的的地址地址,该地址的该地址的类型不是类型不是int*,而而应该是一个由应该是一个由6个个int类型类型变量组成的一维数组的地址变量组成的一维数组的地址,即和即和int(*)6类型类型的指针等价。的指针等价。因此要定义一个指针指向因此要定义一个指针指向mat,可以可以如下定义如下定义:p是是一个指向一个指向由由6个个int类型类型变量组成的一维数组的指针变量组成的一维数组的指针,并指向并指向mat的的第第一行
23、一行mat0。称称p为为数组指针。数组指针。推而广之推而广之,定义二维数组的指针变量的语法格式为定义二维数组的指针变量的语法格式为:4.4 字符串304.4.1 C风格字符串1.字符串字符串与字符数组与字符数组C+中的中的字符数组可用来处理字符串字符数组可用来处理字符串,因此也允许直接用字符串常量对字符数组因此也允许直接用字符串常量对字符数组进行初进行初始化。始化。如果数组定义的长度大于初始化字符串的长度如果数组定义的长度大于初始化字符串的长度,多出的字符均为多出的字符均为0。2.字符指针字符指针与字符串与字符串用指针处理字符串更方便用指针处理字符串更方便,更灵活。例如更灵活。例如,有如下说明
24、语句有如下说明语句:char*pstr=C+isaobject_orientedlanguage;4.4 字符串314.4.1 C风格字符串3.字符串字符串处理函数处理函数C+中对中对C风格风格的字符串没有提供进行赋值、合并、比较的运算符的字符串没有提供进行赋值、合并、比较的运算符,但提供了许多但提供了许多字符字符串串处理函数。使用这些函数时要包含处理函数。使用这些函数时要包含头文件头文件cstring。下面下面讨论几个最常用的字符串处理函数。讨论几个最常用的字符串处理函数。(1)字符串复制字符串复制函数函数 char*strcpy(char*t,constchar*s)(2)串连接函数串连接
25、函数char*strcat(chart,constchar*s)(3)字符串比较字符串比较函数函数intstrcmp(constchar*s1,constchar*s2)(4)字符串长度函数字符串长度函数intstrlen(constchar*s)4.4 字符串324.4.2 C+string类下面下面介绍介绍string类型类型的常用方法。的常用方法。(1)定义定义string类型类型的对象。的对象。stringstr;/建立空字符串建立空字符串str stringstr(“OK”);/建立字符串建立字符串str,并用并用C风格风格字符串初始化字符串初始化 stringstr1(str);/
26、建立字符串建立字符串str1,并用并用str初始化初始化4.4 字符串334.4.2 C+string类下面下面介绍介绍string类型类型的常用方法。的常用方法。(2)访问访问string对象对象字符。字符。stri;/访问访问str索引索引i的字符的字符,不检查是否出界不检查是否出界 str.at(i);/访问访问str索引索引i的字符的字符,检查是否出界检查是否出界4.4 字符串344.4.2 C+string类下面下面介绍介绍string类型类型的常用方法。的常用方法。(3)string类型的类型的=、+及关系及关系等运算。与等运算。与C风格风格字符串不同字符串不同,进行这些运算时进行
27、这些运算时,不必不必考考虑虑目标串的长短目标串的长短,需要时系统会自动为目标串分配所需空间需要时系统会自动为目标串分配所需空间。str1=str2;/str2赋给赋给str1str1+=str2;/str1和和str2字符串字符串首尾连接首尾连接str1+str2;/返回一个字符串返回一个字符串,它将它将str2的的字符数据连接字符数据连接到到str1的的尾部尾部str1=str2;str1!=str2;/基于字典序比较的关系运算基于字典序比较的关系运算,返回布尔值返回布尔值(4)string类型类型字符串的输入字符串的输入/输出。输出。string类型类型输入输入/输出与输出与C风格风格字符
28、串同样方便字符串同样方便,输出使用输出使用cout和插入和插入运算符运算符“”。4.4 字符串354.4.2 C+string类(5)string类型类型提供了一些常用的函数提供了一些常用的函数,以方便字符串处理。以方便字符串处理。str.substr(pos,len);/返回返回str从从pos位置位置起起,长为长为len个个字符的字串字符的字串str.empty();/检查检查str是否是否为空字符为空字符串串str.insert(pos,str2);/将将str2插入插入str的的pos位置位置处处str.remove(pos,len);/从从str位置位置pos处处起起,删除长度为删除
29、长度为len的的子串子串str.find(str1);/返回返回str1首次在首次在str中中出现时的索引出现时的索引str.find(str1,pos);/返回返回str1首次在首次在str中出现中出现时的索引时的索引,从从位置位置pos处处起寻找起寻找str.length();/返回返回str串长度串长度str.append(str1);/和和str+=str1等价等价str.assign(str1);/和和str=str1等价等价pare(str1);/和和str1比较比较,根据比较结果根据比较结果,返回返回1、0、-1str.swap(str1);/和和str1交换交换4.5 动态内存
30、分配36C+提供提供了这样一种存储空间分配技术了这样一种存储空间分配技术,能够在程序运行时能够在程序运行时,根据实际需求根据实际需求,申请申请适量适量的的内存空间。当不再使用该内存空间内存空间。当不再使用该内存空间,再返还给操作系统。这种技术称为动态分配内存再返还给操作系统。这种技术称为动态分配内存。动态动态内存所占用空间在自由存储区内存所占用空间在自由存储区(也称堆区也称堆区)。在在C+中中,申请和释放自由存储区中空间申请和释放自由存储区中空间,分别使用分别使用new和和delete这这两个运算符来两个运算符来完成完成,使用的格式如下使用的格式如下:4.5 动态内存分配374.4.2 C+s
31、tring类在在C+中数组中数组也可以动态建立。也可以动态建立。对一维数组进行动态分配和撤销的语法格式为对一维数组进行动态分配和撤销的语法格式为:对多维数组进行动态分配语法格式如下对多维数组进行动态分配语法格式如下:4.6 动态数组实例小学生四则运算测试程序384.6.1 功能分析与算法设计小学生四则运算测试程序的小学生四则运算测试程序的主要功能有主要功能有:选择测试类型、测选择测试类型、测试题数量和难度试题数量和难度,程序程序随机产生随机产生四则运算题四则运算题,供小学生自我测试。供小学生自我测试。测试结束给出测试成绩测试结束给出测试成绩,并且显并且显示之前最高得分示之前最高得分记录记录,如果当前如果当前测试的得分超过最高得分记录测试的得分超过最高得分记录,则更新此记录。学生也可以查则更新此记录。学生也可以查看本次测试的看本次测试的所有所有题目和答题题目和答题情况情况。算法描述如下算法描述如下:4.6 动态数组实例小学生四则运算测试程序394.6.2 补充知识结构体类型1.结构体结构体类型的定义类型的定义其定义形式如下其定义形式如下:THANKS