数组的使用:定义和使用,下标和下标范围
1.定义数组
- <类型>变量名称【元素数量】
int grades 【100】
-
元素数量必须是整数
数组 -
是一种容器(放东西的地方),特点是:
- 其中所有元素具有相同的数据类型
- 一旦创建,不能改变大小
-
- (数组中的元素在内存中是连续依次排列的)
**int a 【10】
- (数组中的元素在内存中是连续依次排列的)
-
一个int的数组
-
10个单元:a[0],a[1]… a[9]
-
每个单元就是一个int类型的变量
-
可以出现在赋值的左边或右边
- a[2]=a[1]+6
- 在赋值左边的叫左值
数组的单元
- 数组的每个单元就是数组类型的一个变量
- 使用数组时放在[]中的数字叫做下标或索引,下标从0开始计数
有效的下标范围 - 编译器和运行环境都不会检查数组下标是否越界,无论是对数组单元做读还是写
- 一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃
- segmentation fault
- 但是也可能运气好,没造成严重的后果
- 所以这是程序员的责任来保证程序只使用有效的下标值:(0-数组大小-1)
数组的例子:投票统计
**写一个程序,输入数量不确定的[0-9]范围内的整数,统计每一种数字出现的次数,输入-1表示结束
#include<stdio>
int main(void)
{
const int number =10; //数组的大小
int x;
int count [number]; //定义数组
int i;
for(i=0;i<number;i++) /*
{
count[i] = 0; 初始化数组
} */
scanf("%d",&x);
while(x!=-1)
{
if(x>=0&&x<=9)
{
count[x]++; //数组参与运算
}
scanf("%d",&x)
}
for(i=0;i<number;i++) /*
{
printf("%d:%d\n",i,count[i]); 遍历数组输出
} */
return 0;
}
数组运算
数组的运算
数组的集成初始化、
- int a[] = {2,4,6,7,1,3,5,9,11,13,23,14,32};
- 直接用大括号给出数组的所有元素的初始值
- 不需要给出数组的大小,编译器替你数数
int b[20]={2};
如果给出了数组的大小,但是后面的初始值数量不足,则其后面的元素被初始化为0
集成初始化时的定位
int a[10]={[0]=2,[2]=3,6,};
- 用[n]在初始化数据中的定位
- 没有定位的数据接在前面的位置的后面
- 其他位置的值补零
- 也可以不给出数组⼤⼩,让编译器算
- 特别适合初始数据稀疏的数组
数组的大小
- sizeof给出整个数组所占据的内容的⼤⼩,单位是字节
sizeof[a]/sizeof(a[0])
- sizeof(a[0])给出数组中单个元素的⼤⼩,于是相除就得到了数组的单元个数
- 这样的代码,⼀旦修改数组中初始的数据,不需要修改遍历的代码
数组的赋值
int a[] = {2,4,6,7,1,3,5,9,11,13,23,14,32};
int b[] = a; //这么写是错的
- 数组变量本身不能被赋值
- 要把一个数组的所有元素交给另一个数组,必须采用遍历
for( i=0;i<length;i++){
b[i]=a[i];
}
遍历数组
- 通常都是使⽤for循环,让循环变量i从0到<数组的⻓度,这样循环体内最⼤的i正好是数组最⼤的有效下标
- 常⻅错误是:
- 循环结束条件是<=数组⻓度,或;
- 离开循环后,继续⽤i的值来做数组元素的下标!
***数组作为函数参数时,往往必须再⽤另⼀个参数来传⼊数组的⼤⼩
- 数组作为函数的参数时:
- 不能在[]中给出数组的⼤⼩
- 不能再利⽤sizeof来计算数组的元素个数
数组例子
判断素数
在没学数组前用函数写的://从2到x-1测试是否可以整除
int isprime(int x);
int main(void)
{
int x;
scanf("%d",&x);
if(isprime(x))
{
printf("%d是素数\n",x);
}else{
printf("%d不是素数\n",x);
}
int isprime(int x)
{
int ret = 1;
int i;
if(x==1) ret = 0;
for(i=2;i<x;i++)
{
if(x%i==0)
{ ret=0;
break;
}
}
return ret;
} //对n来说要循环n-1遍
return 0; //当n很大时就是n遍
}
//去掉偶数后从3到x-1,每次加2(只写函数体里的内容)
- 如果x是偶数,立刻拿掉
- 否则要循环 (n-3)/2 +1遍
- 当n很大时就是n/2遍
int isprime(int x)
{
int ret = 1;
int i;
if( x == 1 || ( x%2 == 0 && x!=2 ) )
ret = 0;
for (i=3;i<x;i+=2)
{
if( x%i ==0 )
{
ret = 0;
break;
}
}
return ret;
}
无须到x-1,到sqrt(x)就够了
int isprime(int x)
{
int ret = 1;
int i;
if( x == 1 || ( x%2 == 0 && x!=2 ) )
ret = 0;
for (i=3;i<sqrt(x);i+=2)
{
if( x%i ==0 )
{
ret = 0;
break;
}
}
return ret;
}
判断是否能被已知的且<x的素数整除
构造素数表
二维数组
int[3][5];
- 通常理解为a是一个3行5列的矩阵
二维数组的遍历
for(i=0;i<3;i++)
{
for(j=0;j<5;j++)
{
a[i][j]=i*j;
}
}
- a [i][j] 是一个int
- 表示第i行第j列的单元
- a [i ,j]中,表示的是运算符
二维数组的初始化
int a[][5]={
{0,1,2,3,4},
{2,3,4,5,6},
};
- 列是必须给出的,行数可以有编译器来做
- 每一行的大括号,逗号分隔
- 最后的逗号可以存在也可以不存在
- 如果省略则表示补零
- 也可以用定位
tic-tac-toe游戏(井字棋
• 读⼊⼀个3X3的矩阵,矩阵中的数字为1表⽰该位置上有⼀个X,为0表⽰为O
• 程序判断这个矩阵中是否有获胜的⼀⽅,输出表⽰获胜⼀⽅的字符X或O,或输出⽆⼈获胜
读入矩阵
const int size = 3;
int board[size][size];
int i,j;
int numOfX;
int numOFO;
int result = -1; //-1 : 没人赢,1:X赢,0:O赢
//读入矩阵
for(i=0;i<size;i++)
{
for(j=0;j<size;j++)
{
scanf("%d",&board[i][j]);
}
}
检查行
for (i=0;i<size && result == -1;i++)
{
numOfO = numOfX =0
for(j = 0; j<size; j++)
{
if(board[i][j] == 1)
{
numOfX ++;
}else{
numOfO ++;
}
}
if(numOfO == size)
{
result = 0;
}
else if(numOfX == size)
{
result = 1;
}
}
检查列
if(result == -1)
{ for (j=0;j<size && result == -1;j++)
{
numOfO = numOfX =0
for(i = 0; i<size; i++)
{
if(board[i][j] == 1)
{
numOfX ++;
}else{
numOfO ++;
}
}
if(numOfO == size)
{
result = 0;
}
else if(numOfX == size)
{
result = 1;
}
}
}
检查对角线、
numOfO = numOfO = 0;
for (i=0; i<size; i++)
{
if(board[i][i] ==1 )
{
numOfO ++;
}else{
numOfO ++;
}
}
if(numOfO == size)
{
result = 0;
}else if(numOfO == size)
{
result = 1;
}
numOfO = numOfO = 0;
for (i=0; i<size; i++)
{
if(board[i][size-i-1] ==1 )
{
numOfO ++;
}else{
numOfO ++;
}
}
if(numOfO == size)
{
result = 0;
}else if(numOfO == size)
{
result = 1;
}