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