@TOC
8.1数组
8.1.1初试数组
如何写一个程序计算用户输入的数字的平均数?
#include<stdio.h>
int main()
{
int digit;//输入要求平均数的数字
double sum=0;//记录输入数字的和
int count=0;//记录输入数字的个数
printf("请输入一组数字,用来求平均数,以-1结束\n");
scanf("%d",&digit);
while(digit!=-1)//使用while循环将数字累加到sum中,直到输入-1结束循环
{
sum+=digit;
count++;
scanf("%d",&digit);
}
printf("平均数为%f\n",sum/count);
}
这个代码不需要记录用户输入的每一个数。 如何写一个程序计算用户输入的数字的平均数,并输出所有大于平均数的数? 必须先记录每一个输入的数字,计算平均数之后,再检查记录下来的每一个数字,与平均数比较,决定是否输出 如何记录很多事? sum1,sum2,sum3... 数组 int number[100]; scanf("%d",&number[i]); 数组
#include<stdio.h>
int main()
{
int digit;//输入要求平均数的数字
int Arr[100];//将输入的数字存入数组
int a = 0;//记录输入的数字个数
double sum =0;//记录输入数字的和
printf("请输入一组数字,用来求平均数,以-1结束\n");
for(int i=0;i<100;i++)
{
scanf("%d",&digit);
if(digit==-1)//输入-1结束循环
break;
Arr[a]=digit;
a++;//记录输入数字个数
sum+=digit;//记录输入数字的和
}
printf("平均数为%f\n",sum/a);//输出平均数
for(int b=0;b<a;b++)//使用for循环遍历数组
{
if(Arr[b]>sum/a)//输出大于平均数的数字
{
printf("大于平均数的数字有%d ",Arr[b]);
}
}
return 0;
}
int Arr[100];//定义数组 Arr[a]=digit;//对数组中的元素赋值 Arr[b]>sum/a//使用数组中的元素 printf("大于平均数的数字有%d ",Arr[b]);//遍历数组
8.1.2数组的使用:如何定义和使用数组,数组的下标和下标的范围
定义数组 <类型>变量名称[元素数量] int grades[100]; double weight[20]; 元素数量必须是整数 C99之前:元素数量必须是编译时刻确定的字面量,在C99可以使用变量来确定元素数量 数组 是一种容器(放东西的东西),特点是: 其中所有的元素具有相同的数据类型; 一旦创建,不能改变大小 *(数组中的元素在内存中是连续依次排列的) int [10]
一个int数组 十个单元:a[0],a[1]...a[9] 每个单元就是一个int类型的变量 可以出现在赋值的左边或右边: a[2]=a[1]+6; *在赋值左边的叫做左值 数组的单元 数组的每个单元就是数组类型的一个变量 使用数组时放在[]中的数字叫做下标或索引,下标0开始计数: grades[0] grades[99] average[5] 有效的下标范围 编译器和运行环境都不会检查数组下标是否越界,无论是对数组单元做读还是写 一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃 SEGMENTATION FAULT 但是也可能运气好,没造成严重的后果 所以这是程序员的责任来保证程序只使用有效的下标值:[0,数组的大小-1] 计算平均数 在C99中可以先让用户输入有多少数字要计算,来确定数组的大小 长度为0的数组? int a[0] 可以存在,但是无用
8.1.3数组的例子:统计个数
#include<stdio.h>
int main()
{
const number =10;//定义数组的大小
int Arr[number];//定义数组
int x;//输入要求统计的数字
for(int i=0;i<number;i++)//将数组元素初始化为0
{
Arr[i]=0;
}
printf("请输入一组数据,用来统计每一个数字出现的个数:");
scanf("%d",&x);//输入数字
while(x!=-1)//使用while循环将数字出现的个数存入数组中
{
Arr[x]++;//将数字出现的个数存入数组中
scanf("%d",&x);//输入数字
}
for(int j=0;j<number;j++)//使用for循环遍历数组
{
printf("%d:%d\n",j,Arr[j]);//输出数字出现的个数
}
return 0;
}
8.2数组运算
8.2.1数组运算
在一组给定的数据中,如何找出某个数据是否存在?
#include<stdio.h>
int find(int x,int Arr[],int len);
int main()
{
int x;//要查找的数字
int Arr[]={1,4,2,3,5,0,8,6,7,12,25,47,84,32};//定义数组
int len=sizeof(Arr)/sizeof(Arr[0]);//计算数组的长度
printf("请输入要查找的数字:");
scanf("%d",&x);//输入要查找的数字
int index=find(x,Arr,len);//调用函数
printf("%d在第%d位",x,index+1);
}
int find(int x,int Arr[],int len)//定义一个寻找数字的函数
{
for(int i=0;i<len;i++)//使用for循环遍历数组
{
if(Arr[i]==x)//如果找到了数字
{
return 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来计算数组的元素个数!
8.2.2数组的例子:素数
判断素数 简单版本
#include<stdio.h>
int Prime(int x);
int main()
{
int x;//输入一个整数,判断是不是素数
printf("请输入一个整数");
scanf("%d",&x);
if(Prime(x))//调用Prime函数,如果返回值为1则是素数,否则不是素数
{
printf("是素数");
}
else
{
printf("不是素数");
}
}
int Prime(int x)//判断是否为素数的函数
{
int temp=1;//定义一个临时变量,1为素数,0为不是素数
for(int i=2;i<x;i++)
{
if(x%i==0);
{
temp=0;
break;
}
}
return temp;
}
去掉偶数后,从3到x-1,每次加2
#include<stdio.h>
int main()
{
int x;//输入一个整数,判断是不是素数
printf("请输入一个整数");
scanf("%d",&x);
if(Prime(x))//调用Prime函数,如果返回值为1则是素数,否则不是素数
{
printf("是素数");
}
else
{
printf("不是素数");
}
}
int Prime(int x)//判断是否为素数的函数
{
int temp=1;//定义一个临时变量,1为素数,0为不是素数
if(x==1 || x%2==0 && x!=2)//排除1不是素数,2的倍数不是素数,2是素数
{
temp=0;
}
else
{
for(int i=3;i<x;i+=2)//从3开始,排除偶数,排除偶数后,只需要判断奇数是否能被整除即可,
{ //因为偶数除以奇数的余数一定是1,所以只需要i从3开始,每次加2即可
if(x%2==0)
{
temp=0;
}
}
}
return temp;
}
因为偶数一定不是素数 无需到x-1,到sqrt(x)就够了
#include<stdio.h>
#include<math.h>
int main()
{
int x;//输入一个数判断是否为素数
printf("请输入一个数");
scanf("%d",&x);
if(isPrime(x))//使用isPrime函数判断
{
printf("是素数");
}
else
{
printf("不是素数");
}
}
int isPrime(int x)//判断是否为素数的函数
{
int temp=1;//定义一个临时变量temp如果这个数是素数则temp等于1,否则等于0
if(x==1 || x%2==0 && x!=2)//排除1不是素数,2的倍数不是素数,2是素数
{
temp=0;
}
else
{
for(int i=3;i<=sqrt(x);i+=2)//从3开始,排除偶数,排除偶数后,只需要判断奇数是否能被整除即可,
{ //因为偶数除以奇数的余数一定是1,所以只需要i从3开始,每次加2即可
//判断结束的标志是小于等于根号x
if(x%i==0)
{
temp=0;
}
}
}
return temp;
}
sqrt是开根号 判断是否能被已知的且<x的素数整除
#include<stdio.h>
int isPrime(int x,int prime[],int count);
#define number 10
int main()
{
int prime[number]={2};//定义一个数组存储小于number的素数
int count =1;//数组的下标,也就是存储素数的位置
int x=3;//每一个数字
while(x<number)
{
if(isPrime(x,prime,count))//调用isPrime函数判断素数
{
prime[count++]=x; //如果这个数是素数,就将这个数存储在数组的相应位置上
}
{
printf("x=%d \tcount=%d\t",x,count);//每一次存储都将数组里的数字输出打印出来
for(int i=0;i<number;i++)
{
printf("%d ",prime[i]);
}
printf("\n");
}
x++;
}
for(int i=0;i<count;i++)//遍历打印数组里的数字
{
printf("%d ",prime[i]);
}
}
int isPrime(int x,int prime[],int count)
{
int temp=1;
for(int i=0;i<count;i++)//使用循环判读x是否为素数
{
if(x%prime[i]==0)//判断素数的方法是除以数组中已经有的素数,看是否能整除
{
temp=0;
break;
}
}
return temp;
}
构造素数表 欲构造n以内的素数表 1.令x为2 2.将2x,3x,4x直至ax<n的数标记为非素数 3.令x为下一个没有被标记为非素数的数,重复2;直到所有的数都已经尝试完毕
#include<stdio.h>
#define number 30//判断0到number减一的素数
int isPrime(int x);
int main()
{
int prime[number];//定义一个数组存放是否为素数的标志
for(int j=0;j<number;j++)//将数组中所有的元素都赋值为1
{
if(j==0 || j==1)//将特殊的0和1提前赋值为0
{
prime[j]=0;
}
else
{
prime[j]=1;
}
}
int a;//每一个数字
for(a=2;a<number;a++)//循环的将每一个数字交给isPrime函数
{
if(isPrime(a))//如果这个数是素数,则他的倍数一定不是素数
{
for(int i=a*2;i<number;i=i+a)//将a的倍数的数组下标里的值都赋值为0
{
prime[i]=0;
}
}
else//如果a不是素数则a的数组的下标里的值直接为0
{
prime[a]=0;
}
}
for(int k=0;k<number;k++)//输出时的表头
{
printf("%3d",k);
}
printf("\n");
for(int i=0;i<number;i++)//输出数组
{
printf("%3d",prime[i]);
}
}
int isPrime(int x)//判断是否为素数的函数
{
int temp=1;
for(int i=2;i<x;i++)
{
if(x%i==0)
{
temp=0;
break;
}
}
return temp;
}
8.2.3二维数组
int a[3][5];
通常理解为a是一个3行5列的矩阵
二维数组的遍历
- a[i][j]是一个int
- 表示第i行第j列上的单元
- a[i,j]是什么? 因为逗号也是一个运算符,逗号运算符会先对左侧的表达式进行计算,接着计算右侧的表达式,最终整个逗号表达式的结果是右侧表达式的值。也就是说a[i,j]相当于a[j] 二维数组的初始化
int a[][5] = {
{0,1,2,3,4},
{2,3,4,5,6},
};
- 列数是必须给出的,行数可以由编译器来数
- 每行一个{},逗号分隔
- 最后的逗号可以存在,有古老的传统
- 如果省略,表示补零
- 也可以用定位 tic-tac-toe游戏 代码如下
#include<stdio.h>
int hang(int board[][3]);
int lie(int board[][3]);
int zuo(int board[][3]);
int you(int board[][3]);
int result =-1;//-1表示平局,1表示叉赢,0表示圈赢
int main()
{
int board[3][3];
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
printf("请输入第%d行%d列",i+1,j+1);
scanf("%d",&board[i][j]);
}
}
int hang_result=hang(board);
int lie_result=lie(board);
int zuo_result=zuo(board);
int you_result=you(board);
if(hang_result==1 || lie_result==1 || zuo_result==1 || you_result==1)
{
result=1;
}
else if(hang_result==0 || lie_result==0 || zuo_result==0 || you_result==0)
{
result=0;
}
else
{
result=-1;
}
if(result==1)
{
printf("叉获胜");
}
else if(result==0)
{
printf("圈获胜");
}
else if(result==-1)
{
printf("平局");
}
}
//检查行
int hang(int board[][3])
{
int A1;//表示叉
int A0;//表示圈
for(int i=0;i<3;i++)
{
A1=A0=0;
for(int j=0;j<3;j++)
{
if(board[i][j]==1)
{
A1++;
}
else
{
A0++;
}
}
if(A0==3)
{
return 0;
}
else if(A1==3)
{
return 1;
}
}
return -1;
}
//检查列
int lie(int board[][3])
{
int A1;//表示叉
int A0;//表示圈
for (int j=0;j<3;j++)
{
A0=A1=0;
for(int i=0;i<3;i++)
{
if(board[i][j]==1)
{
A1++;
}
else if(board[i][j]==0)
{
A0++;
}
}
if(A1==3)
{
return 1;
}
else if(A0==3)
{
return 0;
}
}
return -1;
}
//检查左线
int zuo(int board[][3])
{
int A1=0;//表示叉
int A0=0;//表示圈
for (int i=0,j=0;i<3 && i<3;i++,j++)
{
if(board[i][j]==1)
{
A1++;
}
else if (board[i][j]==0)
{
A0++;
}
}
if(A1==3)
{
return 1;
}
else if(A0==3)
{
return 0;
}
return -1;
}
//检查右线
int you(int board[][3])
{
int A1=0;//表示叉
int A0=0;//表示圈
for(int i=0,j=2;i<3 && j>-1;i++,j--)
{
if(board[i][j]==1)
{
A1++;
}
else if(board[i][j]==0)
{
A0++;
}
}
if(A0==3)
{
return 0;
}
else if(A1==3)
{
return 1;
}
return -1;
}