引言
1.什么是数组
数组就是一次性定义了一群变量,没有变量名,但可以根据位置放,like home。
//输入1 2 3 4 5 6 7 8 9 10 -1
#include <stdio.h>
int main()
{
int num;
int sum = 0;
int count = 0;
int home[100]; //加入存100数以内
//求和,计数,以求平均数
do {
scanf("%d", &num);
if (num != -1) {
sum += num;
count++;
home[count] = num; //数组home中第count个位置存入此时的num
//* 为了观察数组存储数的方式
{
int i;
printf("count = %d, \thome: \t", count);
for (i = 1; i <= count; i++) {
printf("%d\t", home[i]);
}
printf("\n");
}
}
} while (num != -1);
//求平均数
double aver = 1.0 * sum / count;
printf("aver = %f\n", aver);
printf("平均数以上的数:\n");
//输出平均数以上的数
int i;
for (i = 1; i <= count; i++) {
if (home[i] > aver) {
printf("%d\n", home[i]);
}
}
return 0;
}
BUG:数组可能越界
解决方案1:数超过100个,就不再计入了
解决方案2:提前告诉计算机将要输入的数个数,直接定好home[数量]
第八章 数组
1.数组简介
1.数组的定义
一般格式:<类型> 变量名称[元素数量];
int grades[100];
double weight[20];
注意事项:
元素数量必须是整数
c99前编译器要求元素数量是字面常量,但之后的编译器也可以用变量,PTA系统建议字面常量
2.数组的特点
数组一种容器
数组一旦创建,不能改变大小
其中所有的元素具有相同的数据类型
数组中的元素再内存中是连续依次排列的
数组可以出现在赋值符的左边或右边;右边读取值(右值),左边往里写东西(左值)
a[2] = a[1] + 6
3.数组的单元
数组的每个单元就是数组类型的变量
4.数组的下标
使用数组时放在[]中的数字叫下标或索引,从0开始计数,范围是0 ~元素变量-1
编译器不会检查数组下标是否越界——编程习惯,自己注意别越界
越界可能会出现:segmentation fault报错
总结:数组的使用
其他:长度为0的数组
int a[0];
可以存在,但没必要
任何一个数都会越界,所以这个数组无用
课堂练习1:数量不确定
//stu
// 输入1 2 3 4 5 9 8 7 5 2 4 5 6 5 0 1 0 0 0 1 5 2 4 5 6 9 8 7 8 5 5 5 -1
#include <stdio.h>
int main()
{
int home[500];
// 挨个读数,存入数组
int num = 0;
int count = 0;
if (count <= 500) {
while (num != -1) {
scanf("%d", &num);
if (num != -1) {
home[count] = num;
count++;
}
}
}
//10次遍历,每次用一个数去比较
int j;
for (j = 0; j <= 9; j++) {
int i;
int cnt = 0;
for (i = 0; i <= (count - 1); i++) {
if (home[i] == j) {
cnt++;
}
}
printf("%d:%d个\n", j,cnt);
}
return 0;
}
tea:不用每个数都存,计数就行,所以需要十个变量
// tea-stu
// 输入1 2 3 4 5 9 8 7 5 2 4 5 6 5 0 1 0 0 0 1 5 2 4 5 6 9 8 7 8 5 5 5 -1
#include <stdio.h>
int main()
{
int home[10];
{
int i;
for (i = 0; i <= 9; i++) {
home[i] = 0;
}
}
int num = 0;
while (num != -1) {
scanf("%d", &num);
if (num != -1) {
home[num]++;
}
}
int i;
for (i = 0; i <= 9; i++) {
printf("%d: %d\n", i,home[i]);
}
return 0;
}
//tea 与我不一样的地方1
if (num >= 0 && num <= 9) {
home[num]++;
}
//tea 与我不一样的地方2
const int end = 10;
// tea
// 输入1 2 3 4 5 9 8 7 5 2 4 5 6 5 0 1 0 0 0 1 5 2 4 5 6 9 8 7 8 5 5 5 -1
#include <stdio.h>
int main()
{
const int begin = 0;
const int end = 10;
int home[end];
{
int i;
for (i = begin; i < end; i++) {
home[i] = 0;
}
}
int num = 0;
while (num != -1) {
scanf("%d", &num);
if (num >= begin && num < end) {
home[num]++;
}
}
int i;
for (i = begin; i < end; i++) {
printf("%d: %d\n", i,home[i]);
}
return 0;
}
2.数组运算
思考:在一组给定的数据中,如何找到某个数据是否存在?
1.集成初始化
int a[] = { 1,2,3,4,5,6 };
{
int i;
for (i = 0; i < 6; i++) {
printf("%d\t", a[i]);
}
}
↑ 6个数,索引0~5,a[0] = 1,a[5] = 6
int a[6] = {2};
↑ 6个数,索引0~5,a[0] = 2,其余a[……] = 0
int a[6] = { [0] = 2,[2]=2,3};//用的编译器不识别
课堂练习:数组集成初始化为0
int a[6] = {0};
2.数组大小——知道有多少数
int a[] = { 1,2,3,4,5,6 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0]));
printf("%d\n", sizeof(a[1]));
热知识:数组一个单元占据4个字节
课堂练习:统计数组内有多少数
sizeof(a)/sizeof(a[0]);
3.数组赋值
数组变量本身不能被赋值
不能整体赋值,只能遍历
int a[] = { 1,2,3,4,5,6 };
// int b[] = a;// 错误!!!!!
for (i=0;i<length;i++){
b[i] = a[i];
}
4.数组遍历
通常都是使用for循环,让循环变量从0开始到<length,这样循环体内最大的i正好是数组最大的有效下标
常见错误:①循环结束条件是<length,而不是<=;②循环结束,继续用i的值作数组元素下标❌
int i;
for (i = 0; i < 7; i++) {
}
printf("i = %d", i); // 最后i=7
int j;
for (j = 0; j <= 6; j++) {
}
printf("j = %d", j);// 最后j=7
5.数组作函数参数
#include <stdio.h>
/*
* 函数search用于找出数key在数组a中的位置
* @param key 要找的数
* @param a 要遍历的数组
* @param length 要遍历的数组长度
* @return 如果找到,返回其在a中的位置,如果找不到,返回值-1
*/
int Search(int key, int a[], int length);
int main()
{
int a[] = { 1,2,3,4,5,6 };
int x;
printf("请输入一个数字:");
scanf("%d", &x);
int len = sizeof(a) / sizeof(a[0]);
int loc = Search(x,a,len);//注意数组,直接用a,而不是a[]
if (loc != -1) {
printf("%d在数组a中%d位置\n",x,loc);
}
else {
printf("%d不在数组a中\n",x);
}
return 0;
}
int Search(int key, int a[], int length)
{
int ret = -1;
int i;
for (i = 0; i < length; i++) {
if (a[i] == key) {
ret = i;
break;//自己写没想到这步
}
}
return ret;
}
注意事项:
数组作为函数参数,必须再用另一个参数传入数组大小
数组作为函数参数,不能在声明中给出数组大小,只能a[],不能a[number]
数组作为函数参数,不能再定义中用sizeof来计算数组的元素个数(别问为什么,就这样吧
课堂练习2:素数
#include <stdio.h>
int isPrime(int x)
{
int ret = 1;
int i;
if (x == 1) {
ret = 0;
}
for (i = 2; i < x; i++) {
if (x % i == 0) {
ret = 0;
break;
}
}
return ret;
}
int main()
{
int x = 11;
if (isPrime(x)) {
printf("Yes!");
}
return 0;
}
简化isPrime函数:减少循环次数,提高效率
简化思路:
方案一:先判断是不是偶数,在奇数范围内寻找
#include <stdio.h>
int isPrime(int x)
{
int ret = 1;
int i;
if (x == 1|| (x%2==0 && x!=2)) {
ret = 0;
}
for (i = 2; i < x; i++) {
if (x % i == 0) {
ret = 0;
break;
}
}
return ret;
}
方案二:在一基础上,缩小结束条件,缩到为根号
#include <math.h>
int isPrime(int x)
{
int ret = 1;
int i;
if (x == 1|| (x%2==0 && x!=2)) {
ret = 0;
}
for (i = 2; i < sqrt(x); i++) {//基于数学原理
if (x % i == 0) {
ret = 0;
break;
}
}
return ret;
}
方案三:和素数表对照——先得到素数对照表
没明白没明白没明白没明白(已解决)
isPrime函数怎么判断素数的没明白,为什么关键条件是 x % a[] == 0,就不是素数——不能被1和本身以外的数整除,数= 素数 * 非素数 = 素数 * 素数 *素数,所以可以素数锁定范围
为啥这样次数就少了?
每个数要判断是不是素数
小于它的所有数去除→小于它的所有素数去除
巧妙的地方
构造素数数组的方法,从2开始一个一个去除,前面的数没有因子(不精准的表述,方便个人理解
#include <stdio.h>
/*
* isPrime函数用来和素数表对照,判断一个数是不是素数
* @param x,输入的数
* @param home,素数表(数组)
* @param len,素数表长度
*/
#include <stdio.h>
int isPrime(int x, int home[], int len)
{
int ret = 1;
int i;
for (i = 0; i < len; i++) {
if (x % home[i] == 0) { //看能不能被已有素数整除,不能则为素数
ret = 0;
break;
}
}
return ret;
}
//总体思路是一边构造表,一边判断是不是
int main()
{
const int len = 5;
int primeHome[len] = { 2 };//
int count = 1;//角标
int i;
printf("\t\t");
int k;
for (k = 0; k < len; k++) {
printf("%d\t", k);
}
printf("\n");
for (i = 3; count < len; i++) {//从i=3开始判断是不是素数
if (isPrime(i, primeHome, count)) {
primeHome[count++] = i; //是素数,放到素数数组里
}
{
printf("i=%d\tcount=%d\t", i, count);
int j;
for (j = 0; j < len; j++) {
printf("%d\t", primeHome[j]);
}
}
printf("\n");
}
printf("素数:\n");
int j;
for (j = 0; j < len; j++) {
printf("%d", primeHome[j]);
if ((j + 1) % 5 != 0) {
printf("\t");
}
else {
printf("\n");
}
}
return 0;
}
方案四:删去倍数
//stu1
#include <stdio.h>
int isPrime(int x);
int main()
{
// 1.创建数组
const int LEN = 10;
int prime[LEN];
int i;
// 2.漂亮的题头
for (i = 0; i < LEN; i++) {
printf("%d\t", i);
}
printf("\n");
// 3.假设都为素数,为1
for (i = 0; i < LEN; i++) {
prime[i] = 1;
}
// 4.已知0不是先排除
prime[0] = 0;
//printf("\n");
// 5.对素数x倍数位置的元素赋0
int x;
for (x = 2; x < LEN; x++) {
if (isPrime(x)) {
int j;
for (j = 2; x * j < LEN; j++) {
prime[x * j] = 0;
}
}
}
// 6.查看数组
for (i = 0; i < LEN; i++) {
printf("%d\t", prime[i]);
}
printf("\n");
return 0;
}
int isPrime(int x)
{
int i;
int ret = 1;
for (i = 2; i < x; i++) {
if (x % i == 0) {
ret = 0;
break;
}
}
return ret;
}
//stu2
#include <stdio.h>
int isPrime(int x);
int main()
{
// 1.创建数组
const int LEN = 10;
int prime[LEN];
int i;
// 2.假设都为素数,为1
for (i = 0; i < LEN; i++) {
prime[i] = 1;
}
// 3.对素数x倍数位置的元素赋0
int x;
for (x = 2; x < LEN; x++) {
if (isPrime(x)) {
for (i = 2; x * i < LEN; i++) {
prime[x * i] = 0;
}
}
}
// 4.查看素数
for (i = 2; i < LEN; i++) {
if (prime[i]) {
printf("%d ", i);
}
}
printf("\n");
return 0;
}
int isPrime(int x)
{
int i;
int ret = 1;
for (i = 2; i < x; i++) {
if (x % i == 0) {
ret = 0;
break;
}
}
return ret;
}
方案五:在四基础上,循环构建素数表
//tea
#include <stdio.h>
int main()
{
// 1.创建数组
const int LEN = 10;
int prime[LEN];
int i;
// 2.假设都为素数,为1
for (i = 0; i < LEN; i++) {
prime[i] = 1;
}
// 3.对素数x倍数位置的元素赋0
int x;
for (x = 2; x < LEN; x++) {
if (Prim[x]) {//注意这里!!!!!!
for (i = 2; x * i < LEN; i++) {
prime[x * i] = 0;
}
}
}
// 4.查看素数
for (i = 2; i < LEN; i++) {
if (prime[i]) {
printf("%d ", i);
}
}
printf("\n");
return 0;
}
感想:循环构造素数表的思想,没想到,不是很理解,双线程工作
其他:
primeHome[count++] = i;
primeHome[count++] = i;
//即
primeHome[count] = i;
count++;
//再次理解a++值是a,++a值是a+1,但经历过这个语句后,a值为a+1
怎么查一个函数
了解函数,unix系统man ,win直接百度
3.二维数组
1.一般格式
int a[3][5];
至少给出列
2.二维数组遍历
int i, j;
int a[3][5];
for (i = 0; i < 3; i++) {
for (j = 0; j < 5; j++) {
a[i][j] = i * j;
printf("%d ", a[i][j]);
}
printf("\n");
}
a[i][j] & a[i,j]
a[i][j]表示第i行第j 列的变量
a[i,j]表示a[j],表示第j个变量
课堂练习3:3×3棋盘格
1.读入矩阵
注意:a[i][j]是一个变量,可以直接赋值,格式化输入、输出等
const int size = 3;//这里没想到用一个const
int a[size][size];
int i, j;
// 0.读入矩阵
// 输入1 0 1 0 1 0 1 1 1
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
scanf("%d", &a[i][j]);
}
}
// 查看数组
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
printf("%d", a[i][j]);
}
printf("\n");
}
// 错误程序,试了一下,这样不可以!!!!
for (i = 0,j = 0; i < 3 && j < 3; i++,j++) {
printf("%d", a[i][j]);
printf("\n");
}
2.检查行/列
// 1.检查行
// 利用ret 成行时ret=3
for (i = 0; i < 3; i++) {
int ret = 0;
for (j = 0; j < 3; j++) {
if (a[i][j]) {
ret++;
}
}
if (ret == 3) {
printf("Bingo!\n");
}
}
// 2.检查列
for (j = 0; j < 3; j++) {
int ret = 0;
for (i = 0; i < 3; i++) {
if (a[i][j]) {
ret++;
}
}
if (ret == 3) {
printf("Bingo!\n");
}
}
3.检查对角线
// 3.检查左上-右下对角线
// 11 22 33都为1
{
int ret = 0;
for (i = 0; i < 3; i++) {
if (a[i][i]) {
ret++;
}
}
if (ret == 3) {
printf("Bingo!\n");
}
}
// 4.检查右上-左下对角线
// 13 22 31
{
int ret = 0;
for (i = 0; i < 3; i++) {
if (a[i][4-i]) {
ret++;
}
}
if (ret == 3) {
printf("Bingo!\n");
}
}