Transcript Document
C语言程序设计 第七章 数组 主讲教师:李艺 [email protected] 主要内容 7.1 一维数组 7.2 字符数组与字符串 7.3 多维数组 7-2 概述 我们已经熟悉了整型、浮点型、字符型数据。本章要 介绍构造类数据 -- 数组。构造类数据是由上述基本类型 数据按一定规则排序构成的数据集合体。是C语言的重要 内容。构造类型数据有: 数组类型; 结构体类型; 共用体类型。 7-3 7.1 一维数组 一维数组的定义格式 数据类型 数组名[元素个数]; 说明 数据类型:指数组元素的类型。有int型、 float型、 char型。 数组名:代表一个数据集合的数组的名字。 下标: 用方括号即“[ ]”届定。不能用圆括号和花括号,下标值 从0开始计数。 元素个数:数组包含数据的个数。元素个数必须是大于或等于1 的整数。 数组必须先定义,后使用。 7-4 7.1 一维数组 例1:例: int data[4]; 该数组有4个元素,它们是: data[0] data[1] data[2] data[3] 我们然后可以象普通变量一样使用数组: data[1] =10; data[2] =12; data[3] = data[1] + data[2] * 2; printf (“%d”; data[3]); 7-5 7.1 一维数组 例2:请看下列程序段有什么错误: int x; int weight[x]; // 元素个数不能用变量来定义。应该是常量 char name(50); // 下标符不能用圆括号 int num[-5]; // 元素个数不能定义成负数。 float deptname[x+15]; //定义数组不能用变量表达式。只能用常量 表达式 int array[10.5]; //元素个数不能用小数定义 7-6 7.1 一维数组 例3: #define BUFSIZE 512 // 宏定义,用指定的标识符来代替后面的数字 #define STACKSIZE 24 // 宏定义 int inbuffer[BUFSIZE]; //等效为 inbuffer[512]; 在编译时进行替换 char outbuffer[STACSIZE]; //等效为 outbuffer[24]; 在编译时进行替换 float s[15+5],x[10]; 7-7 7.1 一维数组 数组元素的存储和使用 每个数组元素都占用内存中的一个存储单元,每个元素都是一个变量, 可以像以前讲过的普通变量一样使用,只不过数组元素是通过数组名和 方括号“[ ]”里的下标来确定的。 系统为数组元素在内存中分配连续的存储单元。 例: int a[5]; 内存地址 数组名a。 数组元素的数据类型为int整型数据。 数组元素的下标值从0开始。 数组元素的个数为15个,它们是: a[0]、a[1]、a[2] .. ..a[13]、a[14] 2000 2002 2004 2006 2008 内存 数组元素 a[0] a[1] a[2] a[3] a[4] 数组名a是数组存储区的首地址,即存放数组第一个元素的地址。 a&a[0];因此数组名是一个地址常 量。不能对数组名进行赋 值和运算。 7-8 7.1 一维数组 数组的使用 就是对数组元素的读写操作。使用数组与使用普通变量类似, 也是先定义后使用。与变量不同的是不能对数组整体进行(读取) 操作,只能对数组的元素进行操作。 一维数组的引用格式 数组名 [ 下标 ] 说明 下标可以是常量或常量表达式。 下标可以是变量,也可以是表达式。 下标如果是表达式, 首先计算表达式, 计算的最终结果为下标值。 下标值若不是整型,C系统会自动取整。 下标值从0开始。而不是从1开始。 使用数组时,下标不能超过或等于定义时的下标值。 7-9 7.1 一维数组 例4: int a[10],i,p; i=2; a[2*i-1]=1; //√下标为变量表达式。 a[5]=1; //√对数组a的第六个元素a[5]赋值1 p=a[5]; //√将数组a的第六个元素a[5]的值赋给变量p a[10-10]=1; // √将1赋给数组a的第一个元素a[0]。 a=11; // ×不能对数组整体进行读写,即不能对数组名读写 printf(“a=%d”,a); // ×同上 a[10]=a[0]-a[1]; // ×下标超限 7-10 7.1 一维数组 一维数组的初始化 数组的初始化就是在定义数组的同时给各数组元素赋初值。初始化是 在程序运行前编译时完成的。 一维数组初始化的格式 数据类型标识符 数组名[元素个数]={ 数值1,数值2,.. ..数值n }; 花括号{ }中的数值用于数组元素赋初值。赋值是按对应次序进行。 花括号{ }中的数值之间用逗号“,”分开。如: int x[5]={ 1,2,3,4,5 }; 则数 组中各元素的初始值为: x[0]=1, x[1]=2, x[2]=3, x[3]=4, x[4 ]=5。 数值的个数要等于数组所定义的元素个数 花括号{ }中数值的个数如果少于数组元素的个数,则多余的数组元素初 始化的数值为0。如: int x[5]={ 3,4,7 }; 则数组中各元素的初始值为: x[0]=3, x[1]=4, x[2]=7, x[3]=0, x[4]=0。 花括号{ }中数值的个数多于数组元素的个数是语法错误。 7-11 7.1 一维数组 在数组初始化中,可缺省方括号中的下标值(元素个 数) , 数组元素个数由花括号中所赋初始值的数值个数 来决定。 如: int y[ ]={ 6,4,1,7,8,10 }; 等价于 int y[6]={ 6,4,1,7,8,10 }; 对于存储类型为static静态或extern外部类型的数组, 如果不在定义时进行赋值, 则多数编译系统都将其值初 始化为0。 如: static int x[3]; 则数组各元素的初值为: x[0]=0, x[1]=0, x[2]=0。 7-12 7.1 一维数组 一维数组的应用举例 #include "stdio.h" void main( ) { int a[ ]={1,2,3,4}; int i,j,s; for( i=3,j=1,s=0; i>=0; i-- ) { s=s+a[ i ]*j; j=j*10; } printf("s=%d\n",s); } 分析: 循环变量 i=3: i=2: i=1: i=0: s=s+a[i]*j j=j*10 s=4, j=10; s=34, j=100; s=234, j=1000; s=1234, j=10000。 运行程序: s=1234 7-13 7.1 一维数组 编程:计算一维数组中所有元素的平均值。 #include “stdio.h” void main() { int i; static int x[]={10,8,7,6,5,4,3,2}; float average=0; for(i=0;i<8;i++) average+=x[i]; average/=8; printf(“The average is %f”, average);} 运行结果为: 5.625000 7-14 7.1 一维数组 用冒泡法对 6 个数排序(由小到大)。冒泡法思路:比较相邻两数, 将小的调到前头。 开始 9 ㈠ 9 89 ㈡ 8 58 ㈢ 5 4 0 0 0 2 2 2 4 4 4 5 5 5 5 80 8 8 8 8 9 9 9 9 9 845 2 5 5 4 9 824 0 4 4 2 9 802 2 09 2 9 90 结果 2 95 8 0 4 ㈤ 2 8 8 ㈣ 5 4 共循环多少次? 每次循环进行了多少次比较?什么时候结束? 如果要求先将最小的数排在最前面,该如何操作? 7-15 7.1 一维数组 #include <stdio.h> #define N 6 void main ( ) { int a[N+1]; int i , j, t ; printf ("input %d numbers:\n", N); for ( i = 1; i <= N; i++) scanf ("%d", &a[i] ); for ( j = 1; j < N; j++) for ( i = 1; i <= N - j; i++) if ( a[i] > a[i+1] ) { t = a[i]; a[i] = a[i+1]; a[i+1] = t; } printf ("the sorted numbers:\n"); for ( i = 1; i <= N; i++) printf ("%d ", a[i] ); printf ("\n"); } 7-16 7.1 一维数组 例:求20个数的最大值。 1. 设一个 a[20],max,i 2. 设max=a[0] 3. 用循环求最大值 void main( ) { int a[20],i,max; for(i=0;i<20;i++) scanf(“%d”,&a[i]); max=a[0]; for(i=1;i<20;i++) if(max<a[i]) max=a[i]; printf(“max=%d\n”,max); } 7-17 7.2 字符数组与字符串 字符数组 前面介绍的都是数值型数组,即数组元素都是数值。本节中的 数组,其每个元素都是一个字符,即char类型。除此之外,它与前 面讲的数组没有区别。 前面介绍的数组的定义、数组的存储形式和数组的引用等都适 用于字符型数组。 字符型数组的定义 char 数组名[字符个数]; 为每个数组元素赋值 前面讲过,在C语言中,字符必须要用单引号括起来。 输出每个数组元素 输入时,采用%c的格式;输出时也采用%c的格式。 7-18 7.2 字符数组与字符串 例:编写程序将Good luck存放在一维数组中,并输出。 #include <stdio.h> void main() { char a[9]; int i=0; a[0]='G'; a[1]='o'; a[2]='o'; a[3]='d'; a[4]=' '; a[5]='l'; a[6]='u'; a[7]='c'; a[8]='k'; for(i=0;i<9;i++) printf("%c",a[i]); } 运行结果为: Good luck 7-19 7.2 字符数组与字符串 字符型数组用于存放字符或字符串, 每一个数组元素存放一个字符 (的ASCII码), 它在内存占用一个字节的空间。 用于存放单个字符的字符数组和字符变量的作用相同, 但表达形式不 同。 例: char c; char c[1]; 字符数组初始化 char a[9]={'G','o','o','d',' ','l','u','c','k'}; //初始化字符数组a:9个字符 依次赋给a[0]~a[8] char b[9]={‘G’,‘o’,‘o’,‘d’}; //数据个数少于数组元素个数,多余的数 组元素初始化为空字符’\0’;反之,系统报错 char d[9]; //没有初始化,对于静态型和外部型数组元素初始化 为’\0’,而自动型数组元素的值不确定 7-20 7.2 字符数组与字符串 字符串 用双引号括起来的一串字符称为字符串。C语言用字 符数组来处理字符串。存放字符串时,在有效字符后 面要有一个字符’\0’,作为字符串的结束标志。 定义字符串数组时,元素个数要比字符串的字符个数 多1个,以保存字符串结束标志符‘\0’。 #include <stdio.h> 运行结果为: main() { char a[10]; /*定义字符数组*/ Well done int i=0; a[0]='w'; a[1]='e'; a[2]='l'; a[3]='l'; a[4]=' '; /*为每个元素赋值*/ a[5]='d'; a[6]='o'; a[7]='n'; a[8]='e'; a[9]='\0'; for(i=0;i<=9;i++) /*输出每个数组元素的值*/ printf("%c",a[i]); 7-21 } 7.2 字符数组与字符串 字符串数组的初始化 即在定义字符串数组的同时进行赋值。有两种方法。 用字符常量初始化数组,例如: char str[6]={ ‘ C’, ‘ h’, ‘i’, ‘ n’, ‘ a’, ‘ \0’ }; 用花括号括将赋值的字符常量括起来。数组str[6]被初始化为: “ China ”。 用字符串常量初始化数组,例如: char string[6]=“China”; 用字符串常量初始化数组时, 可不用花括号。若字符个数少于 数组长度,程序都自动在末尾字符后加‘\0’。 7-22 7.2 字符数组与字符串 用字符串常量初始化时,字符数组的下标也可以省略, 其数组存放字符的个数由赋值的字符串的长度决定。 例如: char str[ ] = {“1a2b3c”}; 等价于 char str[7] = {“1a2b3c”}; 初始化时,若字符个数与数组长度相同,则字符末尾不 加‘\0’,此时字符数组不能作为字符串处理,只能作字 符逐个处理。初始化时是否加‘\0’要看是否作为字符串 处理。 7-23 7.2 字符数组与字符串 字符串处理函数 C 语言标准库函数中, 提供了大量字符串的操作函数, 包括: 字 符型数组的输入/输出函数和字符串处理函数 字符型数组的输入/输出 1. 用getchar( ) 对字符数组进行键盘输入。调用格式: getchar ( ); 例:char c[15]; for(i=0;i<14;i++) c[i]=getchar( ); 2. getchar( )一次只能从键盘接收一个字符。 用gets( ) 对字符串数组进行键盘输入。格式:gets (字符 串数组名); 例:char string[15]; gets(string); 7-24 7.2 字符数组与字符串 3. 用scanf( ) 对字符数组进行赋值。 从键盘读取一个字符:scanf(“%c”, 数组元素地址); 从键盘读取一串字符:scanf(“%s”, 数组名); 例:char c[15]; 字符串输入结束标志: 空格、TAB、回车 for(i=0;i<15;i++) scanf(“%c”,&c[i]); // 逐个赋值 例:char c[15]; scanf(“%s”,c); 或 scanf(“%s”,&c[0]) // 成批赋值 当在键盘输入完要输入的字符串时, 字符数组自动包含 一个‘ \0 ’结束标志。 scanf ( )的格式要求操作数是地址。但 scanf (“%s”, & c ) ; 的写法是不正确的。此时是字符数组, 对其操作 不能加地址运算符号。因为, 字符数组名是字符串第一 个字符的地址, 是地址常量。 7-25 7.2 字符数组与字符串 4. 用putchar ( ) 输出字符数组中的内容。putchar (字符名); 例:char c[20]=“Microsoft PowerPoint ”; for(i=0;i<20;i++) putchar(c[i]); putchar( )一次只能向屏幕输出一个字符。 5. 用puts( )输出字符数组中的内容。puts (字符串数组名); 例:char string[11]=“Microsoft”; puts(string); puts函数将字符数组sring中的所有字符输出到屏幕上, 遇‘\0’结束。 7-26 7.2 字符数组与字符串 6. 用printf ( ) 输出字符、字符串数组中的内容 输出一个字符:printf(“%c”, 数组元素); 输出一个字符串:printff(“%s”, 数组名); printf ( )语句输出字符串数组时, 可以直接引用字符串 数组名。因为, 字符串数组存放的是字符串第一个字符 的地址码。遇‘\0’结束! 7-27 7.2 字符数组与字符串 数值型数组和字符数组的输入输出在使用中的区别 数值型数组: int data[4],i; for(i=0;i<4;i++) scanf(“%d”,&data[i]); for(i=0;i<4;i++) printf(“%d ”,data[i]); // 循环输入每一个数组元素 字符数组: char str[20]; scanf(“%s”, str); //变量名前没有取地址符& printf(“%s\n ”,str); //直接输入数组变量变量名 7-28 7.2 字符数组与字符串 例 将从键盘上输入的字符串的小写字符变成大写字符, 并输出。 设:输入的字符串存入字符数组string[ ]中。 #include “stdio.h” void main( ) { char string[25]; int i; printf(“\n Enter a string :”); scanf(“%s”,string); i=0; while(string[i]!=‘\0’) { if(string[i]>=‘a’&&string[i]<=‘z’) string[i]=string[i]-‘a’+‘A’; i++; } printf(“\n %s”, string); } 运行程序 abCdeFGhijkLMN←┘ ABCDEFGHIJKLMN 7-29 7.2 字符数组与字符串 例输入一个字符串,求其长度。 分析:1) 设 字符数组 str[30] 2) 设变量 i =0 3) str[i]!=‘\0’ i++ #include “stdio.h” void main( ) { int i=0; char str[30]; printf(“\n请输入一个字符串:"); gets(str); while(str[i]!='\0') i++; printf(“字符串长度为:%d", i ); } 运行程序 请输入一个字符串: c language←┘ 字符串长度为:10 7-30 7.2 字符数组与字符串 字符串处理函数 1. gets( )和puts( ) 字符串输入/输出函数 2. strcpy( ) 字符串考贝函数,包含在string.h库文件中,下同。 形式:strcpy(目的字符数组,源字符串); 作用:将源字符串拷贝到目的字符数组中,遇到源字符串的终 止符’\0’为止。 函数返回值:目的字符数组的地址。 #include<stdio.h> #include "string.h" void main( ) { char s[10],sp[ ]="HELLO"; strcpy(s,sp); s[0]='h'; s[6]='!'; puts(s); } 运行结果: hELLO 7-31 7.2 字符数组与字符串 如果只需考贝字符串的一部分,可用函数: strncpy(目的字符数组, 源字符串, 拷贝字符数) #include<stdio.h> #include "string.h" void main( ) { char s[ ]=“This is a source string.”; char b[20]; strncpy(b,s,16); b[16]='\0'; printf("%s\n",b); } 运行结果: This is a source 7-32 7.2 字符数组与字符串 3. strcat( ) 字符串连接函数 形式:strcat(目的字符数组,源字符串); 作用:将源字符串连接到目的字符数组后面。出错,因为数组b 长度定义不够 函数返回值:目的字符数组的地址。 #include<stdio.h> #include "string.h" void main( ) { char a[ ]="abcde"; char charb[11 b[ ]="12345"; ]="12345"; strcat(b,a); printf("%s,%s\n",a,b); } 运行结果: de, 12345abcde 运行结果: abcde, 12345abcde 将数组b长度定义 成11 7-33 7.2 字符数组与字符串 4. strcmp( ) 字符串比较函数 形式:strcmp(字符串1,字符串2); 作用:对两个字符串从各自第一个字符开始进行逐一比较, 直到对应字符不相同或到达串尾为止。 函数返回值: 小于0 __ 字符串1小于字符串2; 等于0 __ 字符串1等于字符串2; 大于0 __ 字符串1大于字符串2。 7-34 7.2 字符数组与字符串 例 输入四个字符串,将ASCII值最大的字符串输出。 #include<stdio.h> #include "string.h" void main( ) { int i; char str[10],temp[10]=“\0"; for ( i=0; i<4; i++) { gets(str); if(strcmp(temp,str)<0) strcpy(temp,str); } puts(temp); } 运行结果: apple cut mobile manager mobile 7-35 7.2 字符数组与字符串 5. strlen( ) 字符串长度函数 形式:strlen(字符串) 作用:求字符串的实际字符个数(不包括’\0’) 函数返回值:实际字符个数 #include<stdio.h> #include "string.h" void main( ) { char a[ ]="\t\r\\\0will\n"; printf( "%d,%d", sizeof(a), strlen(a) ); } 运行程序 10, 3 7-36 7.3 多维数组 下标个数大于1的数组叫多维数组。数组名后有两个下标的数组 叫二维数组,例:int x[2][3]; 有三个下标的数组叫三维数组。 多维数组的定义 定义: [数据存储] 数据类型 数组名[下标1][下标2]…[下标n]; 说明 1. 数据存储、数据类型、数组名的说明:同一维数组。 2. 下标:和一维数组不同的是有两个方括号,注意不能写成 “int c[2,3];”。 3. 数组元素个数为: 下标1下标2 .. .. 下标n 。 例:int x[2][3]; x 是二维数组,有6个元素 (2×3=6),它们是: x[0][0], x[0][1], x[0][2], x[1][0], x[1][1], x[1][2]。 其全部元素数值均为 int 型。 7-37 7.3 多维数组 多维数组的初始化 方法一: int a [2] [3] = { { 1, 2, 3 }, { 4, 5, 6 } }; 等价于: int a [2] [3]; a [0] [0] = 1; a [0] [1]=2; a [0] [2]=3; a [1] [0] = 4; a [1] [1]=5; a [1] [2]=6; 方法二:将所有数据写在一个花括弧里,按数组排列顺序给各元 素赋值。 如:int a [2] [3]= { 1, 2, 3, 4, 5, 6 } ; 方法三: int x[ ] [ 3 ]= { 1, 2, 3, 4, 5, 6 }; 即第一下标值省略,但第二下标值不能省略!!! 方法四:还可以只对部分元素赋值, 如:int a[2][3]= { {1, 2, }, { 4, 5 } }; 结果为a[0][0]=1; a[0][1]=2; a[1][0]=4; a[1][1]=5; 7-38 7.3 多维数组 例 求矩阵a和b相加。矩阵相加的条件:两矩阵行数、列数必须相等。 #include<stdio.h> void main( ) { int a[2][3]={ {1,2,3}, {4,5,6} }; int b[2][3]={ {1,2,3}, {4,5,6} }; int i,j,c[2][3]; for(i=0;i<2;i++) for(j=0;j<3;j++) c[i][j]=a[i][j]+b[i][j]; printf("a + b = \n"); for(i=0;i<2;i++) { for(j=0;j<3;j++) printf("%-5d",c[i][j]); printf("\n"); } } 已知: a = 1 2 4 5 3 6 已知: b= 1 2 4 5 3 6 运行结果: a+b= 2 4 6 8 10 12 7-39 7.3 多维数组 多维数组的存储与使用 多维数组每维的下标值都从0开始,最先变化的是最右边的下 标。在内存中按下标顺序,依次存储在内存的连续空间。 例如:int x[2][3]; 为数组X分配了2字节×6=12个字节 先存放第一行,即 x[0][0], x[0][1], x[0][2], 再存放第二行,即 x[1][0], x[1][1], x[1][2]. X[0][0] X[0][1] X[0][2] X[1][0] X[1][1] X[1][2] 二维数组的存储 7-40 7.3 多维数组 多维数组元素的读取操作 同一维数组一样,先定义、后使用; 不能对一个多维数组的整体进行使用,只能对具体的数组元素进 行使用。 二维数组的引用格式:数组名[下标1][下标2] 说明 下标可以是常量(大于等于0)、常量表达式、变量或表达式。 数组中要特别注意每一维下标都不能越限。因为有的程序编译系 统不检查数组下标越限问题,应特别注意。 7-41