




已阅读5页,还剩127页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
程序设计语言(C),王正杰,第四章 数组、指针与字符串,本章重点数组的定义、初始化和使用;指针的定义、访问和运算;指针与数组和函数的联系;字符串与数组和指针的关系;结构体的应用;几种常用的算法和数据结构。 本章难点指针的定义、赋值和运算;数组、字符串、结构体的操作以及动态存储分配。,在C中,除了前面介绍的基本类型外,还有一种用基本类型数据按一定的规则组成的构造类型,构造类型的每一个分量可以是一个简单的类型变量,也可以又是一个构造类型的变量,它们可以像简单变量一样使用。C语言的构造类型有数组、结构体、共同体等。指针是C语言区别于其他程序设计语言的主要特征,指针可用于有效的表示数据之间复杂的逻辑关系,也可用于动态分配内存,还可以简单有效地处理数组。用来存放字符串的数组是字符数组,除了用访问数组的方式来,操纵字符串外,我们还可以利用指针来使用字符串。本章将介绍典型的构造类型数组和结构体,以及与数组和结构体密切相关的指针和字符串。,数组是具有一定顺序关系的若干相同类型变量的集合体,组成数组的变量称为该数组的元素。 一维数组通常用于表示由固定多个同类型的具有线性次序关系的数据所构成的复合数据,如向量、某个学生的各门课成绩、学生的姓名表等。在语言中使用数组必须先进行定义,一维数组的定义形式为: 存储类型说明符 数据类型标识符 数组名 常量表达式; int a5;,数组名是用户定义的数组标识符,数组名的命名规则要遵循标识符命名规则。方括号中的常量表达式表示数组元素的个数,也称为数组的长度。 对于数组定义应注意以下几点:1)数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元素的数据类型都是相同的。2)数组名不能与其它变量名相同。3)不能在方括号中用变量来表示元素的个数,可以用符号常数或常量表达式,如arrry10表示数组arrry有 10个元素,其下标从0开始。,一维数组的初始化,数组的初始化就是在定义的同时,给部分或全部元素赋值,一维数组的初始化的格式是: 数据类型标识符 数组名常量表达式=初值表; 其中,初值表用一对花括号括起,每个初始值之间用逗号隔开。例如: int array5= 1,2,3,4,5; 该语句定义了一个包含5个整型元素的数组array并对其进行了初始化,初始化后array 0=1、array1=2、array2=3、array3=4、array4=5。,初值表元素的数量可以少于数组长度,也就是可以只对数组的部分元素赋初值。例如: int array5=1,2,3; 初始化后前三个元素的值为array 0=1、array1=2、array2=3,其余没赋初值的元素的值都为0,即array3=0、array4=0。,也可以省略数组长度,例如: int array= 1,2,3,4,5; 初始化后数组的长度为5。,一维数组的访问,像普通变量一样,数组定义之后,就可以在程序中访问数组中的元素。我们只能逐个访问其中的元素,对于数组元素的访问可以通过以下形式表示:数组名下标 int array5= 1,2,3,4,5; a=array3; array3=6;,void main() int array5,i ; /使用循环语句对数组的5个元素分别赋值 for (i=0; i5; i+) arrayi=i*i; /分别输出数组元素的值 for (i=0; i5; i+) cout“下标为“i“的元素的值是:“arrayiendl; ,C语言系统对数组的下标越界不做任何检查,即对有n个元素的数组,既可访问下标小于0的元素,也可访问下标大于n的元素。当然,这样的元素是不存在的,所以越界访问元素会给程序运行造成不可预测的后果,所以程序员应当自己控制下标越界的检查。,用数组来处理求Fibonacci数列问题,void main() int i; int f20=1,1; /初始化第0、1个数 for(i=2;i20;i+) fi=fi-2+fi-1; /求第219个数 for(i=0;i20;i+) /输出,每行5个数 if(i%5=0) coutendl; coutfi“ “; ,向函数传递一维数组,当需要把一个一维数组传给一个函数时,调用者需要把该一维数组的变量名以及数组元素的个数传给被调函数,而被调函数的形参应为不带数组大小的一维数组定义以及数组元素的个数,下面我们通过一个例子来了解向函数传递一维数组的过程。,int min ( int a, int length) int i,m=0; /m用于记录最小元的下标 for (i=1; ilength; i+) if(aiam) /逐个比较数组的元素 m=i; /找出最小的元素 return m; /函数 min将返回最小 /元素的下标: ,void main() int array10=18,26,23,13,15,25,27, 14,29,31,tag; tag=min(array,10); /调用函数min,并将数组 /名作为参数传给函数 cout“数组中最小的元素是:“arraytagendl; ,简单选择排序,假设排序过程中,待排记录序列的状态为:,有序序列R1i-1,无序序列 Rin,第 i 趟 简单选择排序,从中选出 关键字最小的记录,有序序列R1i,无序序列 Ri+1n,对主调函数传递的数组进行排序,void sort(int a,int length) /定义变量tag以标记当前最小元素之下标,/定义交换变量buffer int i,j,tag,buffer; for(i=0;ilength;i+) ,tag=i; /每次外循环,都将tag的值置为 /内循环处理的第一个元素的下标 /内循环的任务是找出数组中下标 /从i到length的元素的最小者 for(j=i;jaj) tag=j; /标记小元素的下标 /将当前未排好序数组的最小元素atag /和元素ai交换 buffer=atag; atag=ai; ai=buffer;,void main() int array10=6,2,10,3,7,5,9,4,8,1,i; coutendl“排序前数组array:“; for(i=0;i10;i+)coutarrayi“ “; sort(array,10);/调用函数sort,并将数组array /和数组长度作为参数传递给函数 coutendl“排序后数组array为:“; for(i=0;i10;i+)coutarrayi“ ”; /输出排序 /后的数组array coutendl; ,该程序使用的是选择排序,其思想是,第一次从所有元素中选取最小值,与a 0交换;第二次从剩余元素中选取最小值,与a 1交换;直至完成整个数组的排序。函数sort中,每轮内循环结束后tag中存放的就是剩余元素中最小者的下标;第i次外循环结束后,数组前i个元素就都是已经排好序的元素。当排序完成返回主调函数main后,主调函数的数组array就是已经完成排序的数组,这是因为main函数中的数组array和sort函数中的数组a代表同一块存储空间,从本质上讲它们是同一个数组。,用起泡法对10个数排序(由小到大)。 起泡法的思路是:将相邻两个数比较,将大的调到后头。,起泡排序,假设在排序过程中,记录序列R0n-1的状态为:,第 i 趟起泡排序,无序序列R1n-i+1,有序序列 Rn-i+2n,n-i+1,无序序列R1n-i,有序序列 Rn-i+1n,比较相邻记录,将关键字最大的记录交换到 n-i+1 的位置上,void main() int a10=6,2,10,3,7,5,9,4,8,1; int i,j,t; for(j=1;jai+1) t=ai;ai=ai+1;ai+1=t; cout“the sorted numberS :“endl; for(i=0;i10;i+) coutai“ “; ,二维数组,前面介绍的数组只有一个下标,称为一维数组,而在实际问题中经常要处理多维的量,需要构造二维数组或更多维的数组。简单地说,二维数组就是具有两个下标的数组,其元素有两个下标,以标识它在数组中的位置。数组维数的概念与几何中维数的概念是相似的,如果说一维数组的元素是线性排列的,只要给出一个下标就可以确定某一特定元素。那么,二维数组就类似于几何中的X-Y坐标系,坐标系中只要指出X坐标和Y坐标就能确定一个点,而要确定二维数组中的某一个元素也只需指出元素所在的行和列。,二维数组定义,存储类型说明符 数据类型标识符 数组名常量表达式1常量表达式2; 其中存储类型说明和数据类型说明与一维数组相同,常量表达式1表示第一维下标的长度,常量表达式2 表示第二维下标的长度,两个常量表达式中不能包含变量。例如: int array23; 定义了一个二维数组array,该数组有两行,每行有三个元素。,二维数组的行下标和列下标都是从0开始的,对于n行m列的二维数组,行下标的取值范围为0n-1,列下标取值范围为0m-1。 二维数组的所有元素占有的内存空间是连续的,因此只要知道数组在内存中的起始地址就可以很容易的算出其它元素的存储单元地址。,二维数组的初始化,二维数组赋初值的方式有两种,一种是不分行给二维数组所有元素赋初值,比如int array23=1,2,3,4,5,6;,另一种更直观的方法是分行给二维数组所有元素赋初值,如int array23=1,2,3,4,5,6;。,同一维数组一样,二维数组也可以只给部分元素赋初值,例如: int array23=1,2,3; 对数组前三个元素array00、array01、array02分别赋以1、2、3,其他剩余元素都为0。 此外二维数组还可以用分行的方法给部分元素赋值,例如: int array23=0,2,4; 初始化后各元素的值是array00=0、array01=2、array02=0、array10=4、array11=0、array12=0,,对二维数组赋初值可以省略说明第一维的长度,但是无论何种情况,都不能省略说明第二维的长度。在给全部元素赋值时,例如: int array23=1,2,3,4,5,6; 编译系统会根据初值个数分配相应的存储单元。在分行给元素赋初值时,如: int array3=2,4,5,6; 编译系统也会根据所分的行数确定第一维的长度。,二维数组的使用,对二维数组的访问同一维数组类似,也是通过下标运算符“”和下标值来进行的。访问的形式如下: 数组名 行下标列下标 例如: int array23= 1,2,3,4,5,6; a=array10; array10=6; 这几条语句的功能是访问数组array中,第二行第一列的那个元素,将其值4赋予变量a后,赋予其新值6。,求4*4二维数组各行和各列元素之,void main() int c4,r4, i,j; /定义c4存放列元素的和, / r4存放行元素的和 int array44= 1,2,3,4,5,6,7,8, 9,10,11,12,13,14,15,16; for(i=0;i4;i+) ri=ci=0; /初始化一维数组 . for(i=0;i4;i+) /输出行元素的和 cout“第”i+1“行元素的和为: “riendl; for(i=0;i4;i+) /输出列元素的和 cout“第”i+1“列元素的和为: “ciendl; ,for(i=0;i4;i+) for(j=0;j4;j+) /将第i行第j列的元素的值加入ri ri=ri+arrayij; /将第i行第j列的元素的值加入cj ci=ci+arrayji; /一次循环就好 /或cj=cj+arrayij;多次循环才行 ,二维数组名作函数的参数,主函数中初始化一个矩阵并将每个元素都输出,然后调用子函数,分别计算每一行的元素之和,将和直接存放在每行的第一个元素中,返回主函数之后输出各行元素的和。,void RowSum(int A4, int nrow) int sum; for (int i = 0; i nrow; i+) sum = 0; for(int j = 0; j 4; j+) sum += Aij; cout “Sum of row “ i “ is “ sum endl; Ai0=sum; ,void main(void) int i; int Table34 = 1,2,3,4,2,3,4,5,3,4,5,6; for (i = 0; i 3; i+) for (int j = 0; j 4; j+) cout Tableij “ “; cout endl; RowSum(Table,3); for (i = 0; i 3; i+) cout Tablei0; ,指 针,指针是C+语言最主要的风格之一,也是C+语言最重要的内容之一,利用指针变量不仅可以有效地表示各种数据结构,也可以用于参数传递和动态分配存储空间,并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针的应用使得C+语言具有灵活、实用、高效的特点。,在计算机中,所有的数据都是存放在存储器中的。计算机的存储器就像一个巨大的一维数组,每个数组元素就是一个存储单元。一般把存储器中的一个字节称为一个内存单元,不同的数据类型所占用的内存单元数不等,如整型数据占4个单元,字符型数据占1个单元,为了正确地访问这些内存单元,必须为每个内存单元编上号,根据一个内存单元的编号即可准确的找到该内存单元,内存单元的编号也叫做地址。,关于内存地址,内存空间的访问方式 通过变量名访问 通过地址访问 地址运算符: 则&var 表示变量var在内存中的起始地址,在用高级语言进行程序设计时,我们通过变量来使用存储在内存中的数据,程序在一般情况下都不需要涉及内存空间的地址,但是,为了增加程序设计的灵活性和提高程序的效率,有时需要直接对内存地址进行操作,C就使用指针类型变量来实现对内存地址的操作。,指针就是指向其它变量的变量,指针的值就是其所指对象的内存地址。严格地讲,指针是C语言中的一种数据类型,但它是一种特殊的数据类型,指针并不是某个具体的数据值,而是指向数据存储单元的计算机存储器的地址。内存单元的地址(指针)和内存单元的内容是两个不同的概念,对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元的内容。,在语言中,使用一个变量来存放指针,这个变量就称为指针变量,一个指针变量的值就是某个内存单元的地址。指针变量与其他变量一样,它占有一定的存储空间,但所不同的是它只能用来存储地址而不能用来存储其他类型的数据。一句话,指针就是存储另一变量地址的变量,一个指针变量的值就是某个内存单元的地址。,指针的定义,与普通变量一样,指针变量在使用前也需要定义。其一般形式为: 数据类型标识符 *变量名; int *p; /说明p是一个指针变量,它的值是某个整型变量的地址 float *q; /说明q是指向浮点变量的指针变量 char f ,*r; /说明f是字符变量,r是指向字符变量的指针变量,指针的赋值,在定义一个指针的同时也可以对它进行初始化赋值,通常是用一个与说明的指针具有相同类型的变量的地址来进行赋值的。初始化赋值的形式如下: 数据类型说明符 *指针变量名=地址; 其中地址可以是同类型变量的地址、数组的地址或数组元素的地址。地址可以用取地址运算符 语句执行完后,变量a的地址将赋给指针变量p,或称将指针p指向变量a,指针变量也可以在定义后赋值,如上述语句就可以改为 int a=5, *p; p= 需要注意的是,没有赋值的指针变量中存放的是一个随机值,使用没有赋过值的指针是相当危险的。如果要使指针变量中的指针不指向任何存储单元,那么可以将空指针赋给指针变量,空指针的值为0,也可以用在stdio.h中定义的符号常量NULL表示。,指针的访问,前面介绍的是如何对指针变量进行赋值,对指针变量赋值后就可以对其进行访问了。 对指针值的访问有两种形式, 一种是将一个指针的值赋给另一个指针 另一种是用指针运算符*将指针所指向的变量的值取出用以访问。,void main() int a=10,b,*p= ,以指针作为函数参数,以地址方式传递数据(传入地址),可以用来带回函数处理结果。 实参是数组名时形参可以是指针。,读入三个浮点数,将整数部分和小数部分分别输出,void splitfloat(float x, int *intpart,float *fracpart) /形参intpart、 fracpart是指针 *intpart = int(x); / 取x的整数部分 *fracpart = x - *intpart; /取x的小数部分 ,void main(void) int i, n; float x, f; cout x; splitfloat(x, ,使用指针来完成两个整数的交换,Swap(int *p1,int *p2) int temp; temp=*p1; *p1=*p2; *p2=temp; ,void main() int a,b; int *pointer_1,*pointer_2; cinab; pointer_1= ,指针的运算,指针变量可以进行赋值运算、部分算术运算及关系运算。 指针的算术运算主要有指针变量加减一个整数(例如p+、p-、p+i、p-i、p+=i、p-=i)和两个同类型的指针变量的相减(例如p-q)。 两指针之间的关系运算表示他们指向的变量在内存中的位置关系。例如: p=q表示p和q指向同一元素;pq表示p处于高地址位置;pq表示p处于低地址位置。上述指针的关系运算一般用于对数组的访问。,指针变量加或减一个整数i的意义是把指针的当前位置(指向某数组元素)向前或向后移动i个位置。例如: short array8,*p; p=array; p=p+5; 其中第二条语句将指针p指向数组array即指向a0,第三条语句将p指向array5,设p是指向数组array的指针变量,则p+i,p-i,p+,p-,p+=i等运算都是合法的。需要注意的是,一个指针变量加(减)1并不是简单地将原值加(减)1,而是将该指针变量的原值(是一个地址)和它指向的变量所占用的内存单元字节数加(减)。同样,指针移动i个位置不等于指针移动i个字节 。 short *p; p+; 指针p指向的地址向高地址移动了2个字节(因为一个短整型数占2个字节 int *p; p+; 则指针p指向的地址向高地址移动了4个字节,两指针变量相减的得到一个整数。如果两个指针变量指向同一个数组的元素,则两个指针变量相减所得的整数是两个指针所指数组元素之间相差的元素个数。例如: int array10,*p,*q,n; p=array; q=p+2;n=q-p; 其中第二条语句将指针p指向数组array即指向a0,第三条语句将p指向array2,第四条语句将指针变量q和p相减得到的值赋给变量n,此时变量n的值是2。,指针与0比较,指针变量可以与0比较,例如: p=0表明p是空指针,它不指向任何变量; p!=0表示p不是空指针。需要再次强调的是,空指针不同于未赋值指针,指针变量未赋值时,它的值不确定,是不能使用的,否则将造成意外错误。而指针变量赋0值后,它就成为空指针,它不指向具体的变量。 int *p; int b=*p;这里没有给p赋值,就使用*p,是绝对错误的!,指针与数组,数组名是一个不允许赋值运算的指针,这个指针的值就是数组的起始地址,例如,对整型一维数组array10,array就是一个指向数组起始地址的指针,它指向数组的第一个元素,array的值与array0的地址相同 用array+i可以表示arrayi的地址,也就是说array+i与& arrayi是相等的 有两种方式表示数组元素:下标法array2和地址法:*(array+2),指向数组元素的指针,声明与赋值 例: int a10, *pa; pa= 通过指针引用数组元素 经过上述声明及赋值后: *pa就是a0,*(pa+1)就是a1,. ,*(pa+i)就是ai. ai, *(pa+i), *(a+i), pai都是等效的。 不能写 a+,因为a是数组首地址是常量。,设有一个int型数组a,有10个元素。用三种方法输出各元素: 使用数组名和下标 使用数组名和指针运算 使用指针变量,数组名和下标 for(i=0; i10; i+) coutai; 使用数组名指针运算 for(i=0; i10; i+) cout*(a+i); 使用指针变量 for(p=a; p(a+10); p+) cout*p;,行指针和列指针,定义一个二维数组int array34来说明,由于二维数组可以看作特殊的一维数组,其中每一个元素又是一个一维数组,所以可以把数组array看作是由array0、 array1、 array2三个元素组成的特殊一维数组,而array0、 array1、 array2又可以分别看作一维数组,所以array0、 array1、 array2也表示一维数组的起始地址。,既然array和array0、 array1、 array2都表示地址(指针),它们之间有什么区别呢?区别就在于array+1指向的是第2行元素的起始地址,也就是array1指向的地址,而array0+1指向的是元素array01的起始地址。array每加1,就跳过一行,所以被称为行指针,而array0、 array1、 array2被称为列指针。,通过运算符*将行指针转换成列指针,*array与array0 相等,*array+1与array0+1是相等的,这里*只是将行指针转换成了列指针,*array还是表示地址,而不是取地址的内容。若要取元素array00的内容,可以用* array0或*array,这里*array的后一个*表示先将行指针转换成列指针,前一个*表示取内容。,array0+1和*(array +0)+1,是array01的地址,那么,*(array0+1)就是array01的值。同理,*(*(array +0)+1)或*(* array +1)也是array01的值。*(arrayi+j)或*(*(array +i)+j)是arrayij的值。务请记住*(array +i)和arrayi是等价的。,array、array+i、array i、*(array+i)、*(array+i)+j、array i+j都是地址。 *(arrayi+j)、*(*(array+i)+j)、 array ij是二维数组元素array ij的值。,指向包含4个元素的一维数组的指针,void main() int a34=1,3,5,7,9,11,13,15,17,19,21,23; int (*p)4,i,j; p=a; cinij; cout“a“i“j“=“*(*(p+i)+j)endl; ,多维数组的地址可作函数参数传递,在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法: 用指向变量的指针变量; 用指向一维数组的指针变量。,有一个班,3个学生,各学4门课,计算总平均分数,以及第n个学生的成绩。 用函数average()求总平均成绩,用函数search ()找出并输出第i个学生的成绩。,void average(float *p,int n); void search(float (*p)4,int n); void main() float score34=65,67,70,60, 80,87,90,81,90,99,100,98; average(*score,12);/求12个分数的平均分 search(score,2); /求第2个学生成绩 ,void average(float *p,int n) float *p_end; float sum=0,aver; p_end=p+n-1; for(;p=p_end;p+) sum=sum+(*p); aver=sum/n; cout“average=“averendl; ,void search(float (*p)4,int n) int i; cout“the score of No.“n “ are:“endl; for(i=0;i4;i+) cout*(*(p+n)+i)“ “; ,指针数组,指针数组就是由指针组成的数组,也就是说数组中的每个元素都是相同数据类型的指针变量。指针数组的声明方式和普通数组相似: 数据类型说明符 *数组名常量表达式; 例如: char *pc5; 声明了一个一维指针数组,其中包括5个元素,均为指向字符类型的指针,void main() int line1=1,0,0; int line2=0,1,0; int line3=0,0,1; int *p_line3; /声明整型指针数组 p_line0=line1; /初始化指针数组元素 p_line1=line2; p_line2=line3; cout“Matrix test:“endl; for(int i=0;i3;i+) /对指针数组元素循环 for(int j=0;j3;j+) /对矩阵每一行循环 coutp_lineij“ “; coutendl; ,函数的指针,我们知道程序只有在代码装入内存后才能运行,函数本身作为程序的一部分,也要在内存中占有一片存储区域,这个区域的起始地址,就是函数的指针,也称之为函数的入口地址。函数的指针与数组的指针类似,数组名代表数组的指针,即数组的首地址,同样函数名就代表函数的指针,也就是函数的入口地址。,函数原型为int fun(int x,int y ,int z),则定义函数指针变量的语句为int(*pfun)(int,int,int),需要注意的是,在声明指向函数的变量时,变量名外的括号不能少。若是没有括号,如 int *pfun(int,int,int)就成为定义返回指针的函数。 定义好的指针变量可以存放函数的指针,例如: pfun=fun; 该函数返回值的数据类型,函数参数个数、类型都应与定义指针变量时说明的一致 。,int minx(int x,int y) if(xy) return x; else return y; ,void main() int a,b,c; int (*pmin)(int x,int y); /定义指向函数的指针 pmin=minx; /将该指针指向函数min / 可以写成pmin= ,返回指针值的函数,函数名前的数据类型标识符用于表示该函数的返回值是什么类型的,函数的返回值可以是整型、字符型或浮点型,也可以是指针型,这时应该将函数的返回值说明成相应数据类型的指针,返回指针值的函数定义格式如下: 数据类型标识符 *函数名 ( 形式参数说明列表 ),其中数据类型标识符和函数名之间的*表示该函数的返回值是指针,数据类型标识符表示指针指向的是何种类型的数据,例如: float *fun(int a , int b); 就声明了一个返回值为单精度浮点型指针的函数。,float *compute(float x,float y) /定义float型指针result用以返回计算结果,并为 /其分配的空间(动态存储分配下一节将介绍) float *result=new float4; /将计算结果依次存入result所指向的存储空间中 *result=x+y; *(result+1)=x-y; *(result+2)=x*y; *(result+3)=x/y; return result; /返回指针result ,void main() float a,b,*p; /定义float型指针p用以接受返回值 couta; coutb; p=compute(a,b);/调用函数,p和result指向同一内存 if(p) /如果result申请的空间得到了允许 /利用指针p依次输出计算结果 cout“两数的和是:“*pendl; cout“两数的差是:“*(p+1)endl; cout“两数的积是:“*(p+2)endl; cout“两数的商是:“*(p+3)endl; delete p; /释放申请的内存空间 ,compute函数申请了4个单精度浮点单元的内存空间,并将这个空间的首地址赋给指针变量result,计算的结果存放在这块存储空间内,并将指针变量返回给主调函数main。主函数使用指针p来接受compute返回的指针result的值,再使用p将计算结果逐个输出,最后释放p指向的内存空间。,动态存储分配,到目前为止,程序中使用的变量和数组的类型、数目和大小是在编写程序时由程序员确定下来的,因此在程序运行时这些数据占用的存储空间数也是一定的,这种存储分配方法被称为静态存储分配,静态存储分配的缺点是程序无法在运行时根据具体情况灵活调整存储分配情况。C+提供了内存空间动态管理的机制,使程序在运行过程中可以按照实际需要申请适量的内存,使用结束后,还可以释放所申请的内存,在程序运行过程中申请或释放的内存单元称为堆,动态申请和释放内存的过程称作建立和删除。,自由存储区也称堆区,是一块可以动态管理的内存区,C+中用指针和new运算符来动态地申请一块内存单元,用delete运算符来释放被申请的内存单元。动态申请变量空间与申请数组空间的格式略有不同,我们分别进行讨论。 使用new运算符动态申请变量空间的格式如下: new 数据类型标识符 (表达式);,数据类型标识符表示开辟的空间中存放何种类型的数据,表达式表示对动态定义的变量进行赋初值,可以省略。如果存储空间的动态开辟成功,则返回指向那块开辟的内存单元地址,否则返回NULL,即空指针。例如: int *p; p=new int(2); 这两条语句的含义是,使用new运算符从自由存储区中分配一块与int类型相适应的存储空间,并赋初值2,然后将这个存储空间的首地址存入事先定义好的整型指针p,如果分配失败,则置指针p为空指针,使用new运算符动态申请一维连续空间格式: new 数据类型标识符 整型表达式; 其中,数据类型标识符表示要申请何种数据类型的存储空间,整型表达式表示一维数组的长度。如果申请分配成功,返回的是数组的指针,失败则返回空指针NULL 。需要注意的时候,动态开辟数组时,无法对其中的元素进行初始化。例如: int *parr; parr=new int 5; /申请的是长度为5的整型数组的存储区域,使用动态存储分配时要注意在确认分配成功后才能使用,否则可能造成严重后果;分配成功后最好不要变动指针的值,否则在释放这片存储时会引起系统内存管理混乱;动态分配的存储空间不会自动释放,只能通过delete释放。 使用delete运算符释放动态分配的变量和数组存储空间的形式分别如下: delete p ; / delete 指针:释放变量空间 delete parr; / delete 指针:释放连续空间 编写程序时,动态的开辟内存一定要有相应的内存释放,否则会造成内存空间的浪费。,输入任意个数的数据, 然后输出所有数据,void main() float *parr; /定义指针用来指向分配存储区的首地址 int i,length; /length用以记录要输入数据的个数 coutlength; parr=new floatlength; /申请长度为length的float数组if(parr) /如果内存分配成功,继续输入数据 else cout“内存分配失败“endl; ,for(i=0;iparri; cout“你刚才输入的数据是:“endl; for(i=0;ilength;i+) coutparri“ “;/输出数组 coutendl; delete parr; /释放申请的内存空间,C语言编译系统的内存管理函数,void *malloc(unsigned int size); 其作用是在内存的动态存储区中分配一个长度为size的连续空间。此函数的值(即“返回值”)是一个指向分配域起始地址的指针(基类型为void)。如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)。,void free(void *p); 其作用是释放由p指向的内存区,使这部分内存区能被其他变量使用。p是调用malloc函数时返回的值。free函数无返回值。,字 符 串,C+语言中的文字数据有两种:一种是单个的字符,一种是字符串。在前面我们了解到,单个的字符可以用字符变量存放。C+中没有字符串数据类型,对字符串数据的存放是通过字符数组或指针指向的一块连续内存空间来实现的。,一维字符数组的定义和普通数组是类似的,只不过数据类型标识符为char型。如: char c10; / 定义了一个长度为10的一维字符数组 一维字符数组初始化的常用方式是以字符串的形式进行初始化,即将整个字符串直接赋值给数组。例如: char c10= “hello c+”;或者 char c10=“hello c+”; 也可以不指定数组长度进行赋值,例如: char c2= “hello c+”;,字符串的结束标志,字符串总是以0作为串的结束符,因此当把一个字符串存入一个数组时,编译系统会自动把结束符0存入数组,并以此作为该字符串是否结束的标志,二维字符数组,字符型的二维数组也可以看成由多个一维字符数组组成的,所以可以用二维字符数组来存放多个字符串。 char week3=“Sun”,”Mon”,”The”, ”wed”,”Thu”,”Fri”; 定义了一个6行的二维字符数组week,每行又可以看作包含3个元素的一维字符数组。注意,在初始化时,元素是用双引号括起的,这是因为相当于对一维字符数组赋予一个字符串作初值。,输入ASCII码,查找并输出其对应的大写英文字母,void main() char letter=“ABCDEFGHIJKLMNOPQRSTUVWXYZ“; int asc; /保存输入的十进制ASCII编码 coutasc; if(asc=A ,void main() int asc; coutasc; cout(char)ascendl; ,指针访问字符串,对字符数组的访问同样也可以使用指针法,所谓字符串的指针就是该字符串在内存中所占空间的起始地址,由于字符串可以用字符数组来实现,所以字符数组名就可以表示该字符串的起始地址,即字符串的指针。我们可以定义指针变量来存放字符串的指针。 char *string, c10=“hello c+”; string=c;,求字符串长度函数,int str_len(char str) char *p=str; /指针p用以访问字符数组str while(*p!=0) /当指针指向的单元 p+; /内容为0时,表示字符串结束 return p-str; void main() char string=“abcdefghijklmnopqrstuvwxyz“; cout“字符串”string“的长度为: “ str_len(string)endl ,例如使用字符串指针变量如string可以进行自加自减运算,而数组名c不能进行自加、自减运算;字符串指针变量的定义和初始化可以同时进行,也可分开进行 char *string=”hello c+”; /字符串指针变量的定义和初始化同时进行,正确 char *string; / 字符串指针变量先定义,正确 string=”hello c+”; /字符串指针变量后初始化,正确,字符数组的定义和初始化则只能同时进行,不可以分开进行。 char c10=“hello c+”; /字符数组的定义 /和初始化同时进行,正确 字符数组的定义和初始化分开进行 char c10; /字符数组先定义,正确 c=“hello c+”;/ 字符数组后初始化,不正确,字符串拷贝函数,将str2内容拷入str1,void str_cpy(char str1 , char str2) char *p1=str1,*p2=str2; int i=0; while(p2i!=0) p1i=p2i; i+; /指针使用下标i完成移动 p1i=0; /必须给str1补上结束标志0 ,void main() char letter1=“abcdefghijklmn“, letter2=“I love C+“; cout“字符串letter2为:“letter2endl; cout“字符串letter1为:“letter1endl; str_cpy(letter1,letter2);/调用字符串拷贝函数 cout“函数调用后字符串letter2为:“letter2endl; cout“函数调用后字符串letter1为:“letter1endl; /输出完成拷贝的字符串 ,字符串处理函数,从前面的例子可以看到,用下标法和指针法来操作字符串非常繁琐。因此,C+提供了一批用于字符串处理的库函数以完成许多常用的字符串操作,如果要在程序中调用输入输出的字符串函数,在使用前应包含头文件“stdio.h“,使用其它字符串函数则应包含头文件“string.h“。,常用的两个字符串函数,strlen( str ) 功能:测字符串的实际长度(不含字符串结束标志0) strcpy (str1,str2) 把字符数组str2中的字符串拷贝到字符数组str1中,串结束标志“0”也一同拷贝。,结 构,在程序中往往还需要处理一些由不同类型元素所构成的复合数据,例如学生基本信息的数据,它由学号、姓名、专业号和入学成绩等元素构成,这些元素不存在像数组那样的线性关系,而且往往还具有不同的数据类型,因此不能用数组类型来表示这样的数据。由于这些数据元素之间有相当强的联系,如果使用一些不同类型的变量来表示上述的复合数据,就会破坏数据的内聚性,而且变量的数目会变得很多,极大地降低程序的可读性。,C提供了结构类型用以描述和管理这种复杂的数据结构,结构是若干相关数据项的有机结合,但各数据项的数据类型可以不同。对于上例,可用long型变量存放学号、char型数组存放姓名、int型变量存放专业号、float型变量存放入学成绩,作为结构的成员,包含在结构类型中,再用该结构定义相应的结构型变量。这样,学生的信息就可以用一个结构型变量存放,数据之间的联系得到了体现,数据的传递也大为方便。,应以关键字struct开始,结构类型名应符合标识符命名规则,数据成员为结构中的数据项,它们都是变量,其类型可以是基本数据类型,也可以是已定义的自定义数据类型。成员名在结构体内具有唯一性,但是允许成员名和程序中的变量名或是其他结构体中的成员名重名,一个结构的所有成员应括在一对花括号内,而且花括号后的分号是必需的。 struct student long num; char *name; int majornum; float scores; ;,定义结构体类型变量的方法,1. 先声明结构体,再定义变量名(普遍使用) 如上面已定义了一个结构体类型struct student,可以用它来定义变量。如: struct student student1, student2; 2. 在声明类型的同时定义变量(不常用),例如: struct student student1,student2; 直接定义结构类型变量(不常用) struct student1,student2;,对结构变量的访问,有两种方式 一种是访问结构变量的某个数据成员, 另一种是访问整个结构变量。,访问一个结构变量中的某个数据成员需要用到成员运算符“.”,它是双目运算符,其左边的操作数是一个结构类型变量,右边的操作数是该结构的一个成员。例如,zhangsan.num表示访问结构类型变量zhangsan的成员num。结构类型变量的每个成员都可以看作是一个独立的变量,对成员变量可以实施像普通变量一样的操作。例如: zhangsan.num=20061001; zhangsan.majornum=10;,对整个结构变量的访问,赋值运算符 = 用于同类型变量之间的赋值操作,这个过程实际上是整个结构变量值的复制过程。例如, lisi=zhangsan; 就是将结构类型变量zhangsan所有成员的值复制给lisi的相应成员变量。,结构体定义和变量的赋值与输出,struct student long num; char *name; int majornum; float scores; ;,void main() /定义student型变量lisi、wangwu、a,初始化lisi student lisi=200610
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年重庆市铜梁区教育事业单位面向铜梁籍应届毕业教育部直属师模拟试卷及答案详解一套
- 2024-2025学年度广东江门中医药职业学院单招《语文》通关题库附参考答案详解【B卷】
- 浙江宁波市市场监督管理局局属事业单位宁波市药品检验所招聘高层次人才笔试备考题库及参考答案详解1套
- 2025年自考公共课每日一练试卷(综合卷)附答案详解
- 公务员考试《常识》高频难、易错点题【黄金题型】附答案详解
- 2025年中共延川县委办公室遴选(选聘)文秘人员的(6人)考前自测高频考点模拟试题及答案详解一套
- 2024高职单招考前冲刺练习题及答案详解(历年真题)
- 2023年度武夷山职业学院单招《英语》考试历年机考真题集附答案详解【A卷】
- 河道堤坝结构设计与加固方案
- 浙江台州三门县消防救援大队招聘消防车驾驶员3人笔试高频难、易错点备考题库含答案详解
- GB 23466-2025听力防护装备的选择、使用和维护
- 人教PEP版(2024)四年级上册英语-Unit 3 Places we live in 单元整体教学设计(共6课时)
- 华为信息安全管理培训课件
- 贵阳市殡仪服务中心招聘考试真题2024
- 重庆市危险化学品企业变更管理实施指南(试行)解读2025.7.25
- 煤改电工程施工质量监控方案和措施
- 布病的护理教学课件
- (2025年标准)预售小麦协议书
- 2025年院感测试题及答案
- 2025年全国保密教育线上培训考试试题库完整答案附带答案详解
- 全套教学课件《工程伦理学》
评论
0/150
提交评论