
8.2.1 数组运算
数组集成初始化
数组定义和初始化有两种方式:
确定大小的数组
int number [100] ;//定义数组 数组大小为100
number [cnt] = x;//对数组里的元素赋值:number数组里面的第cnt个元素赋值为x
不确定大小的数组
int a[] = {2,4,6,7,1,3,5,9,11,13,23,14,32};
第二种方式, 没有给出数组大小,直接用大括号给出了数组的所有元素的初始值,这种定义方法不需要给出数组的大小,让编译器替你数数填入。
相反的,如果定义了数组的大小,在大括号内录入了少于数组大小-1的数据,则编译器会替你将剩余的单元填上0.
int a[13]={2}; //2 0 0 0 0 0 0 0 0 0 0 0 0
数组初始化【改进】
int main(void)
{
int x;
const int NUMBER = 10;//定义数组大小
int count[NUMBER]={0};//定义数组并初始化
int i;
//for(i=0;i<NUMBER;i++)
//{
// count[i]=0;
//}
这段注释掉的代码与初始化为0的语句作用相同
初始数据稀疏的数组C99
//集成初始化的定位

数组里面有几个数 sizeof
sizeof:可以给出整个数组占据的内容大小,单位是字节。
int a[ ]={1,2,3,4,5,6,7,8,9,10,11,12,13}
对于数组a,sizeof(a)=52 sizeof(a[0])=4
然后除以类型的字节单位(可以用数组单个元素大小代替),就可以得到数组大小
sizeof(a)/sizeof(a[0])
//这个代码的好处是当我们修改数组中初始数据时,不需要改动遍历代码
数组的赋值
int a[]={2,4,6,8,10};
int b[]=a;//不可以!!!!
可以这样将数组a赋值给b数组吗?完全不能~
因为数组是特殊的变量(实际上是const)
要想将一个数组的元素赋值给另一个数组,必须采用遍历
遍历数组for

通常我们使用for循环遍历数组,当设置循环变量 (i>0;i<数组长度/13;i++),这样的话循环体内最大的i正好是数组最大的有效下标 /12
常见错误:
循环条件错误设置为:<=数组长度
离开循环之后用i值做数组元素下标//此时i的值是数组无效的下标/13

注意:
search函数中,数组作为函数参数时候,因为不能在[]中给出数组的大小
不能利用sizeof计算数组元素个数
所以需要用另一个参数来传入数组大小。而且在函数头中输入数组大小也是没有意义的
int search(int key,int a[10])//这样的定义是没有意义的
8.2.2素数表+判断素数
用比x小的素数来测试x是否为素数。需要一张已有素数的表,因为素数比起全体数字来说是稀有的。如果要构造这样一张表,假如是100个素数的表,程序如下
#include<stdio.h>
int isPrime(int x, int knownPrimes[], int numberofKnownPrimes);
int main()
{
const int NUMBER = 10;//定义数组大小10
int prime[NUMBER] = { 2 };//初始化为2,为第一个素数
int count = 1;//计数变量为1,已经有一个素数2了
int i = 3;//从3开始测试
while (count<NUMBER)
{
if (isPrime(i,prime,count))//如果用函数判定i是素数
{
prime[count++] = i;//将i添加到素数数组中,并且计数变量增1,作为prime的下标
}
//调试代码
{
printf("i=%d \tcnt=%d\t",i,count);
int i;//局部变量,仅在这个大括号内生效
for(i=0;i<NUMBER;i++)
{
printf("%d\t",prime[i]);
}
printf("\n");
}
//tiaoshi
i++;//数字步进1
}
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 knownPrimes[], int numberofKnownPrimes)
{
int ret = 1;
int i;
for ( i = 0; i < numberofKnownPrimes; i++)
{
if (x%knownPrimes[i]==0)
{
ret = 0;
break;
}
}
return ret;
}
要点:
prime[count++] = i;//
此时cnt不再是“计数器”,不能理解为计数已经找到的素数个数,而是一种“指针”类似,依次指向数组的下标。
cnt++是先取值后自增
++a:先自增后取值;a++:先取值后自增
将第i添加到下标为cnt的素数数组中,然后cnt自增,指向数组的下一个位置
调试代码,要加{ 大括号 }
大括号中可以定义自己的局部变量 i ,仅在这个大括号内生效
也可以先使用外面的变量的值,然后再重新定义
//调试代码
{
printf("i=%d \tcnt=%d\t",i,count);
int i;//局部变量,仅在这个大括号内生效
for(i=0;i<NUMBER;i++)
{
printf("%d\t",prime[i]);
}
printf("\n");
}
新思路的素数表
前几种方案都是不断遍历数字,判断是否是素数。那么思考一下如果我们是直接构造一张表,最后留下来的数都是素数。算法如下:

这种方法是遍历倍数。简单来说,第一个数是2,是素数,删去2的倍数。然后下一个数字是3,是素数,删去3的倍数。下一个是5,是素数,删去5的倍数。然后是7,删去7的倍数。然后是11...依次类推,最后留在这个表里的数字就都是素数了。

伪代码如图:(n以内素数)

具体做法

开始将所有数字都赋值1,
然后从2开始判断素数,将素数倍数的下标赋值0(也就意味着不是素数),
并且作为筛选的条件,所以当其不作为素数时不会计数。
在最后的循环会遍历输出全部素数。
25以内的素数,不会判断25是不是素数,只能数到23是素数。
PS:算法不一定和人的思考方式相同~
8.2.3二维数组
二维数组的概念
int a[3][5] ; //可以理解为3行5列的矩阵。a00 - a24

二维数组的遍历
与一维数组不同,此遍历需要用到两重循环

a[i][j]是一个int型变量,表示第i行第j列
a[i,j]什么意思?//逗号运算符右边的作为结果,因此相当于a[j]
二维数组的初始化

(定位就是从半中间开始定义)
二维数组例子:井字棋

#include <stdio.h>
int main()
{
const int SIZE = 3;
int board[SIZE][SIZE];
int i,j;
int num0fX;//X
int num0f0;//O
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; i++)
{
num0f0 = num0fX = 0;
for ( j = 0; j < SIZE; j++)
{
if (board[i][j]==1)
{
num0fX++;
}
else
{
num0f0++;
}
}
if (num0f0==SIZE)
{
result = 0;
}
else if (num0fX == SIZE) {
result = 1;
}
}
//检查列
for (j = 0; j < SIZE; j++)
{
num0f0 = num0fX = 0;
for (i = 0; i < SIZE; i++)
{
if (board[i][j] == 1)
{
num0fX++;
}
else
{
num0f0++;
}
}
if (num0f0 == SIZE)
{
result = 0;
}
else if (num0fX == SIZE) {
result = 1;
}
}
//正对角线
num0f0 = num0fX = 0;
for (i = 0; i < SIZE; i++)
{
if (board[i][i] == 1)//a11 a22 a33
{
num0fX++;
}
else
{
num0f0++;
}
}
if (num0f0 == SIZE)
{
result = 0;
}
else if (num0fX == SIZE) {
result = 1;
}
}
//副对角线
num0f0 = num0fX = 0;
for (i = 0; i < SIZE; i++)
{
if (board[i][SIZE-i-1] == 1)
{
num0fX++;
}
else
{
num0f0++;
}
}
return 0;
}