小学生都看得懂的C语言入门(3): 数组与函数
#include <stdio.h> int main() { int x; double sum=0; int cnt=0; scanf("%d",&x){ sum+=x; cnt++; scanf("%d",&x); } printf("the mean is %d",sum/cnt);
这是之前求平均数的代码,
上述没有记录每一个输入的数, 一旦输入就加上去, 没有记录
//现在问题变了, 需要你求平均数 并且输出大于平均数的值 , 那么有必要记录每一个
输入的数字, 如何实现?
现在需要用到数组进行记录. 在上述代码基础上增加 number[10] 定义,在while 循环中增加number[cnt]=x记录输入的值
#include <stdio.h> int main() { int x; double sum=0; int number[10]; //长度是10的数组, 可以放10个int int cnt=0; scanf("%d",&x); while(x!=-1){ number[cnt]=x; //记录 赋值 sum+=x; cnt++; scanf("%d",&x); } if (cnt>0){ printf("the mean is %f\n",sum/cnt); int i; //遍历每一个数 找到大于平均数的值 for(i=0;i<cnt;i++){ if(number[i]>sum/cnt){ printf("%d\n",number[i]); } } } return 0; }
为了清楚的知道number[cnt]=x 的存储机制,增加一段调试代码
#include <stdio.h> int main() { int x; double sum=0; int number[10]; //长度是10的数组, 可以放10个int int cnt=0; scanf("%d",&x); while(x!=-1){ number[cnt]=x; //记录 赋值 // --用于调试 { int i; printf("%d\t",cnt); for(i=0;i<=cnt;i++){ printf("%d\t",number[i]); } }printf("\n"); //--用于调试 sum+=x; cnt++; scanf("%d",&x); } if (cnt>0){ printf("the mean is %f\n",sum/cnt); int i; //遍历每一个数 找到大于平均数的值 for(i=0;i<cnt;i++){ if(number[i]>sum/cnt){ printf("%d\n",number[i]); } } }return 0; }
这是每次的number 数组的存储情况,再输入-1终止计算,得到
但是上述存在很明显的问题: 定义了number [10] ,如果实际输入了超过10 怎么办?
别急啊, 首先掌握下数组的定义
int grades[100];
double weight[20];
数组的特点: 1.数组中的每个元素具有相同的数据类型, 2. 一旦创建数组, 之后不能改变大小,
int a[10] 的顺序是 a[0], a[1],... a[9] ,[] 中的数字是索引, 索引从0开始计数!!
编译器不会检查数组下标是否越界, 越界就出现segmentation fault ,
int a[0] 可以存在, 但是没有任何用处..
实例: 输入数量不定的在[0,9]之间的整数, 统计每一种数字出现的次数, 输入-1表示结束
程序如下, 用一个10元数组来作为计数器,
#include <stdio.h> int main(void) { const int num=10; //num决定数组大小 int x; int i; int cnt[num]; for (i=0;i<num;i++){ cnt[i]=0; } //初始化数组的每一个元素, scanf("%d",&x); while(x!=-1){ if (x>=0 && x<=9){ cnt[x] ++; } scanf("%d",&x); } for (i=0;i<num;i++){ printf("%d出现了%d次\n",i,cnt[i]); } return 0; }
结果
(二) 定义函数
实例: 求从m -n 之间所有素数的和sum
#include <stdio.h> int main() { int m,n; int sum=0; int cnt=0; int i; // 求素数的和 scanf("%d %d",&m,&n); //m=10 n=31 if (m==1)m=2; for (i=m;i<=n;i++){ int isprime=1; int k; for (k=2;k<i-1;k++){ if (i%k==0){ isprime=0; break; } } if(isprime){ sum+=i; cnt++; } } printf("有%d个素数, 和为%d\n",cnt,sum); return 0; }
我们可以将上述素数判别的单独拿出来 形成一个函数.
#include <stdio.h> // 定义一个函数 isprime int isprime(int i) { int ret=1; int k; for (k=2;k<i-1;k++){ if (i%k==0){ ret=0; break; } } return ret; } // int main() { int m,n; int sum=0; int cnt=0; int i; // 求素数的和 scanf("%d %d",&m,&n); //m=10 n=31 if (m==1)m=2; for (i=m;i<=n;i++){ if(isprime(i)){ sum+=i; cnt++; } } printf("有%d个素数, 和为%d\n",cnt,sum); return 0; }
实例 : 求 1-10 , 20-30 35-45 三者的和
'代码复制是程序不良的表现'!!!! keep it in mind~~, 不利用与将来程序的维护.
#include <stdio.h> void sum(int begin ,int end) { int i; int sum=0; for (i=begin;i<=end;i++){ sum+=i; } printf("%d到%d 的和是%d \n",begin,end,sum); } int main() { sum(1,10); sum(20,30); sum(35,45); return 0; }
综合上述两个例子, 我们来看什么是函数, 如何定义?
void sum(int begin ,int end) 称为函数头, sum是函数名, void 表示函数没有返回的东西, ()内是参数, 参数用逗号, 分开
以下部分称为函数体
{
int i;
int sum=0;
for (i=begin;i<=end;i++){
sum+=i;
}
printf("%d到%d 的和是%d \n",begin,end,sum);
}
函数头中的圆括号很重要, 调用函数也要加(), 否则出错
#include <stdio.h> void fun() { printf("nihao"); } int main() { fun(); // 要加() !!! return 0; }
而判断别素数的函数 是有返回值的
int isprime(int i)
函数体中有return ret
定义一个最大值函数
int max(int a, int b) { int ret ; if(a>b){ ret=a; } else{ ret=b; } return ret; }
#include <stdio.h> int max(int a, int b) { int ret ; if(a>b){ ret=a; } else{ ret=b; } return ret; } int main() { int x; x=max(10,20);// 将函数值赋给x printf("%d\n",x); }
上述函数头也可以写成
#include <stdio.h> int max(int a, int b) { int ret ; if(a>b){ return a; } else{ return b; } //return ret;
但是这样不好, 使得函数有多个出口(多个return), 可行但是不建议用这种!!
函数可以嵌套用 比如max(10, max(100,11));
没有返回值的函数 则定义为
void 函数名(参数表)
那么之后不能用 return 某个值;
如果函数有返回值, 则必须使用带值的return.
注意: 在书写时, 先定义函数再之后进行调用, 不要把函数的定义放在main 后面, 但是也可以通过函数声明实现
#include <stdio.h> int max(int a, int b); // 函数声明!! , 加分号!! 也可以不加 参数, int max(int , int ) int main() { int x; x=max(10,20);// 将函数值赋给x printf("%d\n",x); } int max(int a, int b) { int ret ; if(a>b){ ret=a; } else{ ret=b; } return ret; }
其他问题:
C语言不允许函数的嵌套定义
int main () 实际上也是一个函数,
---- 二维数组
int a[3][5] 表示3*5矩阵
a[0][0], a[0][1],... a[0][4]
..
a[2][0], a[2][1], ...a[2][4]
int a[][3]={ {0,1,2},{3,4,5}, }; // 定义数组列数一定要给出, 行数可以不给, 计算机会自己数
实例: // tic-tac -toe game, 3*3 矩阵中,写1 或者0 ,当有一行 一列或者对角线
可以连成线, 则一方胜出, 游戏结束, 如何判别游戏结束?
遍历每行 每列, 每个对角线 进行判别
#include <stdio.h> int main() { const int size=3; int board[size][size]; int i,j; int n1; int n0; int result=-1; // -1没有人胜出,1 表示写1方胜出, 0表写0方胜出 //下面读入矩阵 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++){ n0=n1=0; for(j=0;j<size;j++){ if(board[i][j]==1){ n1++; }else{ n0++; } } if (n0==size){ result=0; }else if(n1==size){ result=1; } } //再检查列 if (result==-1){ for (j=0;j<size&&result==-1;j++){ n0=n1=0; for(i=0;i<size;i++){ if(board[i][j]==1){ n1++; }else{ n0++; } } if (n0==size){ result=0; }else if(n1==size){ result=1; } } } // 再检查正对角线 if (result==-1){ n0=n1=0; for(i=0;i<size;i++){ if(board[i][i]==1){ n1++; }else{ n0++; } } if (n0==size){ result=0; }else if(n1==size){ result=1; } } // 最后检查次对角线 if (result==-1){ n0=n1=0; for(i=0;i<size;i++){ if(board[i][size-1-i]==1){ n1++; }else{ n0++; } } if (n0==size){ result=0; }else if(n1==size){ result=1; } } // 下结论 if (result==1){ printf("1 win"); } else if(result==0){ printf("0 win"); }else{ printf("nobody win, have an another try"); } return 0; }
接下来, 学习数组的搜索等其他
数据的集成初始化
#include <stdio.h> int main(void) { int a[]={1,2,3,4};// 数组的集成初始化 for (int i=0;i<4;i++){ printf("%d\t",a[i]); } }
换一种形式
#include <stdio.h> int main(void) { int a[4]={1};// 数组的集成初始化 for (int i=0;i<4;i++){ printf("%d\t",a[i]); } }
得到第一个是1 ,后面自动补0
由此若要初始化一个长度n 的数组a 为0, 只需要int a[n]={0};
对于稀疏数组, 大部分是0 ,只有少数几个值非零, 则可以
#include <stdio.h> int main(void) { int a[4]={[1]=1,[3]=4};// 没给定义的位置自动填充0 ,但是只有C99 才可以这样做 for (int i=0;i<4;i++){ printf("%d\t",a[i]); } }
如何让编译器自动数数组长度?, 用sizeof
#include <stdio.h>
int main(void)
{
int a[]={1,2,3,4};
printf("%d\t",sizeof(a)); //16
printf("%d\t",sizeof(a[0])); //4
printf("数组长度是%d\t",sizeof(a)/sizeof(a[0]));
}
得到数组长度是sizeof(a)/sizeof(a[0])
注意数组的赋值
#include <stdio.h> int main(void) { int a[]={1,2,3,4}; int b[]=a; // 错误! 不能这么赋值 }
数组赋值必须采用遍历
for(int i=0;i<length;i++) {
b[i]=a[i];
}
实例:
#include <stdio.h> //搜索一个数是否在数组中存在 int search(int key, int a[],int length); int main(void) { int a[]={1,2,3,4,10,21,32,18,19}; int x; int loc; printf("please input a number\n"); scanf("%d",&x); int length=sizeof(a)/sizeof(a[0]); loc=search(x,a,length); // 调用search函数 if(loc!=-1){ printf("%d在%d位置上\n",x,loc); }else{ printf("%d doesn't exist\n",x); } return 0; } int search(int key, int a[],int length) { int ret=-1; // 记录key 在数组x 中的位置, 0 表示位置1 int i; for(i=0;i<length;i++){ if (a[i]==key){ ret=i; break; } } return ret; } // 注意,数组作为函数参数时, 必须再用另一个参数传入该数组的大小, //因为不能在[] 中给出数组的大小, 不能再利用sizeof 来计算数组的元素个数