上一篇文章:入门级 C语言期末复习(2)——基本控制结构
构造类型——数组
数组是我们遇到的第一个构造数据类型,是由若干个相同的基本类型组成的一个合集。这些合集在内存里是连续分布的。这个合集里的数据有一个共同的名字,称为数组名。用"数组名[ ]"的形式可以定义和访问数组。这里的数组名实际上也就是这个数组的首地址。
当你需要对若干个数据进行存储、操作的时候,就会用到数组。这里的数组是由同一种基本类型构造而来的,也就是说,我们可以得到整型数组,浮点型数组和字符型数组,实际上各种数组的使用上都是相似的,除了字符数组的使用有些特别。
对于数组,有一维数组和多维数组(目前我们讨论二维数组就足够了)之分。一维数组对应着行,二维数组对应着行和列,三维数组对应着行、列和高。多维数组就是更多不同方向的量度指标罢了。这种理解比较直观。但实际上我们可以用存储方式的角度理解。
我们可以认为a是一个数组其中有a[0]、a[1]、a[2]三个元素,这三个元素又可以看成是三个数组,如a[0]中有a[0][0]、a[0][1]、a[0][2]三个元。因此多维数组可以看作是一维数组的延申或者说嵌套。多维数组在内存中的存储也是连续的,a[0][0]的地址加1(这里的加1指加上所对应的字节,整型为4)就是a[0][1],a[0][2]这个元素加1就是a[1][0]。实际上,我们可以将a[0]看作是一个有12个字节的大元素,因此a[0]加1(也就是加12个字节),就是a[1]。理解这一点对后面指针的学习大有帮助。
考查数组的话肯定会涉及到循环的使用,所以知识都是一环扣一环的,要把基本功打扎实。考到数组的话一般都是给你一堆数据进行操作处理。接下来以数组类型划分举几个例题供大家参考。
一维数组一次循环
插入数据
掌握遍历的方法,不仅可以从前向后,也可以从后往前。
#include <stdio.h>
int a[16]={2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 34, 71, 79, 97, 103};
void display()
{
int i;
for(i=0; i<16; i++)
printf("%d ", a[i]);
}
int main()
{
int n,i;
scanf("%d", &n);
for(i=14; i>=0; i--) //倒序查找,可以将空缺的位置向前移动
if(a[i]>n)
a[i+1]=a[i];
else //查找到目标位置,跳出循环
break;
a[i+1]=n; //将目标位置赋值
display();
return 0;
}
一维数组两次循环
统计不同数字的个数
#include <stdio.h>
int main()
{
int i,count=0,j,a[21];
for (i=0;i<20;i++)
{
scanf("%d",&a[i]);
}
for (i=0;i<19;i++)
{
for (j=i+1;j<20;j++)
{
if (a[i]==a[j]) //从当前数据向后找到有无重复的数据,有则用count记录
{
count++;
break;
}
}
}
printf("%d",20-count);
return 0;
}
输出不同数字
这道题与上一道题目实际上有异曲同工之妙,大家可以通过比较来理解。
#include"stdio.h"
int main()
{ int a[20];
int i,t,p=0;
for(i=0;i<10;i++)
{
scanf("%d",&a[i]);
for(t=0;t<i;t++)
if(a[t]==a[i])
break;
if(t==i) //这里实现了只输出数组中的第一个不重复的数
printf("%d\n", a[i]);
}
return 0;
}
最近对问题
这个题目有的同学想用二维数组,其实大可不必,用两个一维数组就可以实现,两个循环的嵌套实现两两数对之间的比较,将最小的距离记录下来即可。
#include <stdio.h>
#include <math.h>
int main()
{
int a[50],b[50],i,j,n;
double min,d;
scanf("%d",&n);
for (i=0;i<n;i++)
scanf("%d%d",&a[i],&b[i]);
min=sqrt((a[0]-a[1])*(a[0]-a[1])+(b[0]-b[1])*(b[0]-b[1])); //初始化min
for (i=0;i<n-1;i++)
{
for (j=i+1;j<n;j++)
{
d=sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]));
if (min>d) //寻找最小值
{
min=d;
}
}
}
printf("%.3f",min);
return 0;
}
排序
排序也是通过两重循环可以实现的,内外层的循环条件要区分清楚。
冒泡排序
冒泡排序是将数组中未排序部分中最大的一项通过依次交换的方式转移到未排序部分的末尾处。
#include <stdio.h>
int main()
{
int a[10]={9,8,7,6,5,4,3,2,1,0},i,j,t,n=10;
for (i=0;i<n-1;i++)
{
for (j=0;j<n-i-1;j++)
{
if (a[j]>a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
for (i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
选择排序
选择排序的原理是在未排序部分中选择最小的一个与未排序部分的首位进行交换。经过n-1趟,排序完成。
#include <stdio.h>
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9},i,j,t,min=0,n=10;
for (i=0;i<n-1;i++)
{
min=i;
for (j=i+1;j<n;j++)
{
if (a[min]<a[j])
{
min=j;
}
}
{
t=a[min];
a[min]=a[i];
a[i]=t;
}
}
for (i=0;i<n;i++)
printf("%d ",a[i]);
return 0;
}
二维数组
主对角线上的元素之和
主对角线也就是行和列下标相同的数组元素,直接输出结果即可。
#include <stdio.h>
int main()
{
int i,j,a[3][4];
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
scanf("%d",&a[i][j]);
}
}
/*for (i=0;i<n;i++)
{
sum+=a[i][i]; //行和列未确定时可以这样实现
}*/
printf("%d",a[0][0]+a[1][1]+a[2][2]);
return 0;
}
鞍点
在这里我们可以运用一个数组下标的小技巧来简化问题,遍历每一行,找到行中最大,标记该位置。遍历每一列,找到列中最小,标记该位置。遍历整个二维数组,找到有两个标记的元素,输出即可。
#include <stdio.h>
int main()
{
int i,j,min,max,a[3][4],ii,jj,b[3][4],count=0;
for(i=0;i<=2;i++)
{
for(j=0;j<=3;j++)
{
scanf("%d",&a[i][j]);
b[i][j]=0; //b数组用来记录标记次数,初始状态为0
}
}
for(i=0;i<=2;i++)
{
max=a[i][0];
for(j=0;j<=3;j++)
{
if(a[i][j]>=max) //找行中最大
{
max=a[i][j];
}
}
for(j=0;j<=3;j++)
if(a[i][j]==max)
{
b[i][j]++; //标记加1
}
}
for(i=0;i<=3;i++)
{
min=a[0][i];
for(j=0;j<=2;j++)
{
if(a[j][i]<=min) //找列中最小
{
min=a[j][i];
}
}
for(j=0;j<=2;j++)
{
if(a[j][i]==min)
{
b[j][i]++; //标记加1
}
}
}
for(i=0;i<=2;i++)
{
for(j=0;j<=3;j++)
{
if(b[i][j]==2) //有2个标记,则输出
{
printf("%d\n",a[i][j]);
count++;
}
}
}
if (count==0) //数组中没有标记,输出NO
printf("NO");
return 0;
}
数组的内容与循环结合紧密,大家需要把基本功打扎实。