一(一维数组)
①(代码)反序输出
任务描述
编程读入若干整数,按相反顺序输出。
输入格式:
第一行是一个整数N(N<=100),表示这一组数据的个数。接下来的一行是N个整数,用空格或回车分隔。
输出格式:
按输入顺序的相反顺序输出所有数据,用逗号分隔。
输入样例:
3
5 10 8
输出样例:
8,10,5
任务分析
题目要求读入n个数(n<=1000),按反序输出。这样就需要首先读入所有的数,然后再按要求的反序输出。而需要读入的数据最多可能有1000个,数量还不固定,如何存储这些数据呢?我们总不能定义1000个变量吧,用传统的单变量存储这些数据是不现实的。
相关知识 一维数组
前面我们使用的变量都属于简单变量,C语言中还提供了构造数据类型(如数组、结构体、共用体)和指针等。所谓构造数据类型,就是由基本数据类型按照一定规则组合而成的新的数据类型。本章主要介绍C语言中数组的使用,包括一维数组、二维数组和字符数组的定义、使用等。
1.认识数组 C语言提供了一个构造类型的数据结构——数组。 数组是一种特殊的构造数据类型,它是一组由若干个相同类型的变量构成的集合,这些变量具有一个相同的名字——数组名,各个变量之间用下标(序号)来区分。每个变量称为这个数组的元素,数组的下标是从0开始计数的。 例如,有个名字为a的整型(int)数组,共有10个元素,则在C语言中这10个数组元素的名字分别为a[0]、a[1]、a[2]、a[3]、a[4]、a[5]、a[6]、a[7]、a[8]、a[9]。 一个数组的所有元素在内存中是顺序存放的,比如刚刚提到的数组a,在内存中共占据连续的40个字节的空间(假定每个int型数据占4个字节),前4个字节用来存放a[0],接下来的4个字节用来存放a[1],以此类推。 数组是具有一定顺序关系的若干个相同类型变量的集合体,数组属于构造类型。如果数组元素之间只通过一个下标分量来相互区分,那它就是一维数组。
2.一维数组的定义 一维数组是只有一个下标的数组,通过一个下标序号就能确定数组元素。数组和其它普通变量一样,在程序中必须先定义后引用。 一维数组定义的一般形式为: 类型说明符 数组名[整型常量表达式]; 例如: int a[10]; /* 数组名为a,类型为整型,有10个元素 */ float f[20]; /* 数组名为f,类型为单精度实型,有20个元素 */ char ch[20]; /* 数组名为ch,类型为字符型,有20个元素 */ 功能说明: (1)类型说明符定义了数组元素的类型,该数组的所有元素必需具有相同的数据类型。 (2)数组名和变量名的命名规则相同,都是标识符。 (3)整型常量表达式表明数组的长度(元素个数),要放在方括号内,且必须是常量表达式(C99标准之前)。表达式的值定义了该数组一共有多少个元素。 (4)数组元素的下标从0开始,所以上文中数组a的元素有a[0]、a[1]、a[2]、a[3]、a[4]、a[5]、a[6]、a[7]、a[8]、a[9]共10个元素;数组f的元素有f[0]、f[1]、f[2]、… … f[19]共20个元素。
3.一维数组元素的引用 数组必须先定义后引用。可以像使用变量一样使用数组的元素。我们一次只能引用一个数组元素,而不能一次引用整个数组(字符数组除外)。 引用数组元素的一般形式是: 数组名[下标] 下标可以是整型常量或整型表达式,例如下列语句是合法的: a[0]=5; a[1]=a[0]*5+9; a[a[0]]=6;
4.一维数组的遍历 对数组中的每个元素依次访问一遍,称为对数组的遍历。程序中通常在循环结构里让循环变量(计数器)从0开始,每次循环后加1,直到数组最大下标的方法来遍历整个数组。
程序代码
#include<stdio.h>
int main()
{
int a[1010], i, n; //定义数组,长度比题目要求的最大长度多10个
scanf("%d", &n); //首先读入n,表示实际数据的个数
for (i = 0;i < n;i++) //依次读入每个数据放入数组中(遍历)
{
scanf("%d", &a[i]); //读入整数赋值给a[i]
}
for (i = n - 1;i >= 0;i--) //反向输出穷举下标i从n-1到0(遍历)
{
if (i < n - 1)printf(","); //第二项开始前面输出逗号
printf("%d", a[i]); //输出a[i]
}
return 0;
}
代码分析
1.程序中定义int型数组a有1010个元素,因为题目要求最多有1000个数据需要存储,所以我们在定义数组的时候至少要定义1000个元素的数组,为了保险起见,我们在定义数组时可以多定义一些元素,避免数据装不下的情况。
2.第一个for循环,通过穷举i从0到n-1,遍历a[0]到a[n-1],读入每一个数据到a[i]中。这样就实现了读入n个数据,存储到n个变量(数组元素)中。
3.第二个for循环,通过穷举i从n-1到0,遍历a[n-1]到a[0],输出每一个a[i]。从而实现反序输出。 从以上代码可以看出,数组是一组具有相同名字的变量的集合,通过下标区分。 有了数组,我们就可以对多个变量(数组元素)依次统一处理了,例如代码中的遍历输入和遍历输出。这也正式数组存在的意义。
②(代码)输出第n个素数
任务描述
编程找出前1000个素数存放到数组中,然后输入一个整数N,输出第N个素数的值。
输入格式:
输入有多组数据,为若干个空格分隔的整数。
输出格式:
对于输入数据中每个n,输出第n个素数的值,多个输出之间以逗号分隔。
输入样例:
1 2 3 4 5 4 3
输出样例:
2,3,5,7,11,7,5
#include<stdio.h>
#include<math.h>
int main()
{
int a[1000]; //存放前1000个素数
int i, m; // m表示需要判断的数
int count = 0; //统计个数
int n; //输入 数据
char x;
for (m = 2;; m++)
{
for (i = 2; i <= sqrt(m); i++)
{
if (m % i == 0)
{
break;
}
}
if (i > sqrt(m))
{
a[count++] = m;
}
if (count > 1000)
{
break;
}
}
int b = 0;
while (scanf("%d ", &n) != EOF) //输入 n组数据
{
if (b)
{
printf(",");
}
printf("%d", a[n - 1]); //从第二个数开始输出,和%d
b++;
}
return 0;
}
相关知识 一维数组的初始化
数组元素可以通过赋值语句来进行直接赋值,也可以在定义数组的同时对其进行初始化赋值。
(1)在定义数组时对数组全部元素进行初始化。例如: int a[10]={0,1,2,3,4,5,6,7,8,9}; 将数组元素的初值用逗号分隔依次放在一对大括号内。初值与数组元素是一一对应的(多余的元素会被忽略),所以经过上述初始化后,数组元素a[0]~a[10]的值依次为0~9。
(2)在定义数组时对数组部分元素进行初始化。例如: int a[10]={0,1,2,3,4}; 数组定义了10个元素,初始化列表中只给出了5个值,这5个值依次赋给a[0]至a[4],其余数组元素的值系统自动赋值为0。
(3)如果数组在定义时没有进行初始化操作,那么它所有元素的初始值为一个随机值。
(4)定义数组时给没有指定数组长度,根据初值数量自动确定长度。例如:
int c[ ]={1,2,3,4,5,6,7,8,9,10}; 数组的长度将根据初始化元素值的数量自动识别为10。
代码分析案例 请分析以下代码的执行结果
//一维数组的初始化示例代码
#include<stdio.h>
int main()
{
int a[10],i;
int b[10]={1,2,3,4};
int c[]={1,2,3,4,5,6,7,8,9,10};
printf("\n数组a:");
for(i=0;i<10;i++)
{
printf("%d ", a[i]);
}
printf("\n数组b:");
for(i=0;i<10;i++)
{
printf("%d ", b[i]);
}
printf("\n数组c:");
for(i=0;i<10;i++)
{
printf("%d ", c[i]);
}
return 0;
}
执行程序输出:
数组a:2879 54540 4204204 0 654650 87897 5256 -545 8 2550
数组b:1 2 3 4 0 0 0 0 0 0
数组c:1 2 3 4 5 6 7 8 9 10
代码分析:
对于未进行任何初始化赋值的数组元素,和未初始化的变量是同一情况,其值是不确定的。此例程序在不同机器上会得到不同的输出结果。定义数组a时未赋初值,所有元素的值不确定。定义数组b时给部分元素赋了初值,其余元素做清0处理(赋0值)。定义数组c时给没有指定数组长度,根据初值数量自动确定长度为10。
相关知识 数组在内存
1.数组在内存中连续存放 数组的所有元素总是被安排在一块连续的存储空间,数组元素在内存中顺次存放,它们的地址是连续的。C语言还规定,数组名就是数组的首地址,也可以理解为数组名就是数组中第1个元素(下标为0)的地址。
代码分析案例 请分析以下代码的执行结果
// 数组元素在内存中连续存放
#include<stdio.h>
int main()
{
int a[10], k;
for (k = 0;k < 10;k++) a[k] = k;
{
printf("Array address:%x\n", a);
}
for (k = 0;k < 10;k++)
{
printf("a[%d]=%d,Memory address:%x\n", k, a[k], &a[k]);
}
return 0;
}
执行程序输出:
Array address:22fe20
a[0]=0,Memory address:22fe20
a[1]=1,Memory address:22fe24
a[2]=2,Memory address:22fe28
a[3]=3,Memory address:22fe2c
a[4]=4,Memory address:22fe30
a[5]=5,Memory address:22fe34
a[6]=6,Memory address:22fe38
a[7]=7,Memory address:22fe3c
a[8]=8,Memory address:22fe40
a[9]=9,Memory address:22fe44
程序分析:
本例程序中通过%x格式说明符以16进制整数形式输出内存地址值(内存地址值其实是一个无符号整数)。通过输出可以看出,数组名就是数组的首地址,每个元素占4个字节,从a[0]至a[9]共10个元素在内存中存放在连续的存储空间。
2.数组长度 定义数组时,要求数组长度是一个常量表达式,表示数组的长度(元素个数)。下列数组的定义是合法的。
int b[10 + 20]; //相当于 int b[30];
double d[10 + 20 / 6]; //相当于 double d[13];
int c['A']; //相当于 int c[65];
int x[(int)5.6]; //相当于 int x[5];
下面程序代码的数组定义也是合法的:
#define N 10
int main()
{
int a[N], b[N + 10]; //预处理后替换成 int a[10],b[20];
}
下面两种定义数组的情况是错误的,将产生编译错误:
![](https://i-blog.csdnimg.cn/blog_migrate/3f350531d62d163b9857e728f3a1061e.png)
3.数组大小 我们可以使用sizeof(数组名)来测试数组整体大小,例如: 如果有定义int a[10];double b[20];那么sizeof(a)的值为40,说明数组a在内存中整体占40个字节的空间。sizeof(b)的值为160,说明数组b在内存中整体占160个字节的空间。
二(一维数组的应用)
①(代码)斐波那契数列
任务描述:
斐波那契(Fibonacci)数列是这样一个数列:1、1、2、3、5、8、13、21、……, 这个数列前两项是1,从第三项开始,每一项都等于前两项之和。 编程读入两个正整数A和B,输出Fibonacci数列的第A项到第B项。
输入格式:
一行中给出2个不超过90的正整数A和B(A<=B)。
输出格式:
输出Fibonacci数列的第A项到第B项,5个数一行,行内数据以一个空格分隔。
输入样例:
1 8
输出样例:
1 1 2 3 5
8 13 21
输入样例:
76 90
输出样例:
3416454622906707 5527939700884757 8944394323791464 14472334024676221 23416728348467685
37889062373143906 61305790721611591 99194853094755497 160500643816367088 259695496911122585
420196140727489673 679891637638612258 1100087778366101931 1779979416004714189 2880067194370816120
任务分析
我们可以定义一个数组,事先将Fibonacci数列的前90个元素存储进去,然后我们想输出哪段元素都可以轻易实现。因为数组元素的值到下标90附近时会很大,所以数据类型我们定义成long long型。
程序代码
#include<stdio.h>
#define N 90
int main()
{
long long int a, b, i, k, f[N + 5] = { 0 }; //定义数组长度为95(比90稍多一点)
f[1] = f[2] = 1; //前两项f[1]和f[2]赋值1
for (i = 3;i <= N;i++) //计算f[3]到f[N]
{
f[i] = f[i - 1] + f[i - 2];
}
scanf("%ld%ld", &a, &b); //读入a和b
for (k = 0, i = a;i <= b;i++, k++) //输出f[a]到f[b]
{
if (k % 5 > 0)
{
printf(" "); //控制空格的输出
}
printf("%lld", f[i]);
if (k % 5 == 4 && i < b)
{
printf("\n"); //控制回车的输出
}
}
return 0;
}
②(代码)三角形数
任务描述:
传说古希腊毕达哥拉斯(约公元前570-约公元前500年)学派的数学家经常在沙滩上研究数学问题,他们在沙滩上画点或用小石子来表示数。比如,他们研究过1,3,6,10,15,21,28,36,45,55,66,78,91……这些数被称为三角形数。
![](https://i-blog.csdnimg.cn/blog_migrate/b16246bba1904b60ca37a9c1fa86bc5d.png)
编程将前50个三角形数存入数组,然后输出。每10个一行。
输出样例:
1 3 6 10 15 21 28 36 45 55
66 78 91 105 120 136 153 171 190 210
231 253 276 300 325 351 378 406 435 465
496 528 561 595 630 666 703 741 780 820
861 903 946 990 1035 1081 1128 1176 1225 1275
#include<stdio.h>
int main()
{
int i, j = 2, arr[50];
for (i = 1;i < 50;i++)
{
arr[0] = 1;
arr[i] = arr[i - 1] + j;
j++;
}
for (i = 0;i < 50;i++)
{
if (i == 9 || i == 19 || i == 29 || i == 39)
{
printf("%d\n", arr[i]);
}
else
{
printf("%d ", arr[i]);
}
}
return 0;
}
③(代码)数组元素逆置
任务描述
编程读入10个整数存入数组中,正序输出后,将数组元素逆序重置后再输出。
输入样例:
42 75 29 66 79 55 53 43 27 41
输出样例:
42,75,29,66,79,55,53,43,27,41
41,27,43,53,55,79,66,29,75,42
#include<stdio.h>
int main()
{
int a, arr[10];
for (int i = 0;i < 10;i++)
{
scanf("%d", &a);
arr[i] = a;
if (i != 9)
{
printf("%d,", arr[i]);
}
else
{
printf("%d", arr[i]);
}
}
printf("\n");
int left = 0, right = sizeof(arr) / sizeof(arr[0]) - 1;
while (left <= right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
for (int i = 0;i < 10;i++)
{
if (i != 9)
{
printf("%d,", arr[i]);
}
else
{
printf("%d", arr[i]);
}
}
return 0;
}
④(代码)大赛(冒泡排序)
任务描述:
8号选手参加校园歌手大赛,编程读入20个整数(70-100之间)并存入数组中做为20个评委的打分,请按题目要求编程实现输出样例要求的功能(最后得分为去掉最高分和最低分后的平均分)。
输入样例:
82 89 83 70 94 90 86 73 79 83 89 97 95 93 82 94 96 94 91 84
输出样例:
去掉一个最高分:97分
去掉一个最低分:70分
8号选手最后得分:87.611分
#include<stdio.h>
int main()
{
int a, arr[20] = { 0 };
for (int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)
{
scanf("%d", &a);
arr[i] = a;
}
int i = 0, j = 0;
for (i = 0;i < sizeof(arr) / sizeof(arr[0]) - 1;i++) //冒泡排序,后面写到函数中
{
int flag = 1;//优化
for (j = 0;j < sizeof(arr) / sizeof(arr[0]) - 1 - i;j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag)
{
break;
}
}
printf("去掉一个最高分:%d分\n", arr[19]);
printf("去掉一个最低分:%d分\n", arr[0]);
arr[19] = 0;
arr[0] = 0;
int s = 0;
for (i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)
{
s += arr[i];
}
float average = s / 18.0;
printf("8号选手最后得分:%.3f分", average);
return 0;
}
⑤(代码)大赛新规则
任务描述
8号选手参加校园歌手大赛,编程读入20个整数(0-100之间)并存入数组中做为评委打分。最后得分计算规则:先计算20个数的平均分,然后去掉所有与平均分相差10分以上的分数,最后把剩下的分数再取平均做为最后得分。如果没有剩下分数,此次打分无效。
输入样例:
86 87 83 70 99 94 78 89 86 80 97 84 90 87 95 87 84 99 84 95
输出样例:
所有评委平均分:87.700分.
不合格得分:70 99 99 .
最后得分:87.412分.
输入样例:
72 72 73 71 71 72 73 71 71 72 98 98 97 100 99 97 97 99 99 99
输出样例:
所有评委平均分:85.050分.
不合格得分:72 72 73 71 71 72 73 71 71 72 98 98 97 100 99 97 97 99 99 99 .
无合格打分.
#include<stdio.h>
int main()
{
int i, j, c = 0, arr[20], r;
float s = 0, s2 = 0, p, p2;
for (i = 0;i < 20;i++)
{
scanf("%d", &j);
arr[i] = j;
s += arr[i];
}
p = s / 20;
printf("所有评委平均分:%0.3f分.\n", p);
printf("不合格得分:");
for (i = 0;i < 20;i++)
{
if (arr[i] > p)
{
r = arr[i] - p;
}
else
{
r = p - arr[i];
}
if (r > 10)
{
printf("%d ", arr[i]);
arr[i] = 0;
c++;
}
else
{
continue;
}
}
printf(".\n");
for (i = 0;i < 20;i++)
{
s2 += arr[i];
}
if (s2 == 0)
{
printf("无合格打分.");
}
else
{
p2 = s2 / (20 - c);
printf("最后得分:%0.3f分.", p2);
}
return 0;
}