第9课数组Word文档格式.docx
《第9课数组Word文档格式.docx》由会员分享,可在线阅读,更多相关《第9课数组Word文档格式.docx(25页珍藏版)》请在冰豆网上搜索。
![第9课数组Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-11/26/52ec8972-cf44-435d-a453-0c2cf1201954/52ec8972-cf44-435d-a453-0c2cf12019541.gif)
a[0]a=10
3:
数组元素中下标表达式的值必须是整数。
在编写程序时保证数组下标不越界是十分重要的。
a[2.5]a[10]=123
★一维数组的初始化
一维数组的始化,其实就是给数组元素赋值。
inta[8]={0,1,2,4,5,6,7}
所赋的值放在等号后的一对花括号中,数值类型必须必须与所说明的类型一致,所赋值之间用逗号隔开。
系统会按赋值顺序来自动分配。
当花括号中的值少于数组元素个数时,将自动给数组后面元素赋值0.如
inta[10]={1}这个时候除了a[0]=1外,其它的都是0;
对于字符数组也是一样;
chara[10]={‘!
’}
不够的也会赋值‘\0’
通过赋初值定义数组的大小
C语言中规定,可以通过赋初值来定义数组的大小,这时数组说明符的一对方括号中可以不指定数组的大小。
如inta[]={1,1,1,1,1,1,1,1,1,1}
这样相当于数组中有了10个元素
例题:
编写一个程序,通过键盘给数组a中的10个成员赋初值。
#include<
stdio.h>
main()
{
inta[10];
inti,*p;
p=a;
for(i=0;
i<
10;
i++)
{scanf(“%d”,p);
printf(“a[i]=%d”,*p);
}
编写一个程序定义一个含有30个成员的数组。
并给其赋值,要求从1这样的奇数开始。
当赋值完毕后,按每行10个输出。
include<
#definem30
inta[m];
inti,k=1;
m;
{a[i]=k;
k+=2;
{printf(“a[%d]=%d”,i,a[i]);
if((i+1)%10==0)
printf(“\n”);
9.2一维数组和指针
★一维数组和数组元素的地址
前言:
定义的数组名可以认为是一个存放地址值的指针变量名,其中的地址值是数组第一个元素的地址,也就是数组所占一串连续存储单元的起始地址。
重要的是:
这个指针变量中的地址值不可改变,也就是说,不可以给数组重新赋值。
因此,也可以认为数组名是一个地址常量。
如:
floata[10],*p,x;
语句a=&
x或a++这样的语句都是非法的。
因为不能给a重新赋地址值。
一旦定义a永远指向a数组的首地址。
虽然不可以改变数组名a中的内容,但可以用对数组名加一个整数的办法,来依次表达该数组中不同元素的地址。
inta[10],*p;
p=a+4~~~~~~~~~~p=&
a[4]
再如:
for(k=0;
k<
k++)
p=a+k;
在循环中并没有改变数组名a中的内容,但通过表达式:
a+k逐一给出了a数组中每个元素的地址,使p依次指向a数组中和每一个元素。
如果要能过类似上面的语句给数组中的元素赋值,语句为:
for(k=0;
scanf(“%d”,a+k);
如有p=a或p=&
a[0]这两个表达式所要表达的意思是一样的。
都是指指针P指向了数组a的首地址。
所以当要依次访问数组中的每一个元素时可以用以下的两个形式;
p++;
或a+k(k的值是不断变化的如上面的for语句一样)
★通过数组的首地址引用数组元素
a是数组元素的首地址,a(即a+0)的值即等于&
a[0],则用a+1的值等于&
a[1].
在以前我们学过“间接访问运算符”----“*”来引用地址所在的存储单元。
因此对于数组a[0],可以用表达式*&
a[0]来引用也可以用*(a+0),还可以用a[0]来表示。
但需要注意的是对于*(p+k)这样的表达式不能这样写*p+k,这样写的话就错了。
代表指针取值后再加K的值了。
总结:
表示数组元素s[i]的表达式应当有
s[i]*(s+i)*(p+i)*p[i]
(但当p=s+2时,p=&
a[2].*p[0]就是a[2]的值了)
9.3函数之间对一维数组和数组元素的引用
数组元素作实参
每个数组元素实际上代表内存中的一个存储单元,故和普通变量一样,对应的形参必须是类型相同的变量。
数组元素的值可以传送给该变量,在函数中只能对该变量进行操作,而不能直接引用数组元素,更不能在函数中改变对应数组元素中的值。
数组名作实参
数组名也可以作为实参传送,但数组名是一个地址值,因此,对应的形参就应当是一个指针变量,此指针变量的基类型必须与数组的类型一致。
这样就可以通过指针变量来引用调用函数中对应的数组元素,从而达到对调用函数中对应的数组元素进行操作而改变其中的值。
例:
编写程序,通过一个函数给主函数中定义的数组输入若干大于或等于0的整数,用负数作为输入结束标志,调用另一个函数输出该数组中的数据。
#include<
#defineM100
voidarrout(int*,int);
intarrin(int*);
ints[M],k;
k=arrin(s);
arrout(s,k);
intarrin(int*a)
inti,x;
i=0;
scanf(“%d”,&
x);
while(x>
=0)
*(a+i)=x;
i++;
returni;
voidarrout(int*a,intn)
inti;
n;
printf(((i+1)%5==0)?
”%4d\n”;
”%4d”,*(a+i));
printf(“\n”);
当数组名作为实参时,对应的形参除了是指针外,还可以用另外两种形式。
在上面的题目中数组名作为实参时,函数的首部用的是指针arrin(int*a),还可以用以下的形式调用:
、
arrin(int*a)
arrin(inta[])
arrant(inta[M])
9.3.3数组元素地址作为实参
当用数组元素地址作为实参时,因为是地址值,所以对应的形参也应当是基类型相同的指针变量。
例:
编写函数,对具有10个元素的char类型数组,从下标为4的元素开始,全部设置星号“*”;
保持前4个元素中的内容不变。
假设数组是c[10]={‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’,‘H’,‘I’,‘J’}
根据题意可以知道想要从E开始后面的全变成*
编写一个改变的函数,编写一个输出的函数。
#defineM10
#defineB4
voidsetstar(char*,int);
voidarrout(char*,int);
charc[M]={‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’,‘H’,‘I’,‘J’};
setstar(&
c[4],M-B);
arrout(c,M);
voidsetstar(char*a,intn)
*(a+i)=’*’;
voidarrout(char*a,intn)
inti;
for(i=0;
printf(“%c”,a[i]);
9.4一维数组应用举例
编写程序,定义一个含有15个元素的数组,并编写函数分别完成以下操作。
1,调用C库函数中的随机函数给所有元素赋以0-49的随机数;
2,输出数组元素中的值。
3,按顺序对每隔三个数求一个和数,并传回主函数。
4,最后输出所有求出的和的值。
#include“stdlib.h”
#defineSIZE15
#defineN3
voidgetrand(int*,int);
voidgetave(int*,int*,int);
voidpriarr(int*,int);
intx[SIZE],w[SIZE/N]={0};
getrand(x,SIZE);
printf(“output%drandomnumbers:
\n”,SIZE);
priarr(x,SIZE);
getave(x,w,SIZE);
printf(“Output5sumnumbers:
\n”);
priarr(w,SIZE/N);
voidgetrand(int*a,intn)
a[i]=rand()%50;
voidgetave(int*a,int*b,intn)
inti,j,sum;
for(sum=0,i=0,j=0;
=n;
sum+=a[i];
if((i+1)%3==0)
b[j]=sum;
sum=0
j++;
voidpriarr(int*a,intn)
intI;
printf(“%5d”,a[i]);
if((i+1)%5==0)
将数组中的数按颠倒的顺序重新存放。
在操作时,只能借助一个临时存储单元,不得另外开辟数组。
注意:
不是按颠倒的顺序打印数据,而是要求按逆序重新放置数组中的内容。
#defineNUM8
voidinvert(int*,int);
voidpriout(int*,int);
inta[num]={10,20,30,40,50,60,70,80};
printf(“输出数组中的内容:
”);
priout(a,NUM);
invert(a,NUM);
printf(“输出数组中调换后的内容:
”)
voidpriout(ints[],intn)
printf(“%4d”,s[i]);
voidinvert(int*a,intn)
inti,j,t;
j=n-1;
while(i<
j)
{t=a[i];
a[i]=a[j];
a[j]=t;
j--;
}、
9.5二维数组的定义和二维数组元素的引用
9.5.1二维数组的定义
当数组中的每个元素带有两个下标时,称这样的数组为二维数组。
(在逻辑是可以把二维数组看成一个具有行和列的表格或一个矩阵)
定义语句形式如下:
类型名数组名[常量表达式1][常量表达式2]
二维数组说明符中必须有用两个方括号括起来的常量表达式,常量表达式的值只能是正整数。
如果将二维数组当做矩形来看,那么常量表达式1就是代表行数,常量表达式2就代表列数。
如inta[3][4]a[1][2]
1.定义了一个名为a的二维数组。
2.数组中的每个元素都是整形
3.a数组中共有3*4个元素。
4.a数组的逻辑结构是一个具有3行4列的矩阵。
第0列第1列第2列第3列
第0行a[0][0]a[0][1]a[0][2]a[0][3]
第1行a[1][0]a[1][1]a[1][2]a[1][3]
第2行a[2][0]a[2][1]a[2][2]a[2][3]
其实对于二维数组来说,我们还可以理解为一个特殊的一维数组。
如上,将此二维数组中的第0行可以看为一个名为a[0]的一维数组的几个成员。
同理对另外几行也成立。
9.5.2二维数组元素的引用
引用二维数组元素时必须带有两个下标,引用形式如下:
数组名[下标表达式1][下标表达式2]
inta[3][4]在这样定义的二维数组中,
有a[0][1]a[i][j]a[i+k][j+k]
引用二维数组元素时,一定要把两个下标分别放在两个方括号肉。
不可以定成a[0,1]a[I,j]a[i+k,j+k]
9.5.3二维数组的初始化
1.所赋值个数与数组元素的个数相同
inta[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};
2.每行所赋值个数与数组中元素的个数不同。
inta[4][3]={{1,2},{4,5},{7},{10}};
3.所赋值行数少于数组行数
inta[4][3]={{1,2},{4,5}};
5.赋值时省略行花括号对
inta[4][3]={1,2,3,4,5};
9.5.4通过赋值定义二维数组的大小
inta[]={1,3,3,3,3,34}
对于二维数组,只可以省略第一个方括号中的常量表达式,而不能省略第二个方括号中的常量表达式
inta[][3]={{1,2},{4,5},{7},{10}};
当用以下形式赋值时:
inta[][3]={1,4,6,7,23,25,17,18};
一维大小按以下规则决定:
1,当初值的个数能被第二维的常量表达式的值除尽时,所得商数就是第一维的大小。
2,当初值的个数不能被第二维的常量表达式的值除尽时。
则第一维的大小=所得的商+1
9.5.5二维数组的定义和数组元素引用举例
通过键盘给2*3的二维数组输入数据,第一行赋值1,2,3,第二行赋值10,20,30然后按行输出此二维数组
#include<
inta[2][3],i,j;
printf(“Enterdatabyline:
2;
for(j=0;
j<
3;
j++)
a[i][j]);
printf(“Outputa2-dimensionarray:
for(j=0;
{
printf(“%4d”,a[i][j]);
9.6二维数组和指针
9.6.1二维数组和数组元素的地址
先给出以下定义:
int*p,a[3][4];
1.二维数组a由若干个一维数组组成
像上面定义的数组a,我们可以理解为由a[0]、a[1]、a[2]三个元素组成,而他们又分别是一个一维数组
通过前面我们学过的知识可以知道,数组名是一个地址,其值是第一个元素的地址,此地址的基类型就是数组元素的类型。
而在二维数组中同样a[0]、a[1]、a[2]都是一维数组名,同样也代表了一个不可变的地址常量。
由于它是一个常量,所以这样就错了:
a[0]++。
而a[0]+1这就是代表向后移动一个单位长度。
对于有一个指针变量P的基类型与a[i]相同,则p=a[i]这是正确的。
2.二维数组名也是一个地址常量
二维数组名同样也是一个存放地址常量的指针,其值为二维数组中第一个元素的地址。
以上a的值与a[0]的值是相同的。
a[0]a+0第0行的首地址
a[1]a+1第1行的首地址
………
像他们这样的,还有一个另外的名称----行地址。
所以二维数组名应理解为一个行指针。
inta[3][4]a[0]=a
3.二维数组元素的地址
用以下的五种方式表示:
&
a[i][j]
a[i]+j
*(a+i)+j
a[0][0]+4*i+j
a[0]+4*i+j
9.6.2通过地址引用二维数组元素
若有以下定义:
inta[3][4]
则a数组元素可以用一下五种表达式来引用:
*(a[i]+j)
*(*(a+i)+j)
(*(a+i))[j]
*(&
a[0][0]+4*i+j)
9.6.3通过建立一个指针数组引用二维数组元素
int*p[3],a[3][2],i,j;
说明符*p[3]中,也遵照运算符的优先级,一对[]的优先级高于*号,因此p首先与[]结合,构成p[3],说明了P是一个数组名,系统将为它开辟3个连续的存储单元,在它前面的*号则说明了数组p是批针类型,它的每个元素都是基类型为int的指针。
如有:
p[i]=a[i]
这就意味着每一个指针都指向了a数组中的每行的开头。
00
01
10
11
20
21
所以对于数组a中的元素,我们也可以通过这样的指针来表示了
1
2
9.6.4通过建立一个行指针引用二维数组元素
若有以下定义:
inta[3][2],(*prt)[2]
为什么要先加一个()?
这是因为想要*先与prt结合,说明prt是一个指针变量。
然后再与[2]结合,说明指针变量prt的基类型是一个包含有两个int元素的数组。
因为prt与a的类型相同,所以prt=a就是一个合法表达式。
当prt指向a数组的开头时,可以通过以下形式来引用a[i][j]
*(prt[i]+j)
*(*(prt+i)+j)
(*(prt+i))[j]
prt[i][j]
9.7二维数组名和指针数组作为实参
9.7.1二维数组名作为实参时实参和形参之间的数据传递
当二维数组名作为实参时,对应的形参必须是一个行指针变量。
假设有这样的一个二维数组名作为实参
doublea[M][N]
fun(a)
这个时候对应的函数首部应写成以下几种形式
fun(double(*a)[N])
fun(doublea[][N])
fun(doublea[M][N])
一定要注意列下标不能丢。
9.7.2指针数组作为实参时,实参和形参之间的数据传递
当指针数组名作为实参时,对应的形参应当是一个指向指针的指针
如:
double*ps[M]
fun(ps)
则fun函数的首部应写成以下几种形式
fun(double*a[M])
fun(double*a[])
fun(double**a)
9.8二维数组程序举例
编写程序,通过调用随机函数给5*6的二维数组元素赋值10-40内的整数,并求出每行元素的平均值。
stdlib.h>
#defineM6
#defineN5
voidgetdata(int(*)[M]);
voidlineave(int[][M],float*);
voidoutdata(int[N][M],float*);
intr[N][M];
floatave[N];
getdata(r);
lineave(r,ave);
outdata(r,ave);
voidgaetdata(int(*sp)[M])
inti,j,x;
j=0;
while(j<
m)
x=rand()%41;
if(x>
10)
sp[i][j]=x;
voidlineave(ints[][M],float*a)
inti,j;
N;
ave=0.0;
M;
ave=ave+s[i][j];
a[i]=ave/M;
voidoutdata(intsp[N][M],floata[])
printf(“outputtheresult:
printf(“%4d”,sp[i][j]);
printf(“:
%6.2\n”,a[i]);
putchar(“\n”)
一、选择题
[9.1]若已定义:
inta[]={0,1,2,3,4,5,6,7,8,9},*p=a,i;
其中0<=i<
=9,则对a数组元素的引用不正确的是
A)a[p-a]B)*(&
a[i])C)p[i]D)*(*(a+i))
[9.2]以下程序段数组所有元素输入数据,应在下划线填入的是
A)a+(i++)B)&
a[i+1]C)a+iD)&
a[++i]
{inta[10],i=0;
10)scanf("
%d"
_);
[9.3]以下程序的输出结果是
A)3B)4C)1D)2
{inta[10]={1,2,3,4,5,6,7,8,9,10},*p=a;
printf("
%d\n"
*(p+2));
}
[9.4]以下程序的输出结果是
A)不确定的值B)3C)2D)1
mai