




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第第4章章 数组和指针数组和指针l4.1 数组数组l4.2 指针指针l4.3 数组与指针数组与指针l4.1.1 数组的概念数组的概念l4.1.2 数组的声明、引用和赋初值数组的声明、引用和赋初值l4.1.3 字符数组字符数组l4.1.4 数组应用实例数组应用实例l引入数组的必要性引入数组的必要性l什么是数组什么是数组l实例实例计算多边形面积计算多边形面积l在许多情况下,仅用一个个单独的变量来保存数据,是很难满足解题需要的,例如,如果要计算矩形面积,我们可以声明两个变量来分别保存矩形的长和宽:double length, width, area;scanf(%lf %lf, &lengt
2、h, &width);area = length * width;l但要根据顶点坐标计算多边形的面积:l就不可能用单独的变量来保存顶点坐标了。nnkkkkyxyxyxyxyxyxS11111221.l数组是一组同类型变量按下标顺序组成的集合,它用唯一的标识符 数组名来表示集合中的所有元素,而用数组名加下标来表示集合中的每个元素。例如:a0,a1,a2,an-1l一个数组一旦被创建,它的n个元素就作为n个变量被同时映射到n个连续的内存单元:.a0a1a2an-1#includeint main()int n = 4;/ 分别声明两个具有4个元素的double型数组x和y,并赋初值doub
3、le x4 = 100, 300, 300, 100 ; / 存放4个顶点的横坐标double y4 = 100, 100, 300, 300 ; / 存放4个顶点的纵坐标/ 计算以(xi,yi)为顶点的多边形的面积:double s = 0;for (int i = 0; i n; i +)s += xi % n * y(i + 1) % n - x(i + 1) % n * yi % n;s /= 2;printf(“多边形面积为:%fn”, s);/ 打印多边形的面积return 0;l数组维数和元素数目的概念数组维数和元素数目的概念l声明一维数组的语法声明一维数组的语法l一维数组元素的
4、引用一维数组元素的引用l多维数组多维数组l为数组元素赋初值为数组元素赋初值l维数在数学中指独立参数的数目,如一维表示数轴(一个参数)、二维表示平面(两个参数),等等。数组维数则表现为数组元素下标的数目,即一维数组有1个下标(可用来存放向量);二维数组有2个下标(可用来存放矩阵),等等。首先介绍一维数组。l每一维的下标都有一个范围,语言中,下标的最小值为(而不是),最大值由数组声明规定,如果某维的元素数目为,则该维下标的最大值为-。l声明一维数组的语法是:类型标识类型标识 数组名数组名数组元素数目数组元素数目;l其中“数组元素数目”是一个整型的常量表达式,例如:int A10;l声明了一个10个
5、元素的整型一维数组,数组元素的下标为09,即数组元素为A0, A1, , A9l共10个。l引用一维数组元素的语法是:数组名数组名下标下标l其中“下标”是一个整型表达式,取值在(数组元素数目-1)之间,例如:int A10;for (int i = 0; i 10; i +) /循环变量i从0变化到9 Ai = i * i;/为A的第i个元素赋值i2for (int i = 0; i 10; i +) /循环变量i从0变化到9 printf(%dn, Ai);/打印A的第i个元素值l声明二维数组的语法是:类型标识类型标识 数组名数组名第第1维元素数目维元素数目 第第2维元素数维元素数目目;l其
6、中“第维元素数目(i=1,2)”均为整型常量表达式,例如:int B25;l声明了一个2行5列共10个元素的整型二维数组,数组元素(按内存中的排列顺序)为:B00, B01, B02, B03, B04, B10, B11, B12, B13, B14l更多维数组则以此类推。l在声明数组的同时,可以为全部或者部分数组元素赋初值,语法为:数组声明数组声明 = 初值表初值表 ;l例如:int A10 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; / 一维int B25 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ; / 二维l如果初值表中的数据少于数组元素
7、的数目,则无对应数据的数组元素将不被赋初值。l多维数组的初值表实际上是一维的,二者的对应关系遵循“右边下标变化快”的原则。l字符数组的概念字符数组的概念l字符数组的存储和赋值字符数组的存储和赋值l字符和字符数组元素的输入输出字符和字符数组元素的输入输出l字符数组和字符串字符数组和字符串l字符串结束标志字符串结束标志l字符串的输入输出字符串的输入输出l字符串处理函数字符串处理函数l字符数组是字符类型的数组,即该数组的每个元素都是字符变量。字符数组用类型标识char来声明,即一维字符数组声明为:char 数组名数组名数组元素数目数组元素数目;l例如:char C26;l声明了一个一维字符数组,它的
8、每个元素都可以存放一个字符,例如:for (int i = 0; i 26; i +) Ci = a + i; / C0C25存放了字符azl从绪论的基本数据类型列表可以看出, 字符类型char实质上是一种1字节整型,可用来存放字符的ASCII码。而字符常量既可用两单引号引起的字符,也可用该字符的 ASCII码来表示。因此,字符变量或字符数组元素允许用字符常量或0127的整数来赋值,如下例分别使用了字符型常量、十进制整数和十六进制整数为字符变量和数组元素赋值:char c1 = A, c2 = 65, c3 = 0 x41;/三者是等价的char C3 = A, 65, 0 x41 ; /用三
9、种方法赋初值l使用scanf和printf进行输入输出时,字符和字符数组元素可以采用%c格式(IO字符)或%d格式(IO字符的ASCII码)来控制。例如:char c;/ 声明一个字符型变量scanf(%c, &c);/ 以字符格式输入printf(%dn, c); / 以整数(ASCII码)格式输出char C2; / 声明一个2个元素的字符型数组scanf(%d %d, &C0, &C1);/ 以整数格式输入printf(%c %cn, C0, C1); / 以字符格式输出l2.2.1曾提到, C只有字符串常量而无字符串变量。C的字符串可以用字符数组来存储。在声明字
10、符数组的同时,既可用一组字符常量为字符数组元素赋初值,又可用一个字符串常量为字符数组整体赋初值,例如:char S16 = H, e, l, l, o ;/元素04为Hellochar S26 = Hello ;/元素04为Hellol但不允许用一个字符串为字符数组赋值:char S6; S = Hello;/ 语法错误!l然而,尽管Hello只有5个字符,但若将数组S1和S2的元素数目从6改到5, 则第1句正确, 第2句却出现溢出错误,这是为什么呢?l原来,当用一个字符串为字符数组赋初值,或将一个字符串输入字符数组,或用某些字符串函数对字符数组进行操作时,系统会自动将一个“0字符”(即ASC
11、II码为0的字符而不是ASCII码为0 x30的字符0)追加到字符串的末尾来作为字符串的结束标志。若未为该字符留出空间,则出现溢出错误。l由于字符数组可以当做字符串变量使用,因此和字符串常量一样,字符数组也可以通过%s格式进行输入输出,例如:char str16;scanf(%s, str); /输入一个字符串到str(以0结尾)printf(%sn, str); / 输出str中的字符串(不包括0)l字符数组还可以通过 gets 和 puts 两个函数进行输入输出,下例代替了上例后两句:gets(str);/ 输入一个字符串到str(以0结尾)puts(str);/ 输出str中的字符串(不
12、包括0)l为便于对字符数组存储的字符串实现各种操作,设计了一系列字符串处理函数,包括赋值、追加、比较、求长、查找等。使用这些函数,须包含头文件。函数名函数功能调用示例调用结果strcpy字符串拷贝 strcpy(str, Love);str = Love strcat字符串追加 strcat(str, you);str = Love youstrcmp 字符串比较 strcmp(str, Hello); 返回1(L H)strlen字符串求长 strlen(str);返回8(str的长度)strspn字符串查找 strcspn(str, o);返回2(v的下标)l一维数组用例一维数组用例Fib
13、onacci数列数列l二维数组用例二维数组用例存储小九九表存储小九九表l字符数组用例字符数组用例SQL语句的合成语句的合成l3.3.4中的程序实例称为“Fibonacci数列”。那里使用递推公式 F1=1,F2=1,Fn=Fn-2+Fn-1计算出第n个月的兔子对数后,便将第 n-2个月的兔子对数覆盖掉了。若想保存每个月的兔子对数,则可以采用一维数组:#include int main() int f12 = 1, 1 , i; for (i=2; i12; i+) fi = fi - 2 + fi - 1; for (i=0; i12; i+) printf(第%d个月的兔子对数为%dn, i
14、 + 1, fi); return 0;l3.3.6中的程序实例只是打印出小九九表,某些情况下,需要将类似的表格存储起来(如存储矩阵),这就需要使用二维数组。/ 本例将小九九表存储于一个99的二维数组中#include int main() int A99, i, j; for (i = 0; i 9; i +) for (j = 0; j 9; j +) Aij = (i + 1) * (j + 1); return 0;lSQL语句是一种结构化数据库查询语句,广泛用于数据库中数据的查询。SQL语句中除了关键字之外,还有一些字符串需在程序运行时生成并合并到SQL语句之中:#include #
15、include int main()char ID10, sql128;printf(输入待查询学生的学号:); scanf(%s, ID);strcpy(sql, SELECT * FROM student WHERE ID=);strcat(sql, ID); strcat(sql, );printf(查询语句为:%sn, sql); return 0;l4.2.1 指针的概念指针的概念l4.2.2 指针的声明指针的声明l4.2.3 通过指针访问变量通过指针访问变量l4.2.4 指向指针的指针指向指针的指针l4.2.5 通过指针创建动态变量通过指针创建动态变量l4.2.6 指针应用实例指针
16、应用实例链表链表l实验2中,我们通过在Watch窗口分别键入地址表达式&x,&y,&z来得到x,y,z在内存中的物理地址,以便对它们在内存中的映像进行观察;在利用scanf输入数据到变量中时,写在参数表中的“&变量名”(见2.4.3)也是变量的地址。C语言中,允许通过单目取址运算符“&”得到其后的变量的地址。有时,我们想通过该地址而不是变量名来访问内存,这就需要把该地址存储在变量中。用于存储地址的变量就称为指针。l声明一个指针的语法如下:类型标识类型标识 *指针变量名指针变量名;l其中“指针变量名”为一个标识符,星号表示该标识符是一个指针,“类型标识”与
17、指针待存储的地址的变量的类型相同,即如果指针待存储的是变量的地址,而的类型是int,则指针的类型也是int:int x;/ 变量x的类型为intint *p = &x;/ 将x的地址赋给相同类型的指针l当p存储了x的地址后,我们就称p指向x。l当把一个变量的地址赋给一个相同类型的指针后,便可以通过该指针而不是变量名来访问变量,就像通过学号而不是名字也可以找到某个学生一样。以下是一个例子:int x = 3;/ 声明int型变量x并赋初值3int *p = &x;/ 将x的地址赋给同类型的指针pint y = *p;/ 引用指针p将x的值(3)赋给变量yprintf(%d %d
18、%dn, x, *p, y); / 打印出 3 3 3l指针被引用时,它前面的“*”称为“取值运算符”,它得到其后指针所指变量的值。l既然指针也是一个变量(只是用来存储地址而已),因此它也有地址,我们可把该地址存储在另一个指针中。存储指针地址的变量便称为“指向指针的指针”。例如:int x = 3; / x为int型变量int *p = &x; / p为int型指针,它指向xint *pp = &p; / pp为int型指针的指针,它指向px0012FF7C03000000p0012FF787CFF1200pp78FF1200变量x, p, pp在内存中的映像l指针所指变量并不
19、一定事先存在。我们可通过指针直接创建它所指向的变量。这种变量称为“动态变量”,即可以在使用时动态地创建、不用时加以回收。动态变量没有名字,只能通过指向它的指针引用。l创建和回收动态变量的语法分别是:指针变量名指针变量名 = (类型标识类型标识 *)malloc(变量长度变量长度);free(指针变量名指针变量名);/*例*/ int *p = (int *)malloc(sizeof(int); free(p);l使用malloc时必须包含头文件。l由于数组是用下标(代表元素在内存中的物理关系)表示元素间的逻辑关系,因此,使用数组保存成组数据有其固有的缺陷,首先,元素数目无法在使用中动态地加以
20、调整,其次,每插入和删除一个数据,都可能导致大量数据的移动操作。有了指针,我们可以创建一个链表来保存成组数据,从而实现元素插入删除操作的“零移动”:data linkdata linkdata linkdata linkdata linkdata linkdata linkdata link删除:插入:data linkl4.3.1 数组和指针的关系数组和指针的关系l4.3.2 通过指针访问已有数组通过指针访问已有数组l4.3.3 通过指针创建动态数组通过指针创建动态数组l4.3.4 指针数组和多维数组指针数组和多维数组l4.3.5 数组与指针应用实例数组与指针应用实例l数组在内存中的映像数组
21、在内存中的映像l数组名和数组元素地址数组名和数组元素地址l数组和指针似乎是两个概念,其实二者间存在着内在的联系。我们先从数组的声明和元素引用说起。假设声明了整型数组A:int A10 = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ;l则我们可通过对元素的引用打印出它的值:for (int i = 0; i 10; i+) printf(%dn, Ai);lA的元素及其地址和值在内存中的映像为:0AA012ff581A112ff5c2A212ff603A312ff644A412ff685A512ff6c6A612ff707A712ff748A812ff789A912ff7cl数组
22、名A本身有无值呢?我们来打印一下:printf(%xn, A);/ 打印结果为12ff58l这说明数组A本身也是有值的,它的值就是数组元素A0的地址&A0 = 0 x12ff58。l前面曾经说过,指针是存储地址的变量,这说明数组名本身就是一个指针,只是它的值不能被改变而已(设想如果改变了该指针的值,将会产生什么后果),即是一个指针常量(const int *A)。l通过数组运算访问数组元素通过数组运算访问数组元素l通过移动指针访问数组元素通过移动指针访问数组元素l指针运算集合指针运算集合l既然数组名是一个存储了数组第一个元素的地址的指针常量,而数组元素在内存中又是连续存放的,则我们可以
23、通过对它的常量运算(即不改变其自身值的运算)找到数组的各个元素。例如A是一个n个元素的一维数组,A指向它的第1个元素,则 A+1指向它的第2个元素,A+2 指向它的第3个元素,A+n-1指向它的最后一个元素。所以通过对A+i(0in)作取值运算*(A+i),便可取出或者改变数组各个元素的值。l虽然数组名的值不可改变,但是我们可以把它赋给一个同类型的指针变量,来改变指针的值,并通过移动指针访问数组元素:int A10 = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ;int *p = A; /将A第1个元素的地址赋给指针变量pfor (int i = 0; i 10; i +) p
24、rintf(%d,%dn, *(A+i), *p); p+; /移动指针(使其指向下一个数组元素)l执行结果是逐行打印出0,0、1,1、9,9。l作为一种特殊的无符号整型变量,C允许对指针做有限类型的运算。设A和p分别为上页声明的一维数组和指向该数组的指针,则:允许A或p加上或减去一个整数,例如:lfor (int i=0; i10; i+) printf(%d,%dn, *(A+i), *(p+i);允许对p做自加、自减或复合运算,例如:lfor (int i=0; i10; i+) printf(%dn, *p); p+=2; p-; 允许对A或(和)p做关系运算,例如:lfor (int
25、 i=0; iA+5) printf(%d,*p); p+; l我们注意到:在指针运算中,整数代表的是指针所指数组元素的数目而不是字节数目。l与通过指针创建它所指向的动态变量一样,通过指针也可以创建一个动态数组,并用该指针引用该数组,当不用时加以回收。创建和回收动态数组的语法分别是:指针名指针名 = (类型标识类型标识 *)calloc(元素数目元素数目, 长度长度);free(指针名指针名);l使用calloc时也必须包含头文件。int *p = (int *)calloc(10, sizeof(int), i;for (i = 0; i 10; i +) *(p + i) = i; /为数
26、组元素赋值09for (i = 0; i 10; i +) printf(%dn, pi); /打印出09free(p);l指针数组指针数组l动态多维数组动态多维数组l由于指针也是一种变量,因此也允许创建由多个指针变量构成的数组。声明非动态指针数组的语法是:类型标识类型标识 *指针数组名指针数组名数组元素数目数组元素数目;l例如:int *P10;l声明和创建动态指针数组的语法是:类型类型 *指针的指针名指针的指针名=(类型类型 *)calloc(元素数目元素数目, 长度长度);l例如:int *pp = (int *)calloc(10, sizeof(int);l由于指针变量可用来创建动态
27、数组,而指针数组又是由指针变量所组成,因此指针数组中的每个元素都可用来创建一个数组。若指针数组是一维的,而每个元素又延伸出一维,这样就构成了一个动态二维数组,其每行的元素数目可以是不同的。例如:int *P10; / 非动态指针数组(也可以是动态的)for (int i = 0; i 10; i +)/ 循环10次, 每次创建一 Pi = (int *)calloc(i+1, sizeof(int);/个一维数组l动态二维数组元素的引用与非动态数组相同。l数组元素反序:问题和算法数组元素反序:问题和算法l数组元素反序:程序数组元素反序:程序1.用数组下标访问元素用数组下标访问元素l数组元素反序
28、:程序数组元素反序:程序2.用数组运算访问元素用数组运算访问元素l数组元素反序:程序数组元素反序:程序3.用指针移动访问元素用指针移动访问元素l根据数据量定数组大小根据数据量定数组大小问题和算法问题和算法l根据数据量定数组大小根据数据量定数组大小程序程序l用动态二维数组存放分数用动态二维数组存放分数问题和算法问题和算法l用动态二维数组存放分数用动态二维数组存放分数程序程序l设n个元素的一维数组A的值为(a0,an-1), 试将n个值反序存放到同一数组(an-1,a0)。l算法:首先将A0与An-1的值交换,再将A1与An-2的值交换,如此进行,直到将A(n-1)/2的值与An-(n-1)/2-
29、1的值交换。以下是算法示意图:0123456789i=0j=n-1-im=(n-1)/2A0 A1 A2 A3 A4 A5 A6 A7 A8 A9#includeint main()int A10 = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ;int n = 10, m = (n - 1) / 2, i, j, temp;for (i = 0; i n; i +) printf(%dt, Ai);printf(n);for (i = 0; i = m; i +) j = n - 1 - i;temp = Ai; Ai = Aj; Aj = temp;for (i = 0; i
30、 n; i +) printf(%dt, Ai);printf(n);return 0;#includeint main()int A10 = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ;int n = 10, m = (n - 1) / 2, i, j, temp;for (i = 0; i n; i +) printf(%dt, *(A + i);printf(n);for (i = 0; i = m; i +) j = n - 1 - i;temp = *(A + i); *(A + i) = *(A + j); *(A + j) = temp;for (i = 0; i
31、 n; i +) printf(%dt, *(A + i);printf(n);return 0;#includeint main()int A10 = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ;int n = 10, m = (n - 1) / 2, i, temp;for (i = 0; i n; i +) printf(%dt, *(A + i);printf(n);int *pi, *pj;pi = &A0, pj = &An - 1;for (i = 0; i = m; i +) temp = *pi; *pi = *pj; *pj = temp;p
32、i +; pj -;for (i = 0; i n; i +) printf(%dt, *(A + i);printf(n);return 0;l在从外设(键盘、文件或数据库)读入数据之前,数据量的大小往往是未知的,这样就无法为数组定界(即无法确定元素数目)。l为了根据记录的多少来为数组定界,我们可以采取以下方法:在数据来自文件情况下,可以先扫描一遍数据文件,得到记录的数目后,再用之创建动态数组。在数据来自键盘情况下,可以先创建一个足够大的临时动态数组,将数据读入该数组,同时记录数据的个数。输入结束后,用数据个数创建动态数组并将数据倒入该数组,然后释放临时数组。#include#include#define MAXNUM 1000int main()double x, *X, *a;int i = 0, n;a = (double *)calloc(MAXNUM, sizeof(double);while (true) scanf(%lf, &x);if (x 0) break;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030车险行业发展分析及投资战略研究报告
- 2025-2030真皮旅行包行业市场现状供需分析及投资评估规划分析研究报告
- 2025-2030火电设备市场发展分析及行业投资战略研究报告
- 辽宁省鞍山市2023-2024学年高一下学期期中历史试题(解析版)
- 煤矿沿空留巷中柔模砼墙支护方案与挂模支架设计
- SAQ训练法对10至12岁青少年业余网球运动员移动速度影响的研究
- 建筑工程信息化管理与进度控制措施
- 科技公司商务合约部职责细化
- 数学教研组教师培训发展计划
- 2025年秋季学期数学课程评价与反馈计划
- 县域产业布局与升级-深度研究
- 第十六周《“粽”享多彩端午深耕文化传承》主题班会
- 日间患者流程护理质量改善项目汇报
- 创意美术网络安全课件
- 上海电信2025年度智慧城市合作协议2篇
- 2024燃煤发电企业安全生产标准化达标评级标准
- 产前检查妇产科教学课件
- 气球婚礼派对合同范例
- 2024无人机测评规范
- 术中停电应急预案
- 【高分复习笔记】许莉娅《个案工作》(第2版)笔记和课后习题详解
评论
0/150
提交评论