当前位置 博文首页 > jtwqwq的博客:翁恺老师C语言程序设计网课(7)
之前提到过如何计算用户输入的数字的平均数?
之前的做法:每读到一个数(!=-1)加到sum里,cnt++,最后sum/cnt
这样我们不需要记录每一个数
如果题目还要求:输出所有大于平均数的数?这样就必须记录每一个数了,因为我们是最后才计算平均数的,要最后再用每个数和平均数做判断
如何记录很多数?int num1,num2……?不好。这样下去无穷无尽。
使用数组
int number[100];//定义数组,表示数组可以放100个int
scanf(“%d”,&x);
while(x!=-1){
number[cnt]=x;//对数组中的元素赋值
cnt++;
scanf(“%d”,&x);
}
最后再加个cnt长度的循环,判断每一个数与平均数比较大小
if(cnt>0){
int i;
double average=sum/cnt;
for(i=0;i<cnt;i++){
if(number[i]>average){//使用数组中的元素
printf("%d ",number[i]);//遍历数组
}
}
}
这个程序的安全隐患在于没有考虑使用的数组下标是否会超过100.定义的时候注意要求。
定义数组:
<类型>变量名称[元素数量];//方括号表示这是个数组
int grades[100];
double weight[20];
元素数量必须是整数。在c99之前,元素数量必须是编译时确定的字面量。(a[n]不行)vscode中好像就不行,提示variable-sized object may not be initialized
数组是一种容器,特点是:
其中所有元素具有相同的数据类型;
一旦创建,不能改变大小;
其中元素在内存中连续依次排列(从0开始);
如:定义十个单元a[10]→a[0]~a[9]
每个单元就是一个int类型的变量。像普通变量一样可以出现在赋值的左边或右边。左边的叫左值,右边的叫右值。
数组的每个单元就是数组类型的一个变量。使用数组时[]中的数字/变量叫下标或索引,从0开始计数
(要习惯数数从0开始到n-1)
但编译器和运行环境不会检查数组下标是否越界,无论读、写数组单元。
不过数组越界时可能出问题:segmentation fault
,运气好的话不会造成严重的后果。
所以这是程序员的责任来保证程序只适用有效的下标值(范围:[0,数组大小-1])
防止读入数字超过100个的方法:
方法一:cnt=100之后停止读数;
方法二:利用c99数组大小可以是动态的的特性,定义number[cnt];//用户先输入cnt
可不可以int a[0];?
可以,但是没用。
不停输入0~9范围内的整数,读到-1停止,统计每种数字出现的次数。
和上一道题不同的是,不用记录每次输入的数字,我们需要记录的是每种数字出现的次数。
学到了定义数组为0的方法:
for(int i=0;i<10;i++)count[i]=0;
和打印方法:
for(int i=0;i<10;i++)printf(“%d\n”,count[i]);
该题中出现多次数字10。根据之前学到的方法,我们可以定义const number=10(c99才能用);每一个10用number代替。
通常用到数组的程序都需要的环节:
搜索:在一组给定数据中,怎样找出某个数据是否存在?
(往函数中传数组:int sum(a[]))
数组的集成初始化:
int a[]={2,4,6,7,1,3,5,9}
/*直接用大括号给出数组所有元素的初始值;
不需要给出数组的大小,编译器替你数了。*/
依次初始化数组的每一个单元
如果a[13]={2};
只有a[0]是2,后面的单元都是0
所以如果想定义一个数组全为0:a[13]={0};
C99还可以在大括号里给指定的位置赋值。
用[n]在初始化数据中给出定位,没有定位的数据接在前面的位置后面;其他位置的值补0.
int a[0]={[0]=2,[2]=3,6};
这个例子里,a[0]=2,a[2]=3,a[3]=6
我们也可以不给出数组大小,让编译器计算。比如上例可写为:
int a[]={[0]=2,[2]=3,6};
这样会根据大括号里最大的数字下标来算数组的大小。即下标最大为3
这样特别适合初始数据稀疏的数组。
sizeof给出整个数组所占据的内容的大小,单位是字节。(n*4,sizeof(a)/sizeof(a[0])就能得到数组元素个数)
不能直接把一个数组赋给另一个数组b[]=a;
数组变量本身不能被赋值。如果想把一个数组的值全部交给另一个数组,必须遍历。
通常使用for循环,从0开始到<n,这样循环体最大的i正好是数组最大的有效下标。
常见错误:1.循环结束条件是<=数组长度
2.离开循环之后继续使用i作为数组元素下标。
数组作为函数参数时,往往需要另一个参数来传递数组大小。
原因:1、数组传入函数之后我们不能用sizeof来计算数组的元素个数;
2.不能在[]中给出数组的大小。
具体原因后面再说。
之前找素数的例子。我们可以定义isPrime()函数来判断一个数是否是素数。
isPrime()函数:我们从2到x-1都拿去除x,循环要走很多遍,重复执行的次数很多(程序很差)。
优化:当x是!=2的偶数,一定不是素数,就直接不用判断。
因为剩下需要判断的书都是奇数,肯定%2=1,这样我们判断接下来的数时for循环除数就可以从3开始的奇数判断。
for(int i=3;i<x;i+=2)
再次优化:我们不需要走到x。我们只要走到sqrt(x)就够了。
for(int i=3;i<=sqrt(x);i+=2)
引入:当我们想了解一个函数时,在编译器中输入man 函数名称(man sqrt)就能得到其相关信息。(man:manual手册)
Windows用户:打开浏览器搜索。
再再次优化:我们不需要拿比x小的数字来测试x是不是素数,我们只需要拿比x小的素数就够了。
int isPrime(int x,int knowsPrimes[],int numberofKnownPrimes)
int main()
{
const int number=100;
int prime[number]={2};
int count=1;
int i=3;
while(count<number){
if(isPrime(i,prime,count)){
prime[count++]=i;
}
i++;
}//prime数组装着所有素数
for(i=0;i<number;i++){
printf("%d",prime[i]);
if((i+1)%5)printf("\t");
else printf("\n");
}
return 0;
}
int isPrime(int x,int knowsPrimes[],int numberofKnownPrimes)
{
int ret=1;
int i;
for(i=0;i<numberofKnownPrimes;i++){
if(x%knownPrimes[i]==0){
ret=0;
break;
}
}
return ret;
}
一边构造素数表,一边利用表来证明素数。
其中prime[cnt++]=i
;一举两得,cnt++
的同时还把i的值放到了对应的数组位上。
while(count<number){
if(isPrime(i,prime,count)){
prime[count++]=i;
}
{
printf("i=%d \tcnt=%d\t",i,count);
int i;
for(i=0;i<number;i++){
printf("%d\t",prime[i]);
}
printf("\n");
}
i++;
}
这样加个括号在里面int i
之后,我们使用i就不会影响到外面的i的值了(但是我宁愿重新定义个变量j=i。因为太绕了)
同样的方法,我们可以先输出一个表头。
{
int i;
printf("\t\t\t\t");
for(i=0;i<number;i++){
printf("%d\t",i);
}
printf("\n");
}
换一个思路,使得最后这张表里留下来的数都是素数。
欲构造n以内的素数表:
for(int i=2;x*i<n;i++)
令prime[i*x]=0
int main()
{
const int maxNumber=25;
int isPrime[maxNumber];
int i,x;
for(i=0;i<maxNumber;i++)
{
isPrime[i]=1;
}
for(x=2;x<maxNumber;i++)
{
if(isPrime[x])
{
for(i=2;i*x<maxNumber;i++) isPrime[i*x]=0;
}
}
printf("\n");
return 0;
}
如此可见,算法的思考方式不见得与人相同。
int a[3][5];
通常理解为a是一个3行5列的矩阵
最好先行号再列号,和线性代数也是相对应的。
二维数组的遍历需要两个for循环
int a[][5]={
{0,1,2,3,4},
{2,3,4,5,6},
};
a[i][j]
表示一个int
a[i,j]
是逗号运算符(等于逗号右边的值),表示a[j]
,不是正确表达二维数组的方式。
二维数组的列数必须给出,行数可以交给编译器来数。
给数的时候每行一个{},用逗号分隔。如果省略表示0。
也可以用定位(注意只能是c99)
二维数组是逐行填满的,所以也可以不加大括号,当做一维数组去初始化
PS: tic-tac-toe 井字棋判断输赢问题:行列对角线分开检查。
const int size = 3;
int board[size][size];
int i,j;
int num0fX;//X是一方
int num0fO;//O是一方
int result=-1;