1、第4章 数组 4.1内容概述 本章主要介绍了数值数组和字符数组的定义、初始化、元素引用和数组数据的输入与输出,字符数组实现字符串、字符串函数的实现与调用。指针数组与数组指针定义、元素引用。利用一维数组实现如挑数、排序、求和等实际应用问题。利用二维数组实现矩阵的应用问题。利用字符数组实现字符串的各种操作。本章知识结构如图4.1所示。 数组 数值数组 定义 初始化 元素引用 数组元素输入和输出 指针数组 定义 初始化 应用 字符数组 定义 初始化 元素引用 数组元素输入和输出
2、 图4.1 第4章知识结构图 考核要求:掌握一维数组、二维数组、字符数组和指针数组的定义和初始化;掌握数组元素存储地址计算;掌握数组元素的下标法、指针法引用;掌握字符数组与字符串的区别与联系;掌握有关字符串处理函数的使用方法;能利用一维数组、二维数组解决向量、矩阵等实际应用问题。 重点难点:本章的重点是一维数组、二维数组和字符数组的定义、初始化、元素引用,字符串处理函数的使用。本章的难点是字符串与字符数组的区别,指针数组和数组元素的指针法引用。 核心考点:数组的定义、初始化和数组元素的引用方法,一维数组、二维数组和字符数组的实际应
3、用,字符串的处理方法。 4.2 典型题解析 【例4.1】以下对一维数组a的定义中正确的是( )。 A. char a(10); B. int a[0..100]; C. int a[5]; D. int k=10;int a[k]; 解析:一维数组定义的一般形式为: 类型标识符 数组名[常量表达式] 其中,常量表达式可以是任意类型,一般为算术表达式,其值表示数组元素的个数,即数组长度。 答案:C 【例4.2】以下对一维数组的定义中不正确的是( )。 A. double x[5]={2.0,4.0,6.0,
4、8.0,10.0}; B. int y[5]={0,1,3,5,7,9}; C. char ch1[ ]={'1', '2', '3', '4', '5'}; D. char ch2[ ]={'\x10', '\xa', '\x8'}; 解析:可以对一维数组的全部元素或部分元素赋初值。在对全部数组元素初始化时,数组长度可以省略。若数组长度没有省略,则初始化列表中值的个数不能超过数组的长度。 答案:B 【例4.3】以下对二维数组的定义中正确的是( )。 A.int a[4][]={1,2,3,4,5,6}; B. int a[][3]; C.
5、int a[][3]= {1,2,3,4,5,6}; D. int a[][]={{1,2,3},{4,5,6}}; 解析:定义二维数组时,若按一维格式初始化,则第一维的长度可以省略,此时,系统可根据初始化列表中值的个数及第二维的长度计算出省略的第一维长度,但无论如何,第二维的长度不能省略。没有初始化时,每一维的长度都不能省略。 答案:C 【例4.4】假定一个int型变量占用两个字节,若有定义:int x[10]={0,2,4}; 则数组x在内存中所占字节数是( )。 A. 3 B. 6 C. 10 D.
6、20 解析:一维数组在内存中所占的字节数为:数组长度×sizeof(元素类型)。 答案:D 【例4.5】以下程序的输出结果是( )。 main() { int a[4][4]={{1,3,5},{2,4,6},{3,5,7}}; printf("%d%d%d%d\n",a[0][3],a[1][2],a[2][1],a[3][0]); } A. 0650 B. 1470 C. 5430 D. 输出值不定 解析:定义的数组a为4行4列,且前三行三列元素已初始化,根据C语法规定,未初始化的元素值为0。 答案:A 【例
7、4.6】以下程序的输出结果是( )。 main() { int m[][3]={1,4,7,2,5,8,3,6,9};int i,j,k=2; for(i=0;i<3;i++){ printf("%d ",m[k][i]);} } A. 4 5 6 B. 2 5 8 C. 3 6 9 D. 7 8 9 解析:根据初始化列表中值的个数和第二维的长度,可求得第一维长度为3。第一行的元素值依次为1,4,7;第二行元素值依次为2,5,8;第三行元素值依次为3,6,9。循环执行三次,依次输出行标为2的三个元素,即第三行的3个元素。 答案:C
8、 【例4.7】以下程序的输出结果是( )。 main() { int b[3][3]={0,1,2,0,1,2,0,1,2},i,j,t=0; for(i=0;i<3;i++) for(j=i;j<=i;j++) t=t+b[i][b[j][j]]; printf("%d\n",t); } A. 3 B. 4 C. 1 D. 9 解析:程序中,引用的b数组元素的行下标为循环变量i,列下标为数组元素b[j][j]。外层循环共进行3次,对于每次外循环,内层循环只执行一次(即j=i),所以
9、变量t 的值为元素b[0][b[0][0]]、b[1][b[1][1]]、b[2][b[2][2]]的和。由于数组元素b[0][0]、b[1][1]、b[2][2]的值分别为0、1、2,所以t的值为:0+0+1+2=3。 答案:A 【例4.8】若有定义:int a[2][4];,则引用数组元素正确的是( )。 A. a[0][3] B. a[0][4] C. a[2][2] D. a[2][2+1] 解析:引用二维数组元素时,行下标范围为0~行数-1,列下标范围为0~列数-1。 答案:A 【例4.9】若有定义:int aa[8];,则不能代表
10、数组元素aa[1]地址的是( ) 。 A. &aa[0]+1 B. &aa[1] C. &aa[0]++ D. aa+1 解析: &aa[1]、&aa[0]+1和aa+1都是数组元素aa[1]的地址。由于&aa[0]是地址值常量,不能进行自加、自减运算,所以选项C不能代表aa[1]地址。 答案:C 【例4.10】下列程序执行后的输出结果是( ) 。 main() { int a[3][3], *p,i;p=&a[0][0]; for(i=0;i<9;i++) p[i]=i+1; printf("%d \n",a[1][2]); }
11、 A. 3 B. 6 C. 9 D. 随机数 解析:二维数组的物理存储结构为一维,即按行序顺序存储在连续存储空间中。 本题中,p为指向数组元素的指针变量,初始时,p指向a[0][0]。通过指针p实现对对二维数组元素按行依次赋值。a[1][2]即p[5],其值6。 答案:B 【例4.11】下列程序的输出结果是( )。 main() { char a[10]={9,8,7,6,5,4,3,2,1,0},*p=a+5; printf("%d",*--p); } A. 运行出错 B.
12、 a[4]的地址 C. 5 D. 3 解析:初始时,p指向a[5]。由于单目运算符的结合方向为右结合,所以,*--p等价于*(--p),即先执行--p,p指向a[4],再输出a[4]的值(5)。 答案:C 【例4.12】若有如下定义,则b的值是( )。 int a[10]={1,2,3,4,5,6,7,8,9,10},*p=&a[3],b=p[5]; A. 5 B. 6 C. 8 D. 9 解析:p指向a[3],即p=a+3;b=p[5
13、],即b=*(p+5)。因此,b=*(a+8)=a[8]=9。 答案:D 【例4.13】若二维数组y有m列,则排在y[i][j]前的元素个数为( ) A.j*m+i B.i*m+j C.i*m+j-1 D.i*m+j+1 解析:C语言中的二维数组按行存储。行标为i的元素前共有i行元素,元素个数为i*m,每行列标为j的元素前共有j个元素。因此,y[i][j]前的元素个数为i*m+j。 答案:B 【例4.14】若有定义:char a[10],*b=a;,则不能给数组a输入字符串”This is a book”的语句是( )。 A. gets(a
14、) B. scanf("%s",a) C. gets(&a[0]); D. gets(b) ; 解析: gets为字符串输入函数,调用该函数时需给出字符串的存储地址,以回车作为字符串输入的结束,并将回车符转换成为’\0’。而scanf函数则以回车、空格或跳格作为串输入结束,因此scanf不能输入有空格的字符串。 答案:B 【例4.15】以下程序执行后的输出结果是( )。 A. 2 B. 3 C. 4 D. 5 #include "string.h" main( ) { char *p
15、[10]={ "abc","aabdfg","dcdbe","abbd","cd"}; printf("%d\n",strlen(p[4])); } 解析:定义了一个含有10个元素的字符指针数组p,并对前5个元素初始化,其中p[4]指向字符串"cd",其串长为2。 答案:A 【例4.16】若定义一个名为s且初值为"123"的字符数组,则下列定义错误的是( )。 A.char s[]={’1','2','3','\0 '}; B.char s[]={"123"}; C.char s[]={"123\n"}; D.char s
16、[4]={'1','2','3'}; 解析:字符数组中所存字符中有’\0’时,字符数组才能作为字符串使用。选项A是用字符常量对字符数组初始化,且最后一个元素的值为字符串结束标记(’\0’),所以数组s中存放的就是字符串"123";选项D是用字符常量对部分元素初始化,根据 C语言的规定,系统为第四个元素赋初值为空值,即'\0',所以数组s中存放的也是字符串" 123"。选项B是直接使用字符串"123"对字符数组初始化;选项C也是使用字符串初始化,但是字符串不是"123",而是"123\n",数组长度为5。 答案:C 【例4.17】下列程序的功能是输入N个实数,然后依次输出前l个实数和、前
17、2个实数和、…、前N个实数和。填写程序中缺少的语句。
#define N 10
main()
{ float f[N],x=0.0;int i;
for(i=0;i 18、一次循环的基础上作累加,即前i个实数和(x)等于前i-1个实数和(x)加上第i个实数f[i-1],因此,①处应填写:x=x+f[i-1];。
答案:x=x+f[i-l]; 或 x+=f[i-l];
【例4.18】下面程序的功能是检查一个N×N矩阵是否对称(即判断是否所有的a[i][j]等于a[j][i])。请填空。
#define N 4
main()
{ int a[N][N]={1,2,3,4,2,2,5,6,3,5,3,7,4,6,7,4};
int i,j,found=0;
for(j=0;j 19、 ;i 20、入到另一数组中(最后一组可以不足3个元素),最后输出所求的所有和值且每行输出5个值。
解析:用于存储和值的数组设为b,所有元素都初始化为0。从数组a的第一个元素开始,进行累加操作b[j]+=a[i],累加过程中,数组a的下标每自加3次,数组b的下标自加1次。重复此操作,直到数组a的所有元素累加完为止。输出时,每输出5个元素输出一次换行符"\n"。
#define N 20
#define M N/3+1
main()
{ int a[N],i,j,b[M]={0};
for(i=0;i 21、 22、0]中。
解析:首先将数组d的所有元素都初始化为0,然后从数组b的第一个元素开始判断,如果数组b的元素值大于或等于100,则数组元素d[10]加1,否则,数组元素d[数组b的元素值/10]加1。重复此操作,直到数组b的最后一个元素为止。
#include 23、
for(i=0;i 24、将数组y复制到数组x。
#include 25、for(i=0;i 26、 printf("The original data :\n");
for(i=0;i 27、234。要求:不得调用C语言提供的将字符串转换为整数的函数。
解析:设存放数字字符串的数组为s,存放对应整型数的变量为n(初始值为0)。若字符串的第一个字符为’-’,则从第二个字符开始,否则从第一字符开始,利用公式n=n*10+s[i]-‘0’进行转换,直到’\0’为止。
#include 28、s[i])
{ n=n*10+s[i]-'0';i++;}
if(s[0]=='-') n=-n;
printf("%ld\n",n);
}
【例4.24】编写程序,把N×N矩阵A加上矩阵A的转置,存放在矩阵B中。
解析:可先将A的转置存入B,再将A的元素a[i][j]累加到B的元素b[i][j]。也可直接利用转置性质,b[i][j]=a[i][j]+a[j][i]。
#define N 3
#include 29、
for(i=0;i 30、1列(0= 31、printf("\n");
}
}
4.3 自测试题
1. 单项选择题
(1)以下定义语句中,错误的是( )。
A.int a[]={1,2}; B.char *a[3];
C.char s[10]="test"; D. int n=5,a[n];
(2)以下能正确定义二维数组的是( )。
A.int a[][3]; B.int a[][3]={2*3};
C.int a[][3]={}; D.int a[2][3]={{1}, 32、{2},{3,4}};
(3)以下程序的输出结果是( )。
A.1 5 9 B.1 4 7 C.3 5 7 D.3 6 9
main()
{ int i,x[3][3]={1,2,3,4,5,6,7,8,9};
for(i=0;i<3;i++) printf("%d ",x[i][2-i]);
}
(4)有以下程序, 执行后输出结果是( )
main()
{ int x[8]={8,7,6,5,0},*s;
s=x+3;
printf("%d ",s[2]);
}
A 33、 随机值 B. 0 C. 5 D. 6
(5)若有定义:int a[][3]={1,2,3,4,5,6,7,8}; ,则a数组的行数为( )。
A.3 B.2 C.无确定值 D.1
(6)下列描述中不正确的是 ( )。
A. 字符型数组中可以存放字符串
B. 可以对字符型串进行整体输入、输出
C. 可以对整型数组进行整体输入、输出
D. 不能在赋值语句中通过赋值运算符"="对字符型数组进行整体赋值
(7)运行下列程 34、序的输出结果是( )。
main()
{ int a[]={1,2,3,4,5},i,*p=a+2;
printf("%d", p[1]-p[-1]);
}
A. 出错,因下标不能为负值 B. 2 C. 1 D. 3
(8)以下printf语句的输出结果是( )。
printf("%d\n", strlen("school"));
A. 7 B. 6 C. 存在语法错误 D. 不定值
(9)若有语句:char s1[10], s2[10]="book 35、s";,则能将字符串books赋给数组s1的语句是( )。
A. s1="books"; B. strcpy(s1, s2);
C. s1=s2; D. strcpy(s2, s1);
(10)以下语句或语句组中,能正确进行字符串赋值的是( )。
A. char *sp; *sp="right!"; B. char s[10]; s="right!";
C. char s[10]; *s="right!"; D. char *sp="right!";
2. 程序分析题(阅读程序,写出运行 36、结果)
(1)
main()
{ int x[6],a=0,b,c=14;
do
{ x[a]=c%2;a++;c=c/2;}while(c>=1);
for(b=a-1;b>=0;b--)
printf("%d ", x[b]);
printf("\n");
}
(2)
main()
{ int i,n[6]={0};
for(i=1;i<=4;i++)
{ n[i]=n[i-1]*2+1;
printf("%d ",n[i]);
}
}
(3)
#include 37、ude 38、strlen(str2);
num=i 39、in()
{ char a[]="clanguage",t;
int i,j,k; k=strlen(a);
for(i=0;i<=k-2;i+=2)
for(j=i+2;j 40、]="ab",*p,*q,*r; int n;
n=0;q=s;
while(*q)
{ p=q;r=t;
while(*r)
if( ③ )
{ r++; p++;}
else break;
if( ④ ) n++;
q++;
}
printf("\nThe result is: n=%d\n",n);
}
(3)下面程序的功能是把给定的字符按其矩阵格式读入数组str中,并输出行号与列号之和为3的数组元素。请填空。
mai 41、n( )
{ char str[4][3]={'A','b','C','d','E','f','G','h','I','j','K','l'};
int x,y,z;
for(x=0;x<4;x++)
for (y=0; ⑤ ;y++)
{ z=x+y;
if( ⑥ )
printf("%c\n",str[x][y]);
}
}
(4)下面程序的功能是输入一个3×3的实数矩阵,求两条对角线元素中各自的最大值。请填空。
main()
{ float s[3][3],ma 42、x1,max2,x;
int i,j;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{ scanf("%f",&x);s[i][j]=x;}
max1= ⑦ ;
for(i=1;i<3;i++)
if(max1 43、
printf("max2=%f\n",max2);
}
(5)下面程序的功能是利用数组计算并存储Fibonacci序列的前40项,每行输出4项。请填空
main()
{ long int a[40]={1,1};
int i;
for(i=2;i<40;i++)
a[i]= ⑨ ;
for(i=0;i<40;i++)
{ if( ⑩ ) printf("\n");
printf("%10ld",a[i]);
}
}
4. 程序设计题
(1)给定一维整型数组,输入 44、数据并求第一个值为奇数元素之前的元素和。
(2)给定一维整型数组,输入数据并对前一半元素升序排序,对后一半元素降序排序。
(3)输入字符串并统计各数字字符出现的次数。
(4)给定N×N矩阵,输入矩阵元素并互换主次对角线元素值。
(5)给定二维数组a[M][N],输入数据并将元素按照行序存入到一维数组b中。
4.4 实验题目
(1)数组a中存放N个非0整数,编写程序,将数组a中的所有正数存放在数组的前面,负数存放在数组的后面。
(2)将数组a中的N个元素后移m位,移出的m位顺序存放在数组的前m位。
(3)有5名学生,每名学生有语文、数学、物理和外语四门课的考试成绩,编程统计各学生 45、的总分和平均分,以及所有学生各科的总分和平均分。
(4)将整型N×N矩阵主对角线元素进行升序排序。
(5)将4×4阶矩阵的4个最小值按升序存放在主对角线上。
(6)求N×N矩阵每行最大值的和。
(7)由键盘输入一个字符串,按照ASCII码由小到大的顺序排序,要求删除所输入的重复字符。如输入"ad2f3adjfeainzzzzv",则应输出"23adefijnvz"。
(8)从键盘输入一个字符串,去掉所有非十六进制字符后转换成十进制数输出。要求如输入"g2sh8iBof",输出值为:10431。
4.5 思考题
(1)定义二维数组时是否可以省略第一维长度?省略时系统如何计算长度?
46、
(2)定义一维数组与引用一维数组元素时,“[]”内数据的含义是什么?
(3)若有定义:int a[3][4],(*q)[4]=a;,则如何利用指针变量q引用数组a的元素?
(4)若有如下定义和语句:
int a[3][4],*p[3];
p[0]=&a[0][0];p[1]=&a[1][0];p[2]=&a[2][0];
则如何利用指针数组名p引用数组a的元素?
(5)试说明下列两种定义方式的区别。
char a[3][8]={"gain","much","strong"};
char *a[3]={"gain","much","st 47、rong"};
4.6 习题解答
1. 单项选择题(下列每小题有4个备选答案,将其中一个正确答案填到其后的括号内)
(1)设有定义:int a[10],*p=a;,对数组元素的正确引用是( )。
① a[p] ② p[a] ③ *(p+2) ④ p+2
解答:a和p是地址,不可以用作数组元素的下标,所以①②错误,选项④为p之后两个元素的地址即等价于&a[2],选项③为元素a[2]。
答案:③
(2)若有如下定义,则不能表示数组a元素的表达式是( )。
int a[10]={1,2,3,4,5,6,7,8,9,10},*p= 48、a;
① *p ② a[10] ③ *a ④ a[p-a]
解答:因为p初值为a,所以选项①为元素a[0],选项③也为元素a[0],选项④为a[0],选项②元素下标超出下标界限(0~9)。
答案:②
(3)若有如下定义,则值为3的表达式是( )。
int a[10]={1,2,3,4,5,6,7,8,9,10},*p=a;
① p+=2,*(p++) ② p+=2,*++p ③ p+=3,*p++ ④ p+=2,++*p
解答:四个表达式都是逗号表达式,表达式的值为第二个式子的值,选项①的p从指向a[0]改 49、变为指向a[2],因此表达式值为3,选项②的p指向a[2],计算*++p时指针指向a[3],表达式值为4,选项③的p指向a[3],表达式值为4,选项④的p指向a[2],计算++*p后a[2]元素值变为4。
答案:①
(4)设有定义:char a[10]="ABCD",*p=a;,则*(p+4)的值是( )。
① "ABCD" ② ’D’ ③ ’\0’ ④ 不确定
解答:数组所赋初值为串,数组a[4]及其后的六个元素值都为'\0',*(p+4)等价于*(a+4)即a[4]。
答案:③
(5)将p定义为指向含4个元素的一维数组的指针变 50、量,正确语句为( )。
① int (*p)[4]; ② int *p[4]; ③ int p[4]; ④ int **p[4];
解答:①定义p为指向含4个整型元素的一维数组的指针变量。②定义了一个有四个元素的指针数组,数组名为p,数组中的每一个元素都是指向整型变量的指针变量。③定义了一个有四个元素的整型数组,数组名为p。④定义了一个有四个元素的二级指针数组,数组名为p,数组中的每一个元素都是指向整型指针变量的指针变量。
答案:①
(6)若有定义int a[3][4];,则输入其3行2列元素的正确语句为( )。
① scanf("%d",a[3,2]);






