C语言程序设计
2002 年第六章 数 组第六章 数 组
数组,是由多个数据成员组成的 构造类型的数据 。 组成数组的数据成员称为 数组元素 。( 简单类型数据 只包含一个数据成员)
数组元素,是一些数目固定、类型相同、存储单元连续的变量。
数组元素的类型,任何类型(简单类型和构造类型的数据均可)。
用途,将相关的同类型数据集中用一个标识符(数组名)表示,同时用若干个数字序号(下标)来区别各数组元素,便于循环处理。
仅用一个数字序号确定一个元素的数组为 一维数组,需两个以上数字序号确定一个元素的数组为 多维数组 或 n维数组 。
6.1 数组的说明、引用和初始化
6.1.1 数组的说明一、一维数组的说明:
( 1)存储类型区分符 类型区分符 数组名 [长度说明 ]
( 2)存储类型区分符 类型区分符 数组名 [长度说明 ]=初值表其中:
数组名,合法 C标识符;数组名同时也是连续存储单元的首地址;
长度说明,数组元素的数目,必须是值为正整数的常量表达式;
类型区分符,数组元素的数据类型;
初值表,数组元素变量的初始值;
存储类型区分符,规定数组元素的作用域。
例 1,int a[10];
定义具有 10个整型数的数组 a.
例 2,float b[40],c[40+10];
定义具有 40个单精度浮点数的数组 b。
定义具有 50个单精度浮点数的数组 c。
例 3,#define LEN 10
char str[LEN];
定义具有 10个字符的数组 str,可用来表示最大长度为 9的字符串例 4,int size=10;
int d[size]; /*错误! 长度说明不是 常量表达式 */
二、多维数组的说明:
( 1)存储类型区分符 类型区分符 数组名 [第 1维长度说明 ]
[第 2维长度说明 ]… [ 第 n维长度说明 ]
( 2)存储类型区分符 类型区分符 数组名 [第 1维长度说明 ]
[第 2维长度说明 ]… [ 第 n维长度说明 ]=初值表 …
其中:
数组名,合法 C标识符;数组名同时也是连续存储单元的首地址;
各长度说明,必须是值为正整数的常量表达式;
类型区分符,数组元素的数据类型;
初值表,数组元素变量的初始值;
存储类型区分符,规定数组元素的作用域。
例 1:处理下列 3*2矩阵:
10 3
5 21
6 8
可定义:
int a[3][2];
具有 3行 2列(共 3*2=6个整型数)的二维数组 a.
例 2:处理多个字符串 {“SUN”,,MON”,,TUE”,
,WED”,
” THU“,” FRI“,,SAT”}
可定义:
char weekday[7][4]; /*字符串有结束标志
‘ \0?*/
6.1.2 数组的引用对数组元素的存取操作称为对数组的引用;
一、一维数组元素的引用形式,数组名 [下标 ]
例,int a[5]; /*定义具有 5个整型数的数组 a*/
5个整型数变量(习惯称为 下标变量 ),
a[0],a[1],a[2],a[3],a[4]
for(i=0;i<5;i++)
{ printf(“input a[%d]”,i); scanf(“%d”,&a[i]);
printf(“a[%d]=%d”,i,a[i]); }
注意,程序员应控制下标边界。编译系统不能处理下标越界错误。
a[0][0] a[0][1]
a[1][0] a[1][1]
a[2][0] a[2][1]
二,n维数组元素的引用形式,数组名 [下标 1] [下标 2] …[ 下标 n]
例,int a[3][2];
6个整型数,a[0][0],a[0][1],a[1][0],a[1][1],a[2][0],a[2][1]
a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1]
逻辑结构物理结构(按行存放)
下标变化规则:
第一个下标变量:数组名 [0][0]…[0]
后面下标从 0开始先变化,变化一个轮次后,回到初始值 0,同时前面下标发生变化。再开始下一个轮次。
int x[3][2][3]
18个下标变量依次为:
x[0][0][0] x[0][0][1] x[0][0][2] x[0][1][0] x[0][1][1] x[0][1][2]
x[1][0][0] x[1][0][1] x[1][0][2] x[1][1][0] x[1][1][1] x[1][1][2]
x[2][0][0] x[2][0][1] x[2][0][2] x[2][1][0] x[2][1][1] x[2][1][2]
6.1.2 数组初始化
( 1)显式初始化值的个数与说明长度相同:
int x[5]={0,1,2,3,4};
int a[2][3]={1,2,3,4,5,6};
( 2)有初始化值时,长度说明可缺省,数组长度由初值个数确定:
int y[]={1,2,3,4,5,6,7,8};
int b[][3]={1,2,3,4,5,6};
( 3)初始化值的个数小于说明长度:
int z[10]={0,1,2,3,4}; /*前 5个下标变量赋值 */
int c[3][4]={{11,12},{21},{31,32,33}};
( 4)字符数组的初始化:
char str1[10]={?a?,?b?,?c?};
char str2[10]={?a?,?b?,?c?,?\0?};
char str2[10]=“abc”;
char str3[]=“abc”; /*说明了一长度为 4的数组 */
char str3[4]={?a?,?b?,?c?,?\0?};
等价等价
6.2 数组的运算
包括:输入、输出、赋值及基本运算。
一般只能对单个下标变量运算。
一,一维数组的输入输出与赋值
int i;
float x[30];
for(i=0;i<30;i++)
scanf(%f”,&x[i]); /*对 x[i]可进行任何 float运算 */
for(i=0;i<30;i++)
printf(%8.2f”,&x[i]);
二,多维数组的输入输出与赋值
int i,j;
int x[2][3];
for(i=0;i<2;i++)
for(j=0;j<3;i++)
scanf(%d”,&x[i][j]); /*对 x[i][j]可进行任何 int运算 */
for(i=0;i<2;i++)
for(j=0;j<3;i++)
printf(%d”,&x[i][j]);
三,字符数组的输入输出与赋值
char str1[30],str2[20]=“string2”;
scanf(“%s”,str1);
printf(“%s”str1);
四,字符串数组的输入输出与赋值
char weekday[7][4];
int i;
for(i=0;i<7;i++) /*输入时,必须控制字符长度小于 4*/
scanf(“%s”,weekday[i]);
for(i=0;i<7;i++)
printf(“%s”,weekday[i]);
例 6.1:计算 10个学生的平均成绩,以及每个人的成绩与平均成绩之差。
解法 1,用简单变量实现。
#define NUMBERS 10
main(){
float x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,sum,average;
scanf(“%f %f %f %f %f %f %f %f %f %f”,
&x1,&x2,&x3,&x4,&x5,&x6,&x7,&x8,&x9,&x10)
sum=x1+x2+x3+x4+x5+x6+x7+x8+x9+10;
average=sum/NUMBERS;
printf(“average=%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f”,
average,x1- average,x2 - average,x3 - average,x4 - average,
x5 - average,x6 - average,x7 - average,x8 - average,x9 -verage,
x10 - average);
}
解法 1,用数组实现。 当学生数变化时,仅修改 NUMBERS
#define NUMBERS 10
main(){
int i;
float x[NUMBERS],sum=0,average;
printf(“input %d score”; NUMBERS);
for(i=0;i< NUMBERS;i++) { /*一边输入,一边累加求和 */
scanf(“%f”,x[i]);
sum+=x[i]; }
average=sum/NUMBERS;
printf(“average=%.2\n”,average);
for(i=0;i< NUMBERS;i++)
printf(“x[%d]-average=%.2\n”,i+1,x[i]-averager);
}
例 6.2:输入 n个数,将它们按从小到大排序后输出分析:输入 n个数存放在一数组中,便于循环处理;
排序方法:冒泡排序法。
void sort(int V[],int n)
{ 对 V[n]表示的 n个整数进行排序处理
}
main()
{ 输入 n个数;
调用 sort对 n个数排序;
输出 n个数检验排序效果
}
原序列,10 3 7 8 5 2 1 4 9 6
第 1遍,(n=10个数的一遍处理,n-1=9次比较(交换) )
1,10 3 7 8 5 2 1 4 9 6
2,3 10 7 8 5 2 1 4 9 6
3,3 7 10 8 5 2 1 4 9 6
4,3 7 8 10 5 2 1 4 9 6
5,3 7 8 5 10 2 1 4 9 6
6,3 7 8 5 2 10 1 4 9 6
7,3 7 8 5 2 1 10 4 9 6
8,3 7 8 5 2 1 4 10 9 6
9,3 7 8 5 2 1 4 9 10 6
3 7 8 5 2 1 4 9 6 10
原序列,10 3 7 8 5 2 1 4 9 6
第 1遍完,3 7 8 5 2 1 4 9 6 10
第 2遍完,3 7 5 2 1 4 8 6 9 10
第 3遍完,3 5 2 1 4 7 6 8 9 10
第 4遍完,3 2 1 4 5 6 7 8 9 10
第 5遍完,2 1 3 4 5 6 7 8 9 10
第 6遍完,1 2 3 4 5 6 7 8 9 10
第 7遍完,1 2 3 4 5 6 7 8 9 10
第 8遍完,2 1 3 4 5 6 7 8 9 10
第 9遍完,1 2 3 4 5 6 7 8 9 10
void sort(int v[],int n)
{ int i,j,temp;
for(i=0;i<n-1;i++) /*控制 n-1遍处理 */
for(j=0; j<n-i-1;j++) /*控制第 i遍时的 i-1次比较 */
if (v[j]>v[j+1]) /*确定是否交换数据 */
{temp=v[j];v[j]=v[j+1];v[j+1]=temp}
}
#include,stdio.h”
#define N 10
void main()
{
int a[N],i;
printf(“input %d numbers:\n”,N);
for(i=0;i<N;i++)
scanf(“%d”,&a[i]);
sort(a,N);
for(i=0;i<N;i++)
printff(“%4d”,a[i]);
}
a[0] 10
a[1] 3
a[2] 7
a[3] 8
a[4] 5
a[5] 2
a[6] 1
a[7] 4
a[8] 9
a[9] 6
a v
n 10v[0]
v[1]
v[2]
v[3]
v[4]
v[5]
v[6]
v[7]
v[8]
v[9]
a和 v共同对同一连续存储单元进行操作
6.4 字符串处理函数编译环境中定义了常用字符串处理标准库函数,头文件为
string.h
(1)strcpy(char t[],char s[])---s的串值复制到 t中。
char str[10];
strcpy(str,"data");
printf(“%s”,str); 输出为,t="data“
(2)strlen(char s[])----求 s的长度
printf(“%d”,strlen(“data*123”)); 输出,8
(3)strcat(char s1[],char s2[])----s2的值接到 s1的后面。
char s1[20]="data",s2[10]="123"
strcat(s1,s2); printf(“s1=%s,s2=%s”,s1,s2);
输出,s1="data123",s2="123“
(4)strcmp(char s1[],char s2[])---比较 s1和 s2的大小若 s1<s2,返回负整数 如,strcmp("ABC","abc")
若 s1=s2,返回 0如,如,strcmp("abc","abc")
若 s1>s2,返回正整数 如,strcmp("ABCD“,"ABC“)
注意:不能用,ABCD“==”ABC“的形式比较字符串。
(5) strstr(char s1[],char s2[])----若 s2是 s1的子串,则指向 s2在 s1中第 1次出现时的第 1个字符的地址,否则返回 NULL。
char s1[20]="ABE123*DE123bcd";
char s2[]="E123";
strstr(s1,s2) 得到第一个 E123的字符 ‘ E?的地址。
例:定义一个函数,该函数从一个字符中删去与给定字符相同的全部字符,并压缩字符串。
(在下面字符串中去掉‘ e?)
H e i s s t u d e n t?\0?
s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9] s[10] s[11] s[12] s[13]
j:写 指示器
i:读指示器
H i s s t u d n t?\0? t?\0?
s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9] s[10] s[11] s[12] s[13]
j:写 指示器读指示器,i
void squeeze(char s[],char c)
{
int i=0,j=0;
while (s[i]!=?\0?)
{
if (s[i]!=c)
{
s[j]=s[i];
j++; /*写指示器指向下一空位 */
}
i++; /*读指示器指向下一位置 */
}
s[j]=?\0?; /*写字符串结束标记 */
}
main()
{ char str[]=“He is student”;
squeeze(str,?e?);
printf(“%s”,str); }
s[i]≠?\0?
非 0
0
squeeze
结束
0?j
s[i]?s[j]
0?i
s[i]≠c
j++
非 0
0?\0s[j]
i++
例:定义将 一个 字符串反转的函数。例如字符串 abcd反转后为 dcba;
#include,string.h”
void reverse(char s[])
{
int c,i,j;
for(i=0,j=strlen(s)-1;i<j;i++,j--)
{c=s[i];s[i]=s[j];s[j]=c}
}
a b c d e f g h i?\0?
s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] s[8] s[9] s[0] s[10]
ji
例:定义字符串比较函数,如果两字符串相等,返回 0;
如果第一个 字符串大于第二个字符串,返回值大于 0;如果第一个 字符串小于第二个字符串,返回值小于 0;
int strcmp(char s[],char t[])
{
int i=0;
while (s[i]==t[i]&&s[i]!=?\0?)
++i;
return (s[i]-t[i]);
}
strcmp(“abc”,”abde”)
返回‘ c?-?d?的值
strcmp(“abf”,”abde”)
返回‘ f?-?d?的值
strcmp(“abc”,”abc”)
返回‘ \0?-?\0?的值
strcmp(“abc”,”abcdef”)
返回‘ \0?-?d?的值