当前位置:   article > 正文

零基础学浙大翁恺C语言(6):数组与函数_编写一个程序,计算用户输入的所有数字的平均值

编写一个程序,计算用户输入的所有数字的平均值

零基础学C语言(6):数组与函数

数组

数据可以存放在变量里,每一个变量有一个名字,有一个类型,还有它的生存空间。如果我们需要保存一些相同类型、相似含义、相同生存空间的数据,我们可以用数组来保存这些数据,而不是用很多个独立的变量。数组是长度固定的数据结构,用来存放指定的类型的数据。一个数组里可以有很多个数据,所有的数据的类型都是相同的。

写一个程序计算用户输入的数字的平均数

第4章提到,求平均数不需要记录每一个数,只需要每读到一个数,就把它加到一个累加的变量里,到全部数据读完,再拿它去除读到的数的个数就可以了。

写一个程序计算用户输入的数字的平均数,并输出所有大于平均数的数?

这个时候不记录就不行了,所以一定要把所有的数存下来,等平均数求出后才能判断。
如何记录很多数?int n1,n2,n3…? ——————使用数组,且number的位置会随着程序运行不断递增,来调整n1,n2,n3。(类似python的列表)

#include <stdio.h>

int main()
{
	int x;
	double sum = 0;
	int cnt = 0;
	int number[100]; //定义数组 
	scanf ("%d",&x);
	
	while ( x != -1){  //输入-1退出
		number[cnt]  = x;  //对数组中的元素进行赋值
		sum += x;
		cnt ++;
		scanf("%d",&x);
	}
	if ( cnt > 0 ){
		printf("%f\n",sum/cnt);
		int i; 
		//遍历整个数组,判断是否大于平均数 
		for ( i=0;i<cnt;i++ ){
			if( number[i] > sum/cnt ){ //使用number中的数进行判断.
				printf("%d\n",number[i]);
			}
		}
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

输入1-8,按-1计算,输出平均值和大于平均值的数字。

1 2 3 4 5 6 7 8
-1
4.500000
5
6
7
8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

但这个程序有安全隐患,因为定义的数组元素个数不超过100,但程序中没有判断输入个数有没有超过100。

定义数组

  • <类型>变量名称[元素数量];
  • int grades[100]; 每个单元都是int
  • double weight[20];
  • 元素数量必须是整数
  • C99之前:元素数量必须是编译时刻确定的字面量
  • 是一种容器(放东西的东西),特点是:其中所有的元素具有相同的数据类型;
  • 一旦创建,不能改变大小
  • *(数组中的元素在内存中是连续依次排列的)
  • ·数组的每个单元就是数组类型的一个变量
  • 使用数组时放在[ ]中的数字叫做下标或索引,下标从0开始计数:(是从C语言开始的,简化编译器),**程序员需要保证 [0,数组的大小-1] **
  • 比如定义了int a[10]; 不能写a[10]=3;因为最大就只有a[9]。
  • 数组的下标不一定是整数,字符可以做下标吗?存储时应该会与它本身的ASCII相对应。
int a[255];
a['A'] = 1;
  • 1
  • 2

int a[10]是一个int的数组

  • 每个单元就是一个int类型的变量
  • 可以出现在赋值的左边或右边:a[2] =,a[1]+6;
  • *在赋值左边的叫做左值

C99可以实现用户输入任意数字的数组。
在这里插入图片描述

数组例子:统计个数

写一个程序,输入数量不确定的[0,9]范围内的整数,统计每一种数字出现的次数,输入-1表示结束

不需要记录每个数字,但要记录每个数字出现了多少次。

#include <stdio.h>

int main(void)
{
	const int number = 10; //数组的大小,C99后才能用
	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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

函数定义与使用

在这里插入图片描述
isPrime有返回一个ret。

求和

求出1到10、20到30和35到45的三个和

#include <stdio.h>

int main()
{
	int i;
	int sum;
	
	for (i=1,sum=0;i<=10;i++){
		sum+=i;
	}
	printf("%d到%d的和是%d\n",1,10,sum);
	
	for (i=20,sum=0;i<=30;i++){
		sum+=i;
	}
	printf("%d到%d的和是%d\n",1,10,sum);
	
	for (i=35,sum=0;i<=45;i++){
		sum+=i;
	}
	printf("%d到%d的和是%d\n",1,10,sum);
	
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

用到了ctrl c v,输出:

110的和是55
110的和是275
110的和是440
  • 1
  • 2
  • 3

三段几乎一模一样的代码,这种事情在程序中叫“代码复制”,是程序质量不良的表现,等到程序维护时需要维护多处。所以用函数把重复的提取出来,再调用函数。

#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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

什么是函数

函数是一块代码,接收零个或多个参数做一件事情,并返回零个或一个值。

在这里插入图片描述
void返回类型就是不返回任何东西,不能使用带值的return,可以没有return。
函数调用一定要有圆括号(),即使没有参数。如果有参数,则需要给出正确的数量和顺序,来初始化函数中的参数

从函数中返回值

void不返回任何东西,int返回int类型。
return停止函数的执行,并送回一个值。

int max(int a, int b)
{
	int ret;
	if (a>b){
		ret=a;
	}else{
		ret=b;
	}
	return ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

调用函数

#include <stdio.h>
//一个函数里用多个return也可以。
int max(int a, int b)
{
	//int ret;
	if (a>b){
		return a;
	}else{
		return b;
	}
	//return ret;
}
//但不符合“单一出口”的理念,不利于修改。只是可以这么做,但是不好的做法。

int main()
{
	int a,b,c;
	a=5;
	b=6;
	c=max(10,22);
	c=max(a,b);
	c=max(c,23);
	printf("%d\n",max(a,b));
	printf("%d\n",max((max(a,b)),c));
	//函数可以赋值给变量再传递给函数(套用)。
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

函数先后关系

先把函数写在上面,调用的代码写在下面。因为C的编译器是自上而下顺序分析代码的,必须要在前面看到过长什么样子。

可以先用一个函数原型告诉编译器这个函数长什么样子(函数名称,参数数量,参数类型,返回类型),然后调用时候会根据原型判断。

 //函数原型,以分号";"结尾。以前写在函数main里面。
double max(double a, double b); 

int main()
{
	int a,b,c;
	a=5;
	b=6;
	c=max(10,12);
	printf("%d\n",c));
	max(12,13); //根据原型判断
	return 0;
}

//实际的函数头
double max (double a, double b)
{
	int ret;
	if (a>b){
		ret=a;
	}else{
		ret=b;
	}
	return ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

调用函数问题:类型不匹配?

  • 调用函数时给的值与参数的类型不匹配是C语言传统上最大的漏洞。
  • 编译器总是悄悄替你把类型转换好,但是这很可能不是你所期望的,可能遗漏错误。
  • 例如:
#include <stdio.h>

void cheer(int i)
{
	printf("cheer %d\n",i);
}


int main()
{
	cheer(2.5); 
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 返回的是cheer 2,而不是cheer 2.5.因为自动转换了int类型,甚至不会出现warning提示你!
  • 后续的语言,C++/Java在这一方面很严格。

区分参数和值!

区分本地/局部变量,全局变量!

调用函数时的逗号和逗号运算符怎样区分?

  • 调用函数时的圆括号里的逗号是标点符号,不是运算符 f(a,b)
  • 只有用2个括号时,才是先进行里面的逗号运算符,再函数 f((a,b))
  • 区别是2个参数还是1个参数。

关于main

  • int main()也是一个函数
  • 要不要写成int main(void)?
  • return的0有人看吗?
  • Windows: if error level 1。正常是0.
  • Unix Bash: echo $?
  • h: echo $status

二维数组

前面讲的都是1维数组,是一个下标,线性的。
二维数组通常理解为矩阵,int a[3][5],是一3行5列的矩阵,要用a[i][j], 不能用a[i,j]!

对于二维数组,遍历就需要两重循环。外面那层遍历行号,里面那层遍历列号。

二维数组的初始化

int a[][5]={
	{0,1,2,3,4},
	{2,3,4,5,6},
};
  • 1
  • 2
  • 3
  • 4
  • 列数是必须给出的,行数可以由编译器来数
  • 每行一个{},逗号分隔
  • 最后的逗号可以存在,有古老的传统·
  • 如果省略,表示补零
  • 也可以用定位(*c99 ONLY)

tic-tac-toe游戏(井字棋)

  • 输入矩阵,判断谁赢了
  • 读入一个3X3的矩阵,矩阵中的数字为1表示该位置上有一个×,为0表示为〇
  • 程序判断这个矩阵中是否有获胜的一方,输出表示获胜一方的字符×或O,或输出无人获胜
#include <stdio.h>


int main()
{
	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;
		}
	}
}

	//检查对角线 [i][i],又分正负对角线
	numOfO = numOfX=0;
	for (i=0;i<size;i++){
		if (board[i][i] == 1){
				numOfX ++;
			}else{
				numOfO ++;
			}
		}

	if (numOfO == size){
			result = 0;
		} else if (numOfX == size){
			result = 1;
		}
		
	//负对角线 
	numOfO = numOfX=0;
	for (i=0;i<size;i++){
		if (board[i][size-i-1] == 1){
				numOfX ++;
			}else{
				numOfO ++;
			}
		}
	 
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

行和列的代码也可以合并起来。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/517678
推荐阅读
相关标签
  

闽ICP备14008679号